diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..7e50d89 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,10 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + labels: + - "dependencies" + commit-message: + prefix: "ci" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..a18c111 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,109 @@ +name: Release + +on: + pull_request: + types: [closed] + branches: [main] + +jobs: + release: + # Only run if PR was merged (not just closed) and has a release label + if: | + github.event.pull_request.merged == true && + (contains(github.event.pull_request.labels.*.name, 'release:major') || + contains(github.event.pull_request.labels.*.name, 'release:minor') || + contains(github.event.pull_request.labels.*.name, 'release:patch')) + + runs-on: ubuntu-latest + permissions: + contents: write + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 # Fetch all history for tags + + - name: Get latest tag + id: get_tag + run: | + # Get the latest semver tag (handles v prefix) + LATEST_TAG=$(git tag --sort=-v:refname | grep -E '^v?[0-9]+\.[0-9]+\.[0-9]+$' | head -1) + + if [ -z "$LATEST_TAG" ]; then + echo "No existing tags found, starting from v0.0.0" + LATEST_TAG="v0.0.0" + fi + + echo "latest_tag=$LATEST_TAG" >> $GITHUB_OUTPUT + echo "Latest tag: $LATEST_TAG" + + - name: Determine version bump type + id: bump_type + run: | + if ${{ contains(github.event.pull_request.labels.*.name, 'release:major') }}; then + echo "type=major" >> $GITHUB_OUTPUT + elif ${{ contains(github.event.pull_request.labels.*.name, 'release:minor') }}; then + echo "type=minor" >> $GITHUB_OUTPUT + elif ${{ contains(github.event.pull_request.labels.*.name, 'release:patch') }}; then + echo "type=patch" >> $GITHUB_OUTPUT + fi + + - name: Calculate new version + id: new_version + run: | + LATEST_TAG="${{ steps.get_tag.outputs.latest_tag }}" + BUMP_TYPE="${{ steps.bump_type.outputs.type }}" + + # Remove 'v' prefix if present + VERSION=${LATEST_TAG#v} + + # Split version into parts + IFS='.' read -r MAJOR MINOR PATCH <<< "$VERSION" + + # Bump version based on type + case $BUMP_TYPE in + major) + MAJOR=$((MAJOR + 1)) + MINOR=0 + PATCH=0 + ;; + minor) + MINOR=$((MINOR + 1)) + PATCH=0 + ;; + patch) + PATCH=$((PATCH + 1)) + ;; + esac + + NEW_VERSION="v${MAJOR}.${MINOR}.${PATCH}" + echo "new_version=$NEW_VERSION" >> $GITHUB_OUTPUT + echo "New version: $NEW_VERSION (bump type: $BUMP_TYPE)" + + - name: Create and push tag + run: | + NEW_VERSION="${{ steps.new_version.outputs.new_version }}" + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git tag -a "$NEW_VERSION" -m "Release $NEW_VERSION" + git push origin "$NEW_VERSION" + + - name: Create GitHub Release + uses: actions/github-script@v7 + with: + script: | + const newVersion = '${{ steps.new_version.outputs.new_version }}'; + const previousTag = '${{ steps.get_tag.outputs.latest_tag }}'; + + await github.rest.repos.createRelease({ + owner: context.repo.owner, + repo: context.repo.repo, + tag_name: newVersion, + name: `Release ${newVersion}`, + generate_release_notes: true, + draft: false, + prerelease: false + }); + + console.log(`Created release ${newVersion}`); diff --git a/README.md b/README.md index 69b5696..5b09e7c 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@

TM1 versions - v5.0.0 + v5.0.0

diff --git a/bedrock_processes_json/}bedrock.chore.execution.check.json b/bedrock_processes_json/}bedrock.chore.execution.check.json index 4f3838d..fc6310f 100644 --- a/bedrock_processes_json/}bedrock.chore.execution.check.json +++ b/bedrock_processes_json/}bedrock.chore.execution.check.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.chore.execution.check", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.chore.execution.check', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pMonthDays', '', \r\n 'pWeekDays', '',\r\n 'pDelim', '&',\r\n 'pStartTime', 0, 'pEndTime', 24,\r\n 'pScheduleTimezone','en-AU',\r\n 'pServerTimezone','etc/UTC'\r\n );\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~## \r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This TI was created to overcome the limited scheduling options in chores. In order to use this TI it has to be the 1st TI in the chore.\r\n# As an example, if you need to run a chore every Monday & Wednesday you would schedule it to run EVERY day but set the pWeekdays parameter to Mon & Wed.\r\n# The chore would then kick off every day but this TI will perform a ProcessExitByChoreQuit function on all days NOT mentioned in pWeekdays.\r\n\r\n# Alternative setup: instead of adding this TI as the 1st TI in the chore, you could also use ExecuteProcess to call it, \r\n# from the top of the Prolog of your first TI process. This is definitely easier than hardcoding process call parameters in the chore dialog.\r\n\r\n# Timezones:\r\n# pScheduleTimezone parameter allow specifying the timezone to perform checks in if server timezone is different to schedule one. E.g. PA server is running in UTC and time or days of week are to be checked in AEST. Full list of timezones https://en.wikipedia.org/wiki/List_of_tz_database_time_zones\r\n# pServerTimezone allows to cater for situations when PA server is running in local time in yet another timezone, e.g. you want to check chore schedule in timezone Europe/Munich for server running in Asia/Singapore\r\n\r\n# Use case: For productive systems.\r\n# 1. A chore should run every 30 minutes between 8am & 8pm on weekdays. Schedule chore for every 30 minutes and include this process 1st in chore with parameters pWeekDays=MON&TUE&WED&THU&FRI pStartTime=8 pEndTime=20.\r\n# 2. A chore should run only on 1st calendar day of each month. Schedule chore for daily execution and include this process 1st in chore with parameters pMonthDays=1.\r\n\r\n# Note:\r\n# * This process will quit a chore if any time-bound, weekday-bound or date-bound conditions which define when the chore should NOT run are met.\r\n# * Only the parameter(s) needed should be specified.\r\n# * Only scheduled executions will be quit outside the parameters. The checks are bypassed if a chore is manually executed by a user. This is done by checking the TM1User function.\r\n# * Time conditions are checked using these parameters in the following order of priority.\r\n# 1. pMonthDays : Days in month when chore is allowed to run. Enter delimited list of days e.g. 1&2&30&31 (blank = no restriction on allowed days of month).\r\n# 2. pWeekDays : Days in week when chore is allowed to run Enter delimited list of weekdays e.g. MON&FRI (blank = no restriction on allowed weekdays).\r\n# 3. pStartTime & pEndTime : Time of day when chore is allowed to run e.g. pStartTime=7, pEndTime=22 execution will be allowed between 7AM & 10PM ( blank = no time-bound restrictions).\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncStartTime = NumberToString( pStartTime );\r\ncEndTime = NumberToString( pEndTime );\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent= 'User:%cUserName% Process:%cThisProcName% Message: %sMsg%';\r\ncLogInfo = 'User:%cUserName% Process:%cThisProcName% run to check if chore should run with parameters pMonthDays:%pMonthDays%, pWeekDays:%pWeekDays%, pDelim:%pDelim%, pStartTime:%cStartTime%, pEndTime:%cEndTime%, pScheduleTimezone: %pScheduleTimezone% pServerTimezone: %pServerTimezone%.' ; \r\nnErrors = 0;\r\nsMsg = '';\r\n\r\n## LogOutput parameters\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nEndIf;\r\n\r\n### Check params\r\nIf( pDelim @= '' );\r\n pDelim = '&';\r\nElse;\r\n pDelim = SubSt( pDelim, 1, 1 );\r\nEndIf;\r\n\r\nIf( pMonthDays @= 'ALL' );\r\n pMonthDays = '';\r\nEndIf;\r\nIf( pMonthDays @<> '' );\r\n If( SubSt( pMonthDays, Long( pMonthDays ), 1 ) @<> pDelim );\r\n pMonthDays = pMonthDays | pDelim;\r\n EndIf;\r\nEndIf;\r\n\r\nIf( pWeekDays @= 'ALL' );\r\n pWeekDays = '';\r\nEndIf;\r\nIf( pWeekDays @<> '' );\r\n pWeekDays = Upper( pWeekDays );\r\n If( SubSt( pWeekDays, Long( pWeekDays ), 1 ) @<> pDelim );\r\n pWeekDays = pWeekDays | pDelim;\r\n EndIf;\r\nEndIf;\r\n\r\nIf( pStartTime <= 0 % pStartTime > 24 );\r\n pStartTime = 0;\r\nElse;\r\n pStartTime = Round(pStartTime);\r\nEndIf;\r\nsStartTime = NumberToString( pStartTime );\r\n\r\nIf( pEndTime <= 0 % pEndTime > 24 );\r\n pEndTime = 24;\r\nElse;\r\n pEndTime = Round(pEndTime);\r\nEndIf;\r\n\r\nIf( pEndTime < pStartTime );\r\n pEndTime = pStartTime;\r\nEndIf;\r\nsEndTime = NumberToString( pEndTime );\r\n\r\n### Initialize quit Boolean\r\nbQuit = 0;\r\n\r\n### Check the user\r\nIf( DIMIX( '}Clients', cUserName ) > 0 );\r\n If( pLogOutput >= 1 );\r\n sMsg = 'This chore will NOT quit since executed by a user.';\r\n LogOutput( 'INFO', Expand( cMsgErrorContent ) );\r\n EndIf;\r\nElse;\r\n if (pScheduleTimezone@<>'');\r\n #initate the date format for conversion\r\n pServerTimezone = if (pServerTimezone@='','etc/UTC',pServerTimezone);\r\n # need to convert to UTC first and then restate in required timezones\r\n nUTCDateFormatter = NewDateFormatter('', 'etc/UTC', 'serial', 'full', 'datetime');\r\n nScheduleDateFormatter = NewDateFormatter('', pScheduleTimezone, 'serial', 'full', 'datetime');\r\n nServerDateFormatter = NewDateFormatter('', pServerTimezone, 'serial', 'full', 'datetime');\r\n sDateFormat = 'yyyy-MM-dd HH:mm:ss';\r\n sUTCTimeStamp = FormatDate(Now, sDateFormat, nUTCDateFormatter);\r\n nServerParsedDate = ParseDate( sUTCTimeStamp, sDateFormat, nServerDateFormatter );\r\n endif;\r\n ### Check the day of the month\r\n If( pMonthDays @<> '' );\r\n if (pScheduleTimezone @= '');\r\n sDayInMonth = TimSt(Now, '\\d');\r\n else;\r\n sDayInMonth = FormatDate(nServerParsedDate, 'd', nScheduleDateFormatter);\r\n endif;\r\n If( Scan( sDayInMonth | pDelim, pMonthDays ) = 0 & Scan( sDayInMonth |' '| pDelim, pMonthDays ) = 0 );\r\n # could not find the day in the list of acceptable days\r\n bQuit = 1;\r\n sMsg = Expand('Bedrock debug %cThisProcName%: chore will quit. Could not find today %sDayInMonth% in list of acceptable days %pMonthDays%');\r\n IF( pLogOutput = 1 ); LogOutput( 'INFO', sMsg ); EndIf;\r\n Else;\r\n sMsg = Expand('Bedrock debug %cThisProcName%: today %sDayInMonth% found in list of acceptable days %pMonthDays%');\r\n IF( pLogOutput = 1 ); LogOutput( 'INFO', sMsg ); EndIf;\r\n EndIF;\r\n EndIf;\r\n\r\n ### Check the day of the week\r\n If( pWeekDays @<> '' );\r\n if (pScheduleTimezone @= '');\r\n # support for UseExcelSerialDate=T in TM1s.cfg\r\n nDayIndex = Mod( DayNo( Today ) + Dayno( '1960-01-01' ) / 21916 - 2, 7 );\r\n sWeekday = '';\r\n If( nDayIndex = 0 );\r\n sWeekday = 'SUN';\r\n ElseIf( nDayIndex = 1 );\r\n sWeekday = 'MON';\r\n ElseIf( nDayIndex = 2 );\r\n sWeekday = 'TUE';\r\n ElseIf( nDayIndex = 3 );\r\n sWeekday = 'WED';\r\n ElseIf( nDayIndex = 4 );\r\n sWeekday = 'THU';\r\n ElseIf( nDayIndex = 5 );\r\n sWeekday = 'FRI';\r\n ElseIf( nDayIndex = 6 );\r\n sWeekday = 'SAT';\r\n EndIf;\r\n else;\r\n sWeekday = Upper (FormatDate(nServerParsedDate, 'eee', nScheduleDateFormatter));\r\n endif;\r\n If( Scan( sWeekday | pDelim, pWeekDays ) = 0 & Scan( sWeekday |' '| pDelim, pWeekDays ) = 0 );\r\n # could not find the day in the list of acceptable days\r\n bQuit = 1;\r\n pWeekDays = Delet( pWeekDays, Long( pWeekDays ), 1 );\r\n sMsg = Expand('Bedrock debug %cThisProcName%: chore will quit. Could not find today %sWeekday% in list of acceptable days %pWeekDays%');\r\n IF( pLogOutput = 1 ); LogOutput( 'INFO', sMsg ); EndIf;\r\n Else;\r\n pWeekDays = Delet( pWeekDays, Long( pWeekDays ), 1 );\r\n sMsg = Expand('Bedrock debug %cThisProcName%: today %sWeekday% found in list of acceptable days %pWeekDays%');\r\n IF( pLogOutput = 1 ); LogOutput( 'INFO', sMsg ); EndIf;\r\n EndIF;\r\n EndIf;\r\n \r\n ### Check the time of day\r\n if (pScheduleTimezone @= '');\r\n sMinute = TimSt(Now, '\\h:\\i'); \r\n else;\r\n sMinute = FormatDate(nServerParsedDate, 'HH:mm', nScheduleDateFormatter);\r\n endif;\r\n vTimeNow = StringToNumber(SubSt(sMinute, 1, 2));\r\n If( pStartTime = 0 & pEndTime = 24 );\r\n # no time exclusion parameters are set\r\n ElseIf( vTimeNow < pStartTime % vTimeNow >= pEndTime );\r\n # we are in the exclusion zone do not execute chore\r\n bQuit = 1;\r\n sMsg = Expand('Bedrock debug %cThisProcName%: chore will quit. current time %sMinute% is outside the defined execution time from %sStartTime%:00 to %sEndTime%:00');\r\n IF( pLogOutput = 1 ); LogOutput( 'INFO', sMsg ); EndIf;\r\n Else;\r\n # we are not in the exclusion zone, proceed as normal \r\n sMsg = Expand('Bedrock debug %cThisProcName%: current time %sMinute% is within the defined execution time from %sStartTime%:00 to %sEndTime%:00');\r\n IF( pLogOutput = 1 ); LogOutput( 'INFO', sMsg ); EndIf;\r\n EndIF;\r\n\r\nEndIf;\r\n\r\n### Quit chore if quit conditions met\r\nIf( bQuit = 1 );\r\n sMsg = Expand('Bedrock debug %cThisProcName%: terminated the chore for the reasons stated above.');\r\n If( pLogOutput = 1 ); LogOutput( 'INFO' , Expand( cMsgErrorContent ) ); EndIf;\r\n nProcessReturnCode = ProcessExitByChoreQuit();\r\n sProcessReturnCode = 'ProcessExitByChoreQuit';\r\n ChoreQuit;\r\nElse;\r\n ### Return Code\r\n sProcessAction = Expand('Bedrock debug %cThisProcName%: validated the chore to run as normal.');\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogOutput = 1 ); LogOutput('INFO', Expand( sProcessAction ) ); EndIf;\r\nEndIf;\r\n\r\n### End Prolog ###", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.chore.execution.check', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pMonthDays', '', \r\n 'pWeekDays', '',\r\n 'pDelim', '&',\r\n 'pStartTime', 0, 'pEndTime', 24,\r\n 'pScheduleTimezone','en-AU',\r\n 'pServerTimezone','etc/UTC'\r\n );\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~## \r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This TI was created to overcome the limited scheduling options in chores. In order to use this TI it has to be the 1st TI in the chore.\r\n# As an example, if you need to run a chore every Monday & Wednesday you would schedule it to run EVERY day but set the pWeekdays parameter to Mon & Wed.\r\n# The chore would then kick off every day but this TI will perform a ProcessExitByChoreQuit function on all days NOT mentioned in pWeekdays.\r\n\r\n# Alternative setup: instead of adding this TI as the 1st TI in the chore, you could also use ExecuteProcess to call it, \r\n# from the top of the Prolog of your first TI process. This is definitely easier than hardcoding process call parameters in the chore dialog.\r\n\r\n# Timezones:\r\n# pScheduleTimezone parameter allow specifying the timezone to perform checks in if server timezone is different to schedule one. E.g. PA server is running in UTC and time or days of week are to be checked in AEST. Full list of timezones https://en.wikipedia.org/wiki/List_of_tz_database_time_zones\r\n# pServerTimezone allows to cater for situations when PA server is running in local time in yet another timezone, e.g. you want to check chore schedule in timezone Europe/Munich for server running in Asia/Singapore\r\n\r\n# Use case: For productive systems.\r\n# 1. A chore should run every 30 minutes between 8am & 8pm on weekdays. Schedule chore for every 30 minutes and include this process 1st in chore with parameters pWeekDays=MON&TUE&WED&THU&FRI pStartTime=8 pEndTime=20.\r\n# 2. A chore should run only on 1st calendar day of each month. Schedule chore for daily execution and include this process 1st in chore with parameters pMonthDays=1.\r\n\r\n# Note:\r\n# * This process will quit a chore if any time-bound, weekday-bound or date-bound conditions which define when the chore should NOT run are met.\r\n# * Only the parameter(s) needed should be specified.\r\n# * Only scheduled executions will be quit outside the parameters. The checks are bypassed if a chore is manually executed by a user. This is done by checking the TM1User function.\r\n# * Time conditions are checked using these parameters in the following order of priority.\r\n# 1. pMonthDays : Days in month when chore is allowed to run. Enter delimited list of days e.g. 1&2&30&31 (blank = no restriction on allowed days of month).\r\n# 2. pWeekDays : Days in week when chore is allowed to run Enter delimited list of weekdays e.g. MON&FRI (blank = no restriction on allowed weekdays).\r\n# 3. pStartTime & pEndTime : Time of day when chore is allowed to run e.g. pStartTime=7, pEndTime=22 execution will be allowed between 7AM & 10PM ( blank = no time-bound restrictions).\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncStartTime = NumberToString( pStartTime );\r\ncEndTime = NumberToString( pEndTime );\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent= 'User:%cUserName% Process:%cThisProcName% Message: %sMsg%';\r\ncLogInfo = 'User:%cUserName% Process:%cThisProcName% run to check if chore should run with parameters pMonthDays:%pMonthDays%, pWeekDays:%pWeekDays%, pDelim:%pDelim%, pStartTime:%cStartTime%, pEndTime:%cEndTime%, pScheduleTimezone: %pScheduleTimezone% pServerTimezone: %pServerTimezone%.' ; \r\nnErrors = 0;\r\nsMsg = '';\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pDelim\": \"&\",\r\n \"pMonthDays\": \"\",\r\n \"pScheduleTimezone\": \"\",\r\n \"pServerTimezone\": \"\",\r\n \"pWeekDays\": \"\",\r\n \"pEndTime\": 24,\r\n \"pLogOutput\": 0,\r\n \"pStartTime\": 0,\r\n \"pStrictErrorHandling\": 0\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pDelim\": '|StringToJson ( pDelim )|',\r\n \"pMonthDays\": '|StringToJson ( pMonthDays )|',\r\n \"pScheduleTimezone\": '|StringToJson ( pScheduleTimezone )|',\r\n \"pServerTimezone\": '|StringToJson ( pServerTimezone )|',\r\n \"pWeekDays\": '|StringToJson ( pWeekDays )|',\r\n \"pEndTime\": '|NumberToString( pEndTime )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pStartTime\": '|NumberToString( pStartTime )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npDelim = JsonToString( JsonGet( pJson, 'pDelim' ) );\r\npMonthDays = JsonToString( JsonGet( pJson, 'pMonthDays' ) );\r\npScheduleTimezone = JsonToString( JsonGet( pJson, 'pScheduleTimezone' ) );\r\npServerTimezone = JsonToString( JsonGet( pJson, 'pServerTimezone' ) );\r\npWeekDays = JsonToString( JsonGet( pJson, 'pWeekDays' ) );\r\n# Numeric Parameters\r\npEndTime = StringToNumber( JsonToString( JsonGet( pJson, 'pEndTime' ) ) );\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npStartTime = StringToNumber( JsonToString( JsonGet( pJson, 'pStartTime' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n## LogOutput parameters\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nEndIf;\r\n\r\n### Check params\r\nIf( pDelim @= '' );\r\n pDelim = '&';\r\nElse;\r\n pDelim = SubSt( pDelim, 1, 1 );\r\nEndIf;\r\n\r\nIf( pMonthDays @= 'ALL' );\r\n pMonthDays = '';\r\nEndIf;\r\nIf( pMonthDays @<> '' );\r\n If( SubSt( pMonthDays, Long( pMonthDays ), 1 ) @<> pDelim );\r\n pMonthDays = pMonthDays | pDelim;\r\n EndIf;\r\nEndIf;\r\n\r\nIf( pWeekDays @= 'ALL' );\r\n pWeekDays = '';\r\nEndIf;\r\nIf( pWeekDays @<> '' );\r\n pWeekDays = Upper( pWeekDays );\r\n If( SubSt( pWeekDays, Long( pWeekDays ), 1 ) @<> pDelim );\r\n pWeekDays = pWeekDays | pDelim;\r\n EndIf;\r\nEndIf;\r\n\r\nIf( pStartTime <= 0 % pStartTime > 24 );\r\n pStartTime = 0;\r\nElse;\r\n pStartTime = Round(pStartTime);\r\nEndIf;\r\nsStartTime = NumberToString( pStartTime );\r\n\r\nIf( pEndTime <= 0 % pEndTime > 24 );\r\n pEndTime = 24;\r\nElse;\r\n pEndTime = Round(pEndTime);\r\nEndIf;\r\n\r\nIf( pEndTime < pStartTime );\r\n pEndTime = pStartTime;\r\nEndIf;\r\nsEndTime = NumberToString( pEndTime );\r\n\r\n### Initialize quit Boolean\r\nbQuit = 0;\r\n\r\n### Check the user\r\nIf( DIMIX( '}Clients', cUserName ) > 0 );\r\n If( pLogOutput >= 1 );\r\n sMsg = 'This chore will NOT quit since executed by a user.';\r\n LogOutput( 'INFO', Expand( cMsgErrorContent ) );\r\n EndIf;\r\nElse;\r\n if (pScheduleTimezone@<>'');\r\n #initate the date format for conversion\r\n pServerTimezone = if (pServerTimezone@='','etc/UTC',pServerTimezone);\r\n # need to convert to UTC first and then restate in required timezones\r\n nUTCDateFormatter = NewDateFormatter('', 'etc/UTC', 'serial', 'full', 'datetime');\r\n nScheduleDateFormatter = NewDateFormatter('', pScheduleTimezone, 'serial', 'full', 'datetime');\r\n nServerDateFormatter = NewDateFormatter('', pServerTimezone, 'serial', 'full', 'datetime');\r\n sDateFormat = 'yyyy-MM-dd HH:mm:ss';\r\n sUTCTimeStamp = FormatDate(Now, sDateFormat, nUTCDateFormatter);\r\n nServerParsedDate = ParseDate( sUTCTimeStamp, sDateFormat, nServerDateFormatter );\r\n endif;\r\n ### Check the day of the month\r\n If( pMonthDays @<> '' );\r\n if (pScheduleTimezone @= '');\r\n sDayInMonth = TimSt(Now, '\\d');\r\n else;\r\n sDayInMonth = FormatDate(nServerParsedDate, 'd', nScheduleDateFormatter);\r\n endif;\r\n If( Scan( sDayInMonth | pDelim, pMonthDays ) = 0 & Scan( sDayInMonth |' '| pDelim, pMonthDays ) = 0 );\r\n # could not find the day in the list of acceptable days\r\n bQuit = 1;\r\n sMsg = Expand('Bedrock debug %cThisProcName%: chore will quit. Could not find today %sDayInMonth% in list of acceptable days %pMonthDays%');\r\n IF( pLogOutput = 1 ); LogOutput( 'INFO', sMsg ); EndIf;\r\n Else;\r\n sMsg = Expand('Bedrock debug %cThisProcName%: today %sDayInMonth% found in list of acceptable days %pMonthDays%');\r\n IF( pLogOutput = 1 ); LogOutput( 'INFO', sMsg ); EndIf;\r\n EndIF;\r\n EndIf;\r\n\r\n ### Check the day of the week\r\n If( pWeekDays @<> '' );\r\n if (pScheduleTimezone @= '');\r\n # support for UseExcelSerialDate=T in TM1s.cfg\r\n nDayIndex = Mod( DayNo( Today ) + Dayno( '1960-01-01' ) / 21916 - 2, 7 );\r\n sWeekday = '';\r\n If( nDayIndex = 0 );\r\n sWeekday = 'SUN';\r\n ElseIf( nDayIndex = 1 );\r\n sWeekday = 'MON';\r\n ElseIf( nDayIndex = 2 );\r\n sWeekday = 'TUE';\r\n ElseIf( nDayIndex = 3 );\r\n sWeekday = 'WED';\r\n ElseIf( nDayIndex = 4 );\r\n sWeekday = 'THU';\r\n ElseIf( nDayIndex = 5 );\r\n sWeekday = 'FRI';\r\n ElseIf( nDayIndex = 6 );\r\n sWeekday = 'SAT';\r\n EndIf;\r\n else;\r\n sWeekday = Upper (FormatDate(nServerParsedDate, 'eee', nScheduleDateFormatter));\r\n endif;\r\n If( Scan( sWeekday | pDelim, pWeekDays ) = 0 & Scan( sWeekday |' '| pDelim, pWeekDays ) = 0 );\r\n # could not find the day in the list of acceptable days\r\n bQuit = 1;\r\n pWeekDays = Delet( pWeekDays, Long( pWeekDays ), 1 );\r\n sMsg = Expand('Bedrock debug %cThisProcName%: chore will quit. Could not find today %sWeekday% in list of acceptable days %pWeekDays%');\r\n IF( pLogOutput = 1 ); LogOutput( 'INFO', sMsg ); EndIf;\r\n Else;\r\n pWeekDays = Delet( pWeekDays, Long( pWeekDays ), 1 );\r\n sMsg = Expand('Bedrock debug %cThisProcName%: today %sWeekday% found in list of acceptable days %pWeekDays%');\r\n IF( pLogOutput = 1 ); LogOutput( 'INFO', sMsg ); EndIf;\r\n EndIF;\r\n EndIf;\r\n \r\n ### Check the time of day\r\n if (pScheduleTimezone @= '');\r\n sMinute = TimSt(Now, '\\h:\\i'); \r\n else;\r\n sMinute = FormatDate(nServerParsedDate, 'HH:mm', nScheduleDateFormatter);\r\n endif;\r\n vTimeNow = StringToNumber(SubSt(sMinute, 1, 2));\r\n If( pStartTime = 0 & pEndTime = 24 );\r\n # no time exclusion parameters are set\r\n ElseIf( vTimeNow < pStartTime % vTimeNow >= pEndTime );\r\n # we are in the exclusion zone do not execute chore\r\n bQuit = 1;\r\n sMsg = Expand('Bedrock debug %cThisProcName%: chore will quit. current time %sMinute% is outside the defined execution time from %sStartTime%:00 to %sEndTime%:00');\r\n IF( pLogOutput = 1 ); LogOutput( 'INFO', sMsg ); EndIf;\r\n Else;\r\n # we are not in the exclusion zone, proceed as normal \r\n sMsg = Expand('Bedrock debug %cThisProcName%: current time %sMinute% is within the defined execution time from %sStartTime%:00 to %sEndTime%:00');\r\n IF( pLogOutput = 1 ); LogOutput( 'INFO', sMsg ); EndIf;\r\n EndIF;\r\n\r\nEndIf;\r\n\r\n### Quit chore if quit conditions met\r\nIf( bQuit = 1 );\r\n sMsg = Expand('Bedrock debug %cThisProcName%: terminated the chore for the reasons stated above.');\r\n If( pLogOutput = 1 ); LogOutput( 'INFO' , Expand( cMsgErrorContent ) ); EndIf;\r\n nProcessReturnCode = ProcessExitByChoreQuit();\r\n sProcessReturnCode = 'ProcessExitByChoreQuit';\r\n ChoreQuit;\r\nElse;\r\n ### Return Code\r\n sProcessAction = Expand('Bedrock debug %cThisProcName%: validated the chore to run as normal.');\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogOutput = 1 ); LogOutput('INFO', Expand( sProcessAction ) ); EndIf;\r\nEndIf;\r\n\r\n### End Prolog ###", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% completed normally' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogOutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n### End Epilog ###", @@ -10,45 +10,33 @@ "Type": "None" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pMonthDays", - "Prompt": "OPTIONAL: Delimited string of days in month as dd e.g. 01 & 02 & 30 & 31 (Blank=All)", + "Prompt": "OPTIONAL: Delimited list of days in month as dd e.g. 01 & 02 & 30 & 31", "Value": "", "Type": "String" }, { "Name": "pWeekDays", - "Prompt": "OPTIONAL: Delimited string of days in week as ddd e.g. MON & WED (Blank=All)", + "Prompt": "OPTIONAL: Delimited list of days in week as ddd e.g. MON & WED", "Value": "", "Type": "String" }, { "Name": "pDelim", - "Prompt": "OPTIONAL: String array delimiter. Only 1 character allowed (Blank=&)", + "Prompt": "OPTIONAL: Delimiter for list parameters (Default = '&')", "Value": "&", "Type": "String" }, { "Name": "pStartTime", - "Prompt": "OPTIONAL: Time to start running chore from in 24 hr time (at start of hour) (Blank=0)", + "Prompt": "OPTIONAL: Hour to start running chore from in 24 hr time (at start of hour) (Default = 0)", "Value": 0, "Type": "Numeric" }, { "Name": "pEndTime", - "Prompt": "OPTIONAL: Time to finish chore being able to start in 24 hr time (Blank=24)", + "Prompt": "OPTIONAL: Hour to finish chore being able to start in 24 hr time (Default = 24)", "Value": 24, "Type": "Numeric" }, @@ -63,6 +51,24 @@ "Prompt": "OPTIONAL: Timezone for server if ScheduleTimezone is different", "Value": "", "Type": "String" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [], diff --git a/bedrock_processes_json/}bedrock.cube.clone.json b/bedrock_processes_json/}bedrock.cube.clone.json index 77738dc..de9912f 100644 --- a/bedrock_processes_json/}bedrock.cube.clone.json +++ b/bedrock_processes_json/}bedrock.cube.clone.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.cube.clone", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.cube.clone', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pSrcCube' ,'', 'pTgtCube', '',\r\n \t'pIncludeRules', 1, 'pIncludeData', 0,\r\n \t'pFilter', '',\r\n \t'pDimDelim', '&', 'pEleStartDelim', '\u00a6', 'pEleDelim', '+',\r\n \t'pSuppressRules', 1, 'pTemp', 1, 'pCubeLogging', 0\r\n );\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process replicates an existing cube. It can include data & rules too.\r\n\r\n# Use case: Intended for development/prototyping.\r\n# 1. Take a snapshot of cube data copying all rules to values.\r\n# 2. Take an exact copy of a cube in a \"one click action\" as a starting point for prototyping rule changes or developing new features.\r\n\r\n# Note:\r\n# * There are parameter options to include data (pIncludeData) and rules (pIncludeRules) with the creation of the cube.\r\n# * If the source cube (pSrcCube) is left blank or doesn't exist in the model, process will terminate withoud doing anything.\r\n# * If the target cube (pTgtCube) already exists in the model, process will terminate withoud doing anything.\r\n# * If the target cube is left blank or is the same as the source cube the cloned cube will inherit the source cube name with \"_Clone\" appended.\r\n# * If the source cube data only needs to be partially copied, then the pFilter parameter should be entered otherwise all other parameters can be left as is.\r\n# * In productive systems this process may be called internally by other processes (}bedrock.cube.data.copy, }bedrock.cube.data.copy.intercube) if copying data via intermediate cloned cube.\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent= 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pSrcCube:%pSrcCube%, pTgtCube:%pTgtCube%, pIncludeRules:%pIncludeRules%, pIncludeData:%pIncludeData%, pFilter:%pFilter%, pDimDelim:%pDimDelim%, pEleStartDelim:%pEleStartDelim%, pEleDelim:%pEleDelim%, pSuppressRules:%pSuppressRules%, pTemp:%pTemp%, pCubeLogging:%pCubeLogging%.' ; \r\ncDimCountMax = 30 ;\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Initialise ###\r\nnErrors = 0;\r\nnDataCheck = 0;\r\nsDimCountMax = NumberToString( cDimCountMax );\r\nsDimsString = '';\r\nsDelim = '+';\r\n\r\n### Validate Parameters ###\r\n\r\n## Default filter delimiters\r\nIf( pDimDelim @= '' );\r\n pDimDelim = '&';\r\nEndIf;\r\nIf( pEleStartDelim@= '' );\r\n pEleStartDelim= '\u00a6';\r\nEndIf;\r\nIf( pEleDelim @= '' );\r\n pEleDelim = '+';\r\nEndIf;\r\n\r\n# Validate source cube\r\nIf( Trim( pSrcCube ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No cube specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( CubeExists( pSrcCube ) = 0 ); \r\n sMessage = Expand( 'Invalid source cube specified: %pSrcCube%.' );\r\n nErrors = 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate target cube\r\nIf( pTgtCube @= '' % pTgtCube @= pSrcCube );\r\n pTgtCube = pSrcCube | '_Clone';\r\nEndIf;\r\nIf( CubeExists( pTgtCube ) = 1 ); \r\n sMessage = Expand( 'Invalid target cube : %pTgtCube%.' );\r\n nErrors = 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### Create the clone cube ###\r\nnDimCount = 1;\r\nWhile( TabDim( pSrcCube, nDimCount ) @<> '' );\r\n sDimName = TabDim (pSrcCube, nDimCount);\r\n sDimsString = sDimsString | sDimName | sDelim;\r\n nDimCount = nDimCount + 1;\r\nEnd;\r\nnDimCount = nDimCount - 1;\r\nsDimsString = Subst(sDimsString,1,long(sDimsString)-long(sDelim));\r\n\r\nIf( nDimCount > cDimCountMax );\r\n nErrors = 1;\r\n sMessage = Expand( 'Cube has too many dimensions: %pSrcCube% max %sDimCountMax% dims catered for, TI must be altered to accomodate.' );\r\n DataSourceType = 'NULL';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\nsProc = '}bedrock.cube.create';\r\nnRet = ExecuteProcess( sProc,\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pCube', pTgtCube,\r\n 'pDims', sDimsString,\r\n 'pRecreate', 1,\r\n 'pDelim', sDelim\r\n );\r\n\r\nIF(nRet <> 0);\r\n sMessage = 'Error creating the target cube.';\r\n nErrors = 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nENDIF;\r\n\r\n### copy data ####\r\nIf( pIncludeData = 1 );\r\nnRet = ExecuteProcess('}bedrock.cube.data.copy.intercube',\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pSrcCube',pSrcCube,\r\n \t'pFilter',pFilter,\r\n \t'pTgtCube',pTgtCube,\r\n \t'pMappingToNewDims','',\r\n \t'pSuppressConsol',1,\r\n \t'pSuppressRules',pSuppressRules,\r\n \t'pZeroTarget',0,\r\n \t'pZeroSource',0,\r\n \t'pFactor',1,\r\n 'pDimDelim', pDimDelim,\r\n 'pEleStartDelim', pEleStartDelim,\r\n 'pEleDelim', pEleDelim,\r\n 'pTemp', pTemp,\r\n 'pCubeLogging', pCubeLogging);\r\n\r\n IF(nRet <> 0);\r\n sMessage = 'Error copying data.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n ENDIF;\r\n\r\nEndIf;\r\n\r\n### End Prolog ###", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.cube.clone', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pSrcCube' ,'', 'pTgtCube', '',\r\n \t'pIncludeRules', 1, 'pIncludeData', 0,\r\n \t'pFilter', '',\r\n \t'pDimDelim', '&', 'pEleStartDelim', '\u00a6', 'pEleDelim', '+',\r\n \t'pSuppressRules', 1, 'pTemp', 1, 'pCubeLogging', 0\r\n );\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process replicates an existing cube. It can include data & rules too.\r\n\r\n# Use case: Intended for development/prototyping.\r\n# 1. Take a snapshot of cube data copying all rules to values.\r\n# 2. Take an exact copy of a cube in a \"one click action\" as a starting point for prototyping rule changes or developing new features.\r\n\r\n# Note:\r\n# * There are parameter options to include data (pIncludeData) and rules (pIncludeRules) with the creation of the cube.\r\n# * If the source cube (pSrcCube) is left blank or doesn't exist in the model, process will terminate withoud doing anything.\r\n# * If the target cube (pTgtCube) already exists in the model, process will terminate withoud doing anything.\r\n# * If the target cube is left blank or is the same as the source cube the cloned cube will inherit the source cube name with \"_Clone\" appended.\r\n# * If the source cube data only needs to be partially copied, then the pFilter parameter should be entered otherwise all other parameters can be left as is.\r\n# * In productive systems this process may be called internally by other processes (}bedrock.cube.data.copy, }bedrock.cube.data.copy.intercube) if copying data via intermediate cloned cube.\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent= 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pSrcCube:%pSrcCube%, pTgtCube:%pTgtCube%, pIncludeRules:%pIncludeRules%, pIncludeData:%pIncludeData%, pFilter:%pFilter%, pDimDelim:%pDimDelim%, pEleStartDelim:%pEleStartDelim%, pEleDelim:%pEleDelim%, pSuppressRules:%pSuppressRules%, pTemp:%pTemp%, pCubeLogging:%pCubeLogging%.' ; \r\ncDimCountMax = 30 ;\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pDimDelim\": \"&\",\r\n \"pEleDelim\": \"+\",\r\n \"pEleStartDelim\": \"\u00a6\",\r\n \"pFilter\": \"\",\r\n \"pSrcCube\": null,\r\n \"pTgtCube\": \"\",\r\n \"pIncludeData\": 0,\r\n \"pIncludeRules\": 1,\r\n \"pLogOutput\": 0,\r\n \"pStrictErrorHandling\": 0,\r\n \"pSuppressRules\": 1,\r\n \"pTemp\": 1\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pDimDelim\": '|StringToJson ( pDimDelim )|',\r\n \"pEleDelim\": '|StringToJson ( pEleDelim )|',\r\n \"pEleStartDelim\": '|StringToJson ( pEleStartDelim )|',\r\n \"pFilter\": '|StringToJson ( pFilter )|',\r\n \"pSrcCube\": '|StringToJson ( pSrcCube )|',\r\n \"pTgtCube\": '|StringToJson ( pTgtCube )|',\r\n \"pIncludeData\": '|NumberToString( pIncludeData )|',\r\n \"pIncludeRules\": '|NumberToString( pIncludeRules )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|',\r\n \"pSuppressRules\": '|NumberToString( pSuppressRules )|',\r\n \"pTemp\": '|NumberToString( pTemp )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npDimDelim = JsonToString( JsonGet( pJson, 'pDimDelim' ) );\r\npEleDelim = JsonToString( JsonGet( pJson, 'pEleDelim' ) );\r\npEleStartDelim = JsonToString( JsonGet( pJson, 'pEleStartDelim' ) );\r\npFilter = JsonToString( JsonGet( pJson, 'pFilter' ) );\r\npSrcCube = JsonToString( JsonGet( pJson, 'pSrcCube' ) );\r\npTgtCube = JsonToString( JsonGet( pJson, 'pTgtCube' ) );\r\n# Numeric Parameters\r\npIncludeData = StringToNumber( JsonToString( JsonGet( pJson, 'pIncludeData' ) ) );\r\npIncludeRules = StringToNumber( JsonToString( JsonGet( pJson, 'pIncludeRules' ) ) );\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\npSuppressRules = StringToNumber( JsonToString( JsonGet( pJson, 'pSuppressRules' ) ) );\r\npTemp = StringToNumber( JsonToString( JsonGet( pJson, 'pTemp' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Initialise ###\r\nnErrors = 0;\r\nnDataCheck = 0;\r\nsDimCountMax = NumberToString( cDimCountMax );\r\nsDimsString = '';\r\nsDelim = '+';\r\n\r\n### Validate Parameters ###\r\n\r\n## Default filter delimiters\r\nIf( pDimDelim @= '' );\r\n pDimDelim = '&';\r\nEndIf;\r\nIf( pEleStartDelim@= '' );\r\n pEleStartDelim= '\u00a6';\r\nEndIf;\r\nIf( pEleDelim @= '' );\r\n pEleDelim = '+';\r\nEndIf;\r\n\r\n# Validate source cube\r\nIf( Trim( pSrcCube ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No cube specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( CubeExists( pSrcCube ) = 0 ); \r\n sMessage = Expand( 'Invalid source cube specified: %pSrcCube%.' );\r\n nErrors = 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate target cube\r\nIf( pTgtCube @= '' % pTgtCube @= pSrcCube );\r\n pTgtCube = pSrcCube | '_Clone';\r\nEndIf;\r\nIf( CubeExists( pTgtCube ) = 1 ); \r\n sMessage = Expand( 'Invalid target cube : %pTgtCube%.' );\r\n nErrors = 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### Create the clone cube ###\r\nnDimCount = 1;\r\nWhile( TabDim( pSrcCube, nDimCount ) @<> '' );\r\n sDimName = TabDim (pSrcCube, nDimCount);\r\n sDimsString = sDimsString | sDimName | sDelim;\r\n nDimCount = nDimCount + 1;\r\nEnd;\r\nnDimCount = nDimCount - 1;\r\nsDimsString = Subst(sDimsString,1,long(sDimsString)-long(sDelim));\r\n\r\nIf( nDimCount > cDimCountMax );\r\n nErrors = 1;\r\n sMessage = Expand( 'Cube has too many dimensions: %pSrcCube% max %sDimCountMax% dims catered for, TI must be altered to accomodate.' );\r\n DataSourceType = 'NULL';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\nsProc = '}bedrock.cube.create';\r\nnRet = ExecuteProcess( sProc,\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pCube', pTgtCube,\r\n 'pDims', sDimsString,\r\n 'pRecreate', 1,\r\n 'pDelim', sDelim\r\n );\r\n\r\nIF(nRet <> 0);\r\n sMessage = 'Error creating the target cube.';\r\n nErrors = 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nENDIF;\r\n\r\n### copy data ####\r\nIf( pIncludeData = 1 );\r\nnRet = ExecuteProcess('}bedrock.cube.data.copy.intercube',\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pSrcCube',pSrcCube,\r\n \t'pFilter',pFilter,\r\n \t'pTgtCube',pTgtCube,\r\n \t'pMappingToNewDims','',\r\n \t'pSuppressConsol',1,\r\n \t'pSuppressRules',pSuppressRules,\r\n \t'pZeroTarget',0,\r\n \t'pZeroSource',0,\r\n \t'pFactor',1,\r\n 'pDimDelim', pDimDelim,\r\n 'pEleStartDelim', pEleStartDelim,\r\n 'pEleDelim', pEleDelim,\r\n 'pTemp', pTemp,\r\n 'pCubeLogging', pCubeLogging);\r\n\r\n IF(nRet <> 0);\r\n sMessage = 'Error copying data.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n ENDIF;\r\n\r\nEndIf;\r\n\r\n### End Prolog ###", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n### Attach rules to cloned cube ###\r\nIf( nErrors = 0 & pIncludeRules = 1 );\r\n sRule=CubeRuleGet( pSrcCube );\r\n If( sRule@<> '' );\r\n If( nErrors = 0 );\r\n CubeRuleSet(pTgtCube, sRule);\r\n EndIf;\r\n EndIf;\r\nEndIf;\r\n \r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully cloned the %pSrcCube% cube to %pTgtCube%.' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If ( pLogOutput = 1 );\r\n LogOutput('INFO', Expand ( sProcessAction ) );\r\n EndIf;\r\nEndIf;\r\n\r\n### End Epilog ###", @@ -10,83 +10,89 @@ "Type": "None" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pSrcCube", - "Prompt": "REQUIRED: Source Cube", + "Prompt": "REQUIRED: Source cube name", "Value": "", "Type": "String" }, { "Name": "pTgtCube", - "Prompt": "OPTIONAL: Target Cube to create/re-create (Source cube_clone if left blank)", + "Prompt": "OPTIONAL: Target cube to create/re-create (Default = pSrcCube | '_Clone')", "Value": "", "Type": "String" }, { "Name": "pIncludeRules", - "Prompt": "REQUIRED: Include cube rules? (Boolean Yes = 1)", + "Prompt": "OPTIONAL: Include cube rules (Boolean. Default = 1)", "Value": 1, "Type": "Numeric" }, { "Name": "pIncludeData", - "Prompt": "REQUIRED: Include cube data? (Boolean Yes = 1)", + "Prompt": "OPTIONAL: Include cube data (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { "Name": "pFilter", - "Prompt": "OPTIONAL: Filter on source cube in format Year\u00a6 2006 + 2007 & Scenario\u00a6 Actual + Budget. Blank for whole cube", + "Prompt": "OPTIONAL: Filter on cube in format: 'dim_one\u00a6 el_one + el_two & dim_two\u00a6 el_one + el_two'", "Value": "", "Type": "String" }, { "Name": "pDimDelim", - "Prompt": "OPTIONAL: Delimiter for start of Dimension/Element set (default value if blank = '&')", + "Prompt": "OPTIONAL: Delimiter for start of dimension/element set in filter parameters (Default = '&')", "Value": "&", "Type": "String" }, { "Name": "pEleStartDelim", - "Prompt": "OPTIONAL: Delimiter for start of element list (default value if blank = '\u00a6')", + "Prompt": "OPTIONAL: Delimiter for start of element list in filter parameters (Default = '\u00a6')", "Value": "\u00a6", "Type": "String" }, { "Name": "pEleDelim", - "Prompt": "OPTIONAL: Delimiter between elements (default value if blank = '+')", + "Prompt": "OPTIONAL: Delimiter between elements in filter parameters (Default = '+')", "Value": "+", "Type": "String" }, { "Name": "pSuppressRules", - "Prompt": "REQUIRED: Skip rule values? (1=skip)", + "Prompt": "OPTIONAL: Suppress rules (Boolean. Default = 1)", "Value": 1, "Type": "Numeric" }, { "Name": "pTemp", - "Prompt": "REQUIRED: Delete temporary view and Subset ( 0 = Retain View and Subsets 1 = Delete View and Subsets 2 = Delete View only )", + "Prompt": "OPTIONAL: Delete/create temporary objects (0 = Do not delete, 1 = Delete, 2 = if view and subsets are created, keep only subsets)", "Value": 1, "Type": "Numeric" }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, { "Name": "pCubeLogging", "Prompt": "OBSOLETE: This parameter does nothing and is only included for backwards compatability", "Value": 0, "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [ @@ -287,34 +293,5 @@ "EndByte": 0 } ], - "VariablesUIData": [ - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f" - ] + "VariablesUIData": [] } \ No newline at end of file diff --git a/bedrock_processes_json/}bedrock.cube.create.json b/bedrock_processes_json/}bedrock.cube.create.json index faa2019..d0ec41c 100644 --- a/bedrock_processes_json/}bedrock.cube.create.json +++ b/bedrock_processes_json/}bedrock.cube.create.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.cube.create", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.cube.create', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pCube', '', 'pDims', '',\r\n \t'pRecreate', 0, 'pDelim', '&'\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description: \r\n# This process automatically creates a cube based on a delimited string of dimension names.\r\n\r\n# Use case: Intended for development/prototyping.\r\n# 1/ This can be used to quickly create a cube for a demo or development.\r\n\r\n# Note:\r\n# The pDims parameter contains the dimenson list and is mandatory.\r\n# The format of the pDims parameter is as follows for delimiter of '&' (e.g. Dim1 & Dim2 & Dim3 ).\r\n# Spaces are ignored so use them to make your filter more readable.\r\n# The order of the dimension list specifies the initial index order of dimensions in the cube.\r\n# pRecreate is an optional parameter for creating new cubes:\r\n# - If a cube already exists and pRecreate is set to 0 then the process will abort.\r\n# - If a cube already exists and pRecreate is set to 1 then the process will destroy the old cube and recreate with the specified dimensionality.\r\n#EndRegion @DOC\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncDelimDim = TRIM(pDelim);\r\nnDims = 0;\r\nnDimMax = 100;\r\nnErrors = 0;\r\nsMessage = '';\r\ncUserName = TM1User();\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pCube:%pCube%, pDims:%pDims%, pRecreate:%pRecreate%, pDelim:%pDelim%.' ; \r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n## Validate the Cube parameter\r\nIf( TRIM(pCube) @= '' );\r\n sMessage = 'A cube name must be provided.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# If specified cube exists and recreate option not set to true then terminate process\r\nIf( CubeExists( pCube ) = 1 );\r\n If( pRecreate <> 1 );\r\n sMessage = Expand( 'Cube %pCube% already exists. Aborting cube create.' );\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n EndIf;\r\nEndIf;\r\n\r\n# Check the delimiter\r\nIf( cDelimDim @= '' );\r\n cDelimDim = '&';\r\nEndIf;\r\n\r\n# Check the dimension list can't be empty\r\nIf( pDims @= '' );\r\n sMessage = 'The dimension list is blank.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Check the dimension list must contain delimiter\r\nIf( Scan( cDelimDim, pDims ) < 2 );\r\n sMessage = 'The dimension list must contain at least 2 dimension names separated by the delimiter.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### Initialise the dimension variables ###\r\nsDim01 = '';\r\nsDim02 = '';\r\nsDim03 = '';\r\nsDim04 = '';\r\nsDim05 = '';\r\nsDim06 = '';\r\nsDim07 = '';\r\nsDim08 = '';\r\nsDim09 = '';\r\nsDim10 = '';\r\nsDim11 = '';\r\nsDim12 = '';\r\nsDim13 = '';\r\nsDim14 = '';\r\nsDim15 = '';\r\nsDim16 = '';\r\nsDim17 = '';\r\nsDim18 = '';\r\nsDim19 = '';\r\nsDim20 = '';\r\nsDim21 = '';\r\nsDim22 = '';\r\nsDim23 = '';\r\nsDim24 = '';\r\nsDim25 = '';\r\nsDim26 = '';\r\nsDim27 = '';\r\nsDim28 = '';\r\nsDim29 = '';\r\nsDim30 = '';\r\nsDim31 = '';\r\nsDim32 = '';\r\nsDim33 = '';\r\nsDim34 = '';\r\nsDim35 = '';\r\nsDim36 = '';\r\nsDim37 = '';\r\nsDim38 = '';\r\nsDim39 = '';\r\nsDim40 = '';\r\nsDim41 = '';\r\nsDim42 = '';\r\nsDim43 = '';\r\nsDim44 = '';\r\nsDim45 = '';\r\nsDim46 = '';\r\nsDim47 = '';\r\nsDim48 = '';\r\nsDim49 = '';\r\nsDim50 = '';\r\nsDim51 = '';\r\nsDim52 = '';\r\nsDim53 = '';\r\nsDim54 = '';\r\nsDim55 = '';\r\nsDim56 = '';\r\nsDim57 = '';\r\nsDim58 = '';\r\nsDim59 = '';\r\nsDim60 = '';\r\nsDim61 = '';\r\nsDim62 = '';\r\nsDim63 = '';\r\nsDim64 = '';\r\nsDim65 = '';\r\nsDim66 = '';\r\nsDim67 = '';\r\nsDim68 = '';\r\nsDim69 = '';\r\nsDim70 = '';\r\nsDim71 = '';\r\nsDim72 = '';\r\nsDim73 = '';\r\nsDim74 = '';\r\nsDim75 = '';\r\nsDim76 = '';\r\nsDim77 = '';\r\nsDim78 = '';\r\nsDim79 = '';\r\nsDim80 = '';\r\nsDim81 = '';\r\nsDim82 = '';\r\nsDim83 = '';\r\nsDim84 = '';\r\nsDim85 = '';\r\nsDim86 = '';\r\nsDim87 = '';\r\nsDim88 = '';\r\nsDim89 = '';\r\nsDim90 = '';\r\nsDim91 = '';\r\nsDim92 = '';\r\nsDim93 = '';\r\nsDim94 = '';\r\nsDim95 = '';\r\nsDim96 = '';\r\nsDim97 = '';\r\nsDim98 = '';\r\nsDim99 = '';\r\nsDim100 = '';\r\n\r\n### Split delimited dimension list and count number of dimensions ###\r\nsDims = TRIM( pDims );\r\nnDelimIndex = 1;\r\n\r\nWhile( nDelimIndex > 0 & Long( sDims ) > 0 );\r\n\r\n nDelimIndex = Scan( cDelimDim, sDims );\r\n If( nDelimIndex > 0 );\r\n sDim = Trim( SubSt( sDims, 1, nDelimIndex - 1 ) );\r\n sDims = Trim( SubSt( sDims, nDelimIndex + Long( cDelimDim ), Long( sDims ) ) );\r\n Else;\r\n sDim = Trim( sDims );\r\n EndIf;\r\n\r\n If( DimensionExists( sDim ) = 1 );\r\n # sDim recognized as a dimension, increment the dim counter and set the dim name variable (how we wish Expand worked on the LHS of = ...)\r\n nDims = nDims + 1;\r\n If( nDims > nDimMax );\r\n sMessage = 'Maximum number of dimensions exceeded. Aborting';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n EndIf;\r\n If( nDims = 1 );\r\n sDim01 = sDim;\r\n ElseIf( nDims = 2 );\r\n sDim02 = sDim;\r\n ElseIf( nDims = 3 );\r\n sDim03 = sDim;\r\n ElseIf( nDims = 4 );\r\n sDim04 = sDim;\r\n ElseIf( nDims = 5 );\r\n sDim05 = sDim;\r\n ElseIf( nDims = 6 );\r\n sDim06 = sDim;\r\n ElseIf( nDims = 7 );\r\n sDim07 = sDim;\r\n ElseIf( nDims = 8 );\r\n sDim08 = sDim;\r\n ElseIf( nDims = 9 );\r\n sDim09 = sDim;\r\n ElseIf( nDims = 10 );\r\n sDim10 = sDim;\r\n ElseIf( nDims = 11 );\r\n sDim11 = sDim;\r\n ElseIf( nDims = 12 );\r\n sDim12 = sDim;\r\n ElseIf( nDims = 13 );\r\n sDim13 = sDim;\r\n ElseIf( nDims = 14 );\r\n sDim14 = sDim;\r\n ElseIf( nDims = 15 );\r\n sDim15 = sDim;\r\n ElseIf( nDims = 16 );\r\n sDim16 = sDim;\r\n ElseIf( nDims = 17 );\r\n sDim17 = sDim;\r\n ElseIf( nDims = 18 );\r\n sDim18 = sDim;\r\n ElseIf( nDims = 19 );\r\n sDim19 = sDim;\r\n ElseIf( nDims = 20 );\r\n sDim20 = sDim;\r\n ElseIf( nDims = 21 );\r\n sDim21 = sDim;\r\n ElseIf( nDims = 22 );\r\n sDim22 = sDim;\r\n ElseIf( nDims = 23 );\r\n sDim23 = sDim;\r\n ElseIf( nDims = 24 );\r\n sDim24 = sDim;\r\n ElseIf( nDims = 25 );\r\n sDim25 = sDim;\r\n ElseIf( nDims = 26 );\r\n sDim26 = sDim;\r\n ElseIf( nDims = 27 );\r\n sDim27 = sDim;\r\n ElseIf( nDims = 28 );\r\n sDim28 = sDim;\r\n ElseIf( nDims = 29 );\r\n sDim29 = sDim;\r\n ElseIf( nDims = 30 );\r\n sDim30 = sDim;\r\n ElseIf( nDims = 31 );\r\n sDim31 = sDim;\r\n ElseIf( nDims = 32 );\r\n sDim32 = sDim;\r\n ElseIf( nDims = 33 );\r\n sDim33 = sDim;\r\n ElseIf( nDims = 34 );\r\n sDim34 = sDim;\r\n ElseIf( nDims = 35 );\r\n sDim35 = sDim;\r\n ElseIf( nDims = 36 );\r\n sDim36 = sDim;\r\n ElseIf( nDims = 37 );\r\n sDim37 = sDim;\r\n ElseIf( nDims = 38 );\r\n sDim38 = sDim;\r\n ElseIf( nDims = 39 );\r\n sDim39 = sDim;\r\n ElseIf( nDims = 40 );\r\n sDim40 = sDim;\r\n ElseIf( nDims = 41 );\r\n sDim41 = sDim;\r\n ElseIf( nDims = 42 );\r\n sDim42 = sDim;\r\n ElseIf( nDims = 43 );\r\n sDim43 = sDim;\r\n ElseIf( nDims = 44 );\r\n sDim44 = sDim;\r\n ElseIf( nDims = 45 );\r\n sDim45 = sDim;\r\n ElseIf( nDims = 46 );\r\n sDim46 = sDim;\r\n ElseIf( nDims = 47 );\r\n sDim47 = sDim;\r\n ElseIf( nDims = 48 );\r\n sDim48 = sDim;\r\n ElseIf( nDims = 49 );\r\n sDim49 = sDim;\r\n ElseIf( nDims = 50 );\r\n sDim50 = sDim;\r\n ElseIf( nDims = 51 );\r\n sDim51 = sDim;\r\n ElseIf( nDims = 52 );\r\n sDim52 = sDim;\r\n ElseIf( nDims = 53 );\r\n sDim53 = sDim;\r\n ElseIf( nDims = 54 );\r\n sDim54 = sDim;\r\n ElseIf( nDims = 55 );\r\n sDim55 = sDim;\r\n ElseIf( nDims = 56 );\r\n sDim56 = sDim;\r\n ElseIf( nDims = 57 );\r\n sDim57 = sDim;\r\n ElseIf( nDims = 58 );\r\n sDim58 = sDim;\r\n ElseIf( nDims = 59 );\r\n sDim59 = sDim;\r\n ElseIf( nDims = 60 );\r\n sDim60 = sDim;\r\n ElseIf( nDims = 61 );\r\n sDim61 = sDim;\r\n ElseIf( nDims = 62 );\r\n sDim62 = sDim;\r\n ElseIf( nDims = 63 );\r\n sDim63 = sDim;\r\n ElseIf( nDims = 64 );\r\n sDim64 = sDim;\r\n ElseIf( nDims = 65 );\r\n sDim65 = sDim;\r\n ElseIf( nDims = 66 );\r\n sDim66 = sDim;\r\n ElseIf( nDims = 67 );\r\n sDim67 = sDim;\r\n ElseIf( nDims = 68 );\r\n sDim68 = sDim;\r\n ElseIf( nDims = 69 );\r\n sDim69 = sDim;\r\n ElseIf( nDims = 70 );\r\n sDim70 = sDim;\r\n ElseIf( nDims = 71 );\r\n sDim71 = sDim;\r\n ElseIf( nDims = 72 );\r\n sDim72 = sDim;\r\n ElseIf( nDims = 73 );\r\n sDim73 = sDim;\r\n ElseIf( nDims = 74 );\r\n sDim74 = sDim;\r\n ElseIf( nDims = 75 );\r\n sDim75 = sDim;\r\n ElseIf( nDims = 76 );\r\n sDim76 = sDim;\r\n ElseIf( nDims = 77 );\r\n sDim77 = sDim;\r\n ElseIf( nDims = 78 );\r\n sDim78 = sDim;\r\n ElseIf( nDims = 79 );\r\n sDim79 = sDim;\r\n ElseIf( nDims = 80 );\r\n sDim80 = sDim;\r\n ElseIf( nDims = 81 );\r\n sDim81 = sDim;\r\n ElseIf( nDims = 82 );\r\n sDim82 = sDim;\r\n ElseIf( nDims = 83 );\r\n sDim83 = sDim;\r\n ElseIf( nDims = 84 );\r\n sDim84 = sDim;\r\n ElseIf( nDims = 85 );\r\n sDim85 = sDim;\r\n ElseIf( nDims = 86 );\r\n sDim86 = sDim;\r\n ElseIf( nDims = 87 );\r\n sDim87 = sDim;\r\n ElseIf( nDims = 88 );\r\n sDim88 = sDim;\r\n ElseIf( nDims = 89 );\r\n sDim89 = sDim;\r\n ElseIf( nDims = 90 );\r\n sDim90 = sDim;\r\n ElseIf( nDims = 91 );\r\n sDim91 = sDim;\r\n ElseIf( nDims = 92 );\r\n sDim92 = sDim;\r\n ElseIf( nDims = 93 );\r\n sDim93 = sDim;\r\n ElseIf( nDims = 94 );\r\n sDim94 = sDim;\r\n ElseIf( nDims = 95 );\r\n sDim95 = sDim;\r\n ElseIf( nDims = 96 );\r\n sDim96 = sDim;\r\n ElseIf( nDims = 97 );\r\n sDim97 = sDim;\r\n ElseIf( nDims = 98 );\r\n sDim98 = sDim;\r\n ElseIf( nDims = 99 );\r\n sDim99 = sDim;\r\n ElseIf( nDims = 100 );\r\n sDim100 = sDim;\r\n EndIf; \r\n\r\n Else;\r\n\r\n # sDim not recognized as valid dimension\r\n sMessage = Expand( '%sDim% not recognized as valid dimension.' );\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n EndIf;\r\n\r\nEnd;\r\n\r\n### Create the cube ###\r\n\r\nIf( nDims < 2 );\r\n sMessage = 'Number of dimesnions specified is less than 2';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\nIf( CubeExists( pCube ) = 1 & pRecreate = 1 );\r\n CubeDestroy( pCube );\r\nEndIf;\r\n\r\nIf( nDims = 2 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02 );\r\nElseIf( nDims = 3 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03 );\r\nElseIf( nDims = 4 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04 );\r\nElseIf( nDims = 5 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05 );\r\nElseIf( nDims = 6 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06 );\r\nElseIf( nDims = 7 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07 );\r\nElseIf( nDims = 8 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08 );\r\nElseIf( nDims = 9 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09 );\r\nElseIf( nDims = 10 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10 );\r\nElseIf( nDims = 11 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11 );\r\nElseIf( nDims = 12 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12 );\r\nElseIf( nDims = 13 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13 );\r\nElseIf( nDims = 14 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14 );\r\nElseIf( nDims = 15 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15 );\r\nElseIf( nDims = 16 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16 );\r\nElseIf( nDims = 17 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17 );\r\nElseIf( nDims = 18 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18 );\r\nElseIf( nDims = 19 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19 );\r\nElseIf( nDims = 20 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20 );\r\nElseIf( nDims = 21 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21 );\r\nElseIf( nDims = 22 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22 );\r\nElseIf( nDims = 23 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23 );\r\nElseIf( nDims = 24 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24 );\r\nElseIf( nDims = 25 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25 );\r\nElseIf( nDims = 26 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26 );\r\nElseIf( nDims = 27 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27 );\r\nElseIf( nDims = 28 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28 );\r\nElseIf( nDims = 29 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29 );\r\nElseIf( nDims = 30 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30 );\r\nElseIf( nDims = 31 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31 );\r\nElseIf( nDims = 32 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32 );\r\nElseIf( nDims = 33 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33 );\r\nElseIf( nDims = 34 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34 );\r\nElseIf( nDims = 35 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35 );\r\nElseIf( nDims = 36 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36 );\r\nElseIf( nDims = 37 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37 );\r\nElseIf( nDims = 38 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38 );\r\nElseIf( nDims = 39 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39 );\r\nElseIf( nDims = 40 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40 );\r\nElseIf( nDims = 41 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41 );\r\nElseIf( nDims = 42 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42 );\r\nElseIf( nDims = 43 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43 );\r\nElseIf( nDims = 44 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44 );\r\nElseIf( nDims = 45 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45 );\r\nElseIf( nDims = 46 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46 );\r\nElseIf( nDims = 47 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47 );\r\nElseIf( nDims = 48 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48 );\r\nElseIf( nDims = 49 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49 );\r\nElseIf( nDims = 50 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50 );\r\nElseIf( nDims = 51 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51 );\r\nElseIf( nDims = 52 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52 );\r\nElseIf( nDims = 53 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53 );\r\nElseIf( nDims = 54 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54 );\r\nElseIf( nDims = 55 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55 );\r\nElseIf( nDims = 56 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56 );\r\nElseIf( nDims = 57 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57 );\r\nElseIf( nDims = 58 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58 );\r\nElseIf( nDims = 59 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59 );\r\nElseIf( nDims = 60 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60 );\r\nElseIf( nDims = 61 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61 );\r\nElseIf( nDims = 62 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62 );\r\nElseIf( nDims = 63 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63 );\r\nElseIf( nDims = 64 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64 );\r\nElseIf( nDims = 65 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65 );\r\nElseIf( nDims = 66 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66 );\r\nElseIf( nDims = 67 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67 );\r\nElseIf( nDims = 68 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68 );\r\nElseIf( nDims = 69 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69 );\r\nElseIf( nDims = 70 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69, sDim70 );\r\nElseIf( nDims = 71 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69, sDim70, sDim71 );\r\nElseIf( nDims = 72 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69, sDim70, sDim71, sDim72 );\r\nElseIf( nDims = 73 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69, sDim70, sDim71, sDim72, sDim73 );\r\nElseIf( nDims = 74 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69, sDim70, sDim71, sDim72, sDim73, sDim74 );\r\nElseIf( nDims = 75 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69, sDim70, sDim71, sDim72, sDim73, sDim74, sDim75 );\r\nElseIf( nDims = 76 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69, sDim70, sDim71, sDim72, sDim73, sDim74, sDim75, sDim76 );\r\nElseIf( nDims = 77 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69, sDim70, sDim71, sDim72, sDim73, sDim74, sDim75, sDim76, sDim77 );\r\nElseIf( nDims = 78 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69, sDim70, sDim71, sDim72, sDim73, sDim74, sDim75, sDim76, sDim77, sDim78 );\r\nElseIf( nDims = 79 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69, sDim70, sDim71, sDim72, sDim73, sDim74, sDim75, sDim76, sDim77, sDim78, sDim79 );\r\nElseIf( nDims = 80 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69, sDim70, sDim71, sDim72, sDim73, sDim74, sDim75, sDim76, sDim77, sDim78, sDim79, sDim80 );\r\nElseIf( nDims = 81 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69, sDim70, sDim71, sDim72, sDim73, sDim74, sDim75, sDim76, sDim77, sDim78, sDim79, sDim80, sDim81 );\r\nElseIf( nDims = 82 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69, sDim70, sDim71, sDim72, sDim73, sDim74, sDim75, sDim76, sDim77, sDim78, sDim79, sDim80, sDim81, sDim82 );\r\nElseIf( nDims = 83 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69, sDim70, sDim71, sDim72, sDim73, sDim74, sDim75, sDim76, sDim77, sDim78, sDim79, sDim80, sDim81, sDim82, sDim83 );\r\nElseIf( nDims = 84 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69, sDim70, sDim71, sDim72, sDim73, sDim74, sDim75, sDim76, sDim77, sDim78, sDim79, sDim80, sDim81, sDim82, sDim83, sDim84 );\r\nElseIf( nDims = 85 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69, sDim70, sDim71, sDim72, sDim73, sDim74, sDim75, sDim76, sDim77, sDim78, sDim79, sDim80, sDim81, sDim82, sDim83, sDim84, sDim85 );\r\nElseIf( nDims = 86 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69, sDim70, sDim71, sDim72, sDim73, sDim74, sDim75, sDim76, sDim77, sDim78, sDim79, sDim80, sDim81, sDim82, sDim83, sDim84, sDim85, sDim86 );\r\nElseIf( nDims = 87 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69, sDim70, sDim71, sDim72, sDim73, sDim74, sDim75, sDim76, sDim77, sDim78, sDim79, sDim80, sDim81, sDim82, sDim83, sDim84, sDim85, sDim86, sDim87 );\r\nElseIf( nDims = 88 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69, sDim70, sDim71, sDim72, sDim73, sDim74, sDim75, sDim76, sDim77, sDim78, sDim79, sDim80, sDim81, sDim82, sDim83, sDim84, sDim85, sDim86, sDim87, sDim88 );\r\nElseIf( nDims = 89 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69, sDim70, sDim71, sDim72, sDim73, sDim74, sDim75, sDim76, sDim77, sDim78, sDim79, sDim80, sDim81, sDim82, sDim83, sDim84, sDim85, sDim86, sDim87, sDim88, sDim89 );\r\nElseIf( nDims = 90 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69, sDim70, sDim71, sDim72, sDim73, sDim74, sDim75, sDim76, sDim77, sDim78, sDim79, sDim80, sDim81, sDim82, sDim83, sDim84, sDim85, sDim86, sDim87, sDim88, sDim89, sDim90 );\r\nElseIf( nDims = 91 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69, sDim70, sDim71, sDim72, sDim73, sDim74, sDim75, sDim76, sDim77, sDim78, sDim79, sDim80, sDim81, sDim82, sDim83, sDim84, sDim85, sDim86, sDim87, sDim88, sDim89, sDim90, sDim91 );\r\nElseIf( nDims = 92 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69, sDim70, sDim71, sDim72, sDim73, sDim74, sDim75, sDim76, sDim77, sDim78, sDim79, sDim80, sDim81, sDim82, sDim83, sDim84, sDim85, sDim86, sDim87, sDim88, sDim89, sDim90, sDim91, sDim92 );\r\nElseIf( nDims = 93 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69, sDim70, sDim71, sDim72, sDim73, sDim74, sDim75, sDim76, sDim77, sDim78, sDim79, sDim80, sDim81, sDim82, sDim83, sDim84, sDim85, sDim86, sDim87, sDim88, sDim89, sDim90, sDim91, sDim92, sDim93 );\r\nElseIf( nDims = 94 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69, sDim70, sDim71, sDim72, sDim73, sDim74, sDim75, sDim76, sDim77, sDim78, sDim79, sDim80, sDim81, sDim82, sDim83, sDim84, sDim85, sDim86, sDim87, sDim88, sDim89, sDim90, sDim91, sDim92, sDim93, sDim94 );\r\nElseIf( nDims = 95 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69, sDim70, sDim71, sDim72, sDim73, sDim74, sDim75, sDim76, sDim77, sDim78, sDim79, sDim80, sDim81, sDim82, sDim83, sDim84, sDim85, sDim86, sDim87, sDim88, sDim89, sDim90, sDim91, sDim92, sDim93, sDim94, sDim95 );\r\nElseIf( nDims = 96 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69, sDim70, sDim71, sDim72, sDim73, sDim74, sDim75, sDim76, sDim77, sDim78, sDim79, sDim80, sDim81, sDim82, sDim83, sDim84, sDim85, sDim86, sDim87, sDim88, sDim89, sDim90, sDim91, sDim92, sDim93, sDim94, sDim95, sDim96 );\r\nElseIf( nDims = 97 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69, sDim70, sDim71, sDim72, sDim73, sDim74, sDim75, sDim76, sDim77, sDim78, sDim79, sDim80, sDim81, sDim82, sDim83, sDim84, sDim85, sDim86, sDim87, sDim88, sDim89, sDim90, sDim91, sDim92, sDim93, sDim94, sDim95, sDim96, sDim97 );\r\nElseIf( nDims = 98 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69, sDim70, sDim71, sDim72, sDim73, sDim74, sDim75, sDim76, sDim77, sDim78, sDim79, sDim80, sDim81, sDim82, sDim83, sDim84, sDim85, sDim86, sDim87, sDim88, sDim89, sDim90, sDim91, sDim92, sDim93, sDim94, sDim95, sDim96, sDim97, sDim98 );\r\nElseIf( nDims = 99 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69, sDim70, sDim71, sDim72, sDim73, sDim74, sDim75, sDim76, sDim77, sDim78, sDim79, sDim80, sDim81, sDim82, sDim83, sDim84, sDim85, sDim86, sDim87, sDim88, sDim89, sDim90, sDim91, sDim92, sDim93, sDim94, sDim95, sDim96, sDim97, sDim98, sDim99 );\r\nElseIf( nDims = 100 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69, sDim70, sDim71, sDim72, sDim73, sDim74, sDim75, sDim76, sDim77, sDim78, sDim79, sDim80, sDim81, sDim82, sDim83, sDim84, sDim85, sDim86, sDim87, sDim88, sDim89, sDim90, sDim91, sDim92, sDim93, sDim94, sDim95, sDim96, sDim97, sDim98, sDim99, sDim100 );\r\nEndIf;\r\n\r\n", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.cube.create', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pCube', '', 'pDims', '',\r\n \t'pRecreate', 0, 'pDelim', '&'\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description: \r\n# This process automatically creates a cube based on a delimited string of dimension names.\r\n\r\n# Use case: Intended for development/prototyping.\r\n# 1/ This can be used to quickly create a cube for a demo or development.\r\n\r\n# Note:\r\n# The pDims parameter contains the dimenson list and is mandatory.\r\n# The format of the pDims parameter is as follows for delimiter of '&' (e.g. Dim1 & Dim2 & Dim3 ).\r\n# Spaces are ignored so use them to make your filter more readable.\r\n# The order of the dimension list specifies the initial index order of dimensions in the cube.\r\n# pRecreate is an optional parameter for creating new cubes:\r\n# - If a cube already exists and pRecreate is set to 0 then the process will abort.\r\n# - If a cube already exists and pRecreate is set to 1 then the process will destroy the old cube and recreate with the specified dimensionality.\r\n#EndRegion @DOC\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncDelimDim = TRIM(pDelim);\r\nnDims = 0;\r\nnDimMax = 100;\r\nnErrors = 0;\r\nsMessage = '';\r\ncUserName = TM1User();\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pCube:%pCube%, pDims:%pDims%, pRecreate:%pRecreate%, pDelim:%pDelim%.' ;\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pCube\": null,\r\n \"pDelim\": \"&\",\r\n \"pDims\": null,\r\n \"pLogOutput\": 0,\r\n \"pRecreate\": 0,\r\n \"pStrictErrorHandling\": 0\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pCube\": '|StringToJson ( pCube )|',\r\n \"pDelim\": '|StringToJson ( pDelim )|',\r\n \"pDims\": '|StringToJson ( pDims )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pRecreate\": '|NumberToString( pRecreate )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npCube = JsonToString( JsonGet( pJson, 'pCube' ) );\r\npDelim = JsonToString( JsonGet( pJson, 'pDelim' ) );\r\npDims = JsonToString( JsonGet( pJson, 'pDims' ) );\r\n# Numeric Parameters\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npRecreate = StringToNumber( JsonToString( JsonGet( pJson, 'pRecreate' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n## Validate the Cube parameter\r\nIf( TRIM(pCube) @= '' );\r\n sMessage = 'A cube name must be provided.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# If specified cube exists and recreate option not set to true then terminate process\r\nIf( CubeExists( pCube ) = 1 );\r\n If( pRecreate <> 1 );\r\n sMessage = Expand( 'Cube %pCube% already exists. Aborting cube create.' );\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n EndIf;\r\nEndIf;\r\n\r\n# Check the delimiter\r\nIf( cDelimDim @= '' );\r\n cDelimDim = '&';\r\nEndIf;\r\n\r\n# Check the dimension list can't be empty\r\nIf( pDims @= '' );\r\n sMessage = 'The dimension list is blank.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Check the dimension list must contain delimiter\r\nIf( Scan( cDelimDim, pDims ) < 2 );\r\n sMessage = 'The dimension list must contain at least 2 dimension names separated by the delimiter.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### Initialise the dimension variables ###\r\nsDim01 = '';\r\nsDim02 = '';\r\nsDim03 = '';\r\nsDim04 = '';\r\nsDim05 = '';\r\nsDim06 = '';\r\nsDim07 = '';\r\nsDim08 = '';\r\nsDim09 = '';\r\nsDim10 = '';\r\nsDim11 = '';\r\nsDim12 = '';\r\nsDim13 = '';\r\nsDim14 = '';\r\nsDim15 = '';\r\nsDim16 = '';\r\nsDim17 = '';\r\nsDim18 = '';\r\nsDim19 = '';\r\nsDim20 = '';\r\nsDim21 = '';\r\nsDim22 = '';\r\nsDim23 = '';\r\nsDim24 = '';\r\nsDim25 = '';\r\nsDim26 = '';\r\nsDim27 = '';\r\nsDim28 = '';\r\nsDim29 = '';\r\nsDim30 = '';\r\nsDim31 = '';\r\nsDim32 = '';\r\nsDim33 = '';\r\nsDim34 = '';\r\nsDim35 = '';\r\nsDim36 = '';\r\nsDim37 = '';\r\nsDim38 = '';\r\nsDim39 = '';\r\nsDim40 = '';\r\nsDim41 = '';\r\nsDim42 = '';\r\nsDim43 = '';\r\nsDim44 = '';\r\nsDim45 = '';\r\nsDim46 = '';\r\nsDim47 = '';\r\nsDim48 = '';\r\nsDim49 = '';\r\nsDim50 = '';\r\nsDim51 = '';\r\nsDim52 = '';\r\nsDim53 = '';\r\nsDim54 = '';\r\nsDim55 = '';\r\nsDim56 = '';\r\nsDim57 = '';\r\nsDim58 = '';\r\nsDim59 = '';\r\nsDim60 = '';\r\nsDim61 = '';\r\nsDim62 = '';\r\nsDim63 = '';\r\nsDim64 = '';\r\nsDim65 = '';\r\nsDim66 = '';\r\nsDim67 = '';\r\nsDim68 = '';\r\nsDim69 = '';\r\nsDim70 = '';\r\nsDim71 = '';\r\nsDim72 = '';\r\nsDim73 = '';\r\nsDim74 = '';\r\nsDim75 = '';\r\nsDim76 = '';\r\nsDim77 = '';\r\nsDim78 = '';\r\nsDim79 = '';\r\nsDim80 = '';\r\nsDim81 = '';\r\nsDim82 = '';\r\nsDim83 = '';\r\nsDim84 = '';\r\nsDim85 = '';\r\nsDim86 = '';\r\nsDim87 = '';\r\nsDim88 = '';\r\nsDim89 = '';\r\nsDim90 = '';\r\nsDim91 = '';\r\nsDim92 = '';\r\nsDim93 = '';\r\nsDim94 = '';\r\nsDim95 = '';\r\nsDim96 = '';\r\nsDim97 = '';\r\nsDim98 = '';\r\nsDim99 = '';\r\nsDim100 = '';\r\n\r\n### Split delimited dimension list and count number of dimensions ###\r\nsDims = TRIM( pDims );\r\nnDelimIndex = 1;\r\n\r\nWhile( nDelimIndex > 0 & Long( sDims ) > 0 );\r\n\r\n nDelimIndex = Scan( cDelimDim, sDims );\r\n If( nDelimIndex > 0 );\r\n sDim = Trim( SubSt( sDims, 1, nDelimIndex - 1 ) );\r\n sDims = Trim( SubSt( sDims, nDelimIndex + Long( cDelimDim ), Long( sDims ) ) );\r\n Else;\r\n sDim = Trim( sDims );\r\n EndIf;\r\n\r\n If( DimensionExists( sDim ) = 1 );\r\n # sDim recognized as a dimension, increment the dim counter and set the dim name variable (how we wish Expand worked on the LHS of = ...)\r\n nDims = nDims + 1;\r\n If( nDims > nDimMax );\r\n sMessage = 'Maximum number of dimensions exceeded. Aborting';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n EndIf;\r\n If( nDims = 1 );\r\n sDim01 = sDim;\r\n ElseIf( nDims = 2 );\r\n sDim02 = sDim;\r\n ElseIf( nDims = 3 );\r\n sDim03 = sDim;\r\n ElseIf( nDims = 4 );\r\n sDim04 = sDim;\r\n ElseIf( nDims = 5 );\r\n sDim05 = sDim;\r\n ElseIf( nDims = 6 );\r\n sDim06 = sDim;\r\n ElseIf( nDims = 7 );\r\n sDim07 = sDim;\r\n ElseIf( nDims = 8 );\r\n sDim08 = sDim;\r\n ElseIf( nDims = 9 );\r\n sDim09 = sDim;\r\n ElseIf( nDims = 10 );\r\n sDim10 = sDim;\r\n ElseIf( nDims = 11 );\r\n sDim11 = sDim;\r\n ElseIf( nDims = 12 );\r\n sDim12 = sDim;\r\n ElseIf( nDims = 13 );\r\n sDim13 = sDim;\r\n ElseIf( nDims = 14 );\r\n sDim14 = sDim;\r\n ElseIf( nDims = 15 );\r\n sDim15 = sDim;\r\n ElseIf( nDims = 16 );\r\n sDim16 = sDim;\r\n ElseIf( nDims = 17 );\r\n sDim17 = sDim;\r\n ElseIf( nDims = 18 );\r\n sDim18 = sDim;\r\n ElseIf( nDims = 19 );\r\n sDim19 = sDim;\r\n ElseIf( nDims = 20 );\r\n sDim20 = sDim;\r\n ElseIf( nDims = 21 );\r\n sDim21 = sDim;\r\n ElseIf( nDims = 22 );\r\n sDim22 = sDim;\r\n ElseIf( nDims = 23 );\r\n sDim23 = sDim;\r\n ElseIf( nDims = 24 );\r\n sDim24 = sDim;\r\n ElseIf( nDims = 25 );\r\n sDim25 = sDim;\r\n ElseIf( nDims = 26 );\r\n sDim26 = sDim;\r\n ElseIf( nDims = 27 );\r\n sDim27 = sDim;\r\n ElseIf( nDims = 28 );\r\n sDim28 = sDim;\r\n ElseIf( nDims = 29 );\r\n sDim29 = sDim;\r\n ElseIf( nDims = 30 );\r\n sDim30 = sDim;\r\n ElseIf( nDims = 31 );\r\n sDim31 = sDim;\r\n ElseIf( nDims = 32 );\r\n sDim32 = sDim;\r\n ElseIf( nDims = 33 );\r\n sDim33 = sDim;\r\n ElseIf( nDims = 34 );\r\n sDim34 = sDim;\r\n ElseIf( nDims = 35 );\r\n sDim35 = sDim;\r\n ElseIf( nDims = 36 );\r\n sDim36 = sDim;\r\n ElseIf( nDims = 37 );\r\n sDim37 = sDim;\r\n ElseIf( nDims = 38 );\r\n sDim38 = sDim;\r\n ElseIf( nDims = 39 );\r\n sDim39 = sDim;\r\n ElseIf( nDims = 40 );\r\n sDim40 = sDim;\r\n ElseIf( nDims = 41 );\r\n sDim41 = sDim;\r\n ElseIf( nDims = 42 );\r\n sDim42 = sDim;\r\n ElseIf( nDims = 43 );\r\n sDim43 = sDim;\r\n ElseIf( nDims = 44 );\r\n sDim44 = sDim;\r\n ElseIf( nDims = 45 );\r\n sDim45 = sDim;\r\n ElseIf( nDims = 46 );\r\n sDim46 = sDim;\r\n ElseIf( nDims = 47 );\r\n sDim47 = sDim;\r\n ElseIf( nDims = 48 );\r\n sDim48 = sDim;\r\n ElseIf( nDims = 49 );\r\n sDim49 = sDim;\r\n ElseIf( nDims = 50 );\r\n sDim50 = sDim;\r\n ElseIf( nDims = 51 );\r\n sDim51 = sDim;\r\n ElseIf( nDims = 52 );\r\n sDim52 = sDim;\r\n ElseIf( nDims = 53 );\r\n sDim53 = sDim;\r\n ElseIf( nDims = 54 );\r\n sDim54 = sDim;\r\n ElseIf( nDims = 55 );\r\n sDim55 = sDim;\r\n ElseIf( nDims = 56 );\r\n sDim56 = sDim;\r\n ElseIf( nDims = 57 );\r\n sDim57 = sDim;\r\n ElseIf( nDims = 58 );\r\n sDim58 = sDim;\r\n ElseIf( nDims = 59 );\r\n sDim59 = sDim;\r\n ElseIf( nDims = 60 );\r\n sDim60 = sDim;\r\n ElseIf( nDims = 61 );\r\n sDim61 = sDim;\r\n ElseIf( nDims = 62 );\r\n sDim62 = sDim;\r\n ElseIf( nDims = 63 );\r\n sDim63 = sDim;\r\n ElseIf( nDims = 64 );\r\n sDim64 = sDim;\r\n ElseIf( nDims = 65 );\r\n sDim65 = sDim;\r\n ElseIf( nDims = 66 );\r\n sDim66 = sDim;\r\n ElseIf( nDims = 67 );\r\n sDim67 = sDim;\r\n ElseIf( nDims = 68 );\r\n sDim68 = sDim;\r\n ElseIf( nDims = 69 );\r\n sDim69 = sDim;\r\n ElseIf( nDims = 70 );\r\n sDim70 = sDim;\r\n ElseIf( nDims = 71 );\r\n sDim71 = sDim;\r\n ElseIf( nDims = 72 );\r\n sDim72 = sDim;\r\n ElseIf( nDims = 73 );\r\n sDim73 = sDim;\r\n ElseIf( nDims = 74 );\r\n sDim74 = sDim;\r\n ElseIf( nDims = 75 );\r\n sDim75 = sDim;\r\n ElseIf( nDims = 76 );\r\n sDim76 = sDim;\r\n ElseIf( nDims = 77 );\r\n sDim77 = sDim;\r\n ElseIf( nDims = 78 );\r\n sDim78 = sDim;\r\n ElseIf( nDims = 79 );\r\n sDim79 = sDim;\r\n ElseIf( nDims = 80 );\r\n sDim80 = sDim;\r\n ElseIf( nDims = 81 );\r\n sDim81 = sDim;\r\n ElseIf( nDims = 82 );\r\n sDim82 = sDim;\r\n ElseIf( nDims = 83 );\r\n sDim83 = sDim;\r\n ElseIf( nDims = 84 );\r\n sDim84 = sDim;\r\n ElseIf( nDims = 85 );\r\n sDim85 = sDim;\r\n ElseIf( nDims = 86 );\r\n sDim86 = sDim;\r\n ElseIf( nDims = 87 );\r\n sDim87 = sDim;\r\n ElseIf( nDims = 88 );\r\n sDim88 = sDim;\r\n ElseIf( nDims = 89 );\r\n sDim89 = sDim;\r\n ElseIf( nDims = 90 );\r\n sDim90 = sDim;\r\n ElseIf( nDims = 91 );\r\n sDim91 = sDim;\r\n ElseIf( nDims = 92 );\r\n sDim92 = sDim;\r\n ElseIf( nDims = 93 );\r\n sDim93 = sDim;\r\n ElseIf( nDims = 94 );\r\n sDim94 = sDim;\r\n ElseIf( nDims = 95 );\r\n sDim95 = sDim;\r\n ElseIf( nDims = 96 );\r\n sDim96 = sDim;\r\n ElseIf( nDims = 97 );\r\n sDim97 = sDim;\r\n ElseIf( nDims = 98 );\r\n sDim98 = sDim;\r\n ElseIf( nDims = 99 );\r\n sDim99 = sDim;\r\n ElseIf( nDims = 100 );\r\n sDim100 = sDim;\r\n EndIf; \r\n\r\n Else;\r\n\r\n # sDim not recognized as valid dimension\r\n sMessage = Expand( '%sDim% not recognized as valid dimension.' );\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n EndIf;\r\n\r\nEnd;\r\n\r\n### Create the cube ###\r\n\r\nIf( nDims < 2 );\r\n sMessage = 'Number of dimesnions specified is less than 2';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\nIf( CubeExists( pCube ) = 1 & pRecreate = 1 );\r\n CubeDestroy( pCube );\r\nEndIf;\r\n\r\nIf( nDims = 2 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02 );\r\nElseIf( nDims = 3 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03 );\r\nElseIf( nDims = 4 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04 );\r\nElseIf( nDims = 5 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05 );\r\nElseIf( nDims = 6 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06 );\r\nElseIf( nDims = 7 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07 );\r\nElseIf( nDims = 8 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08 );\r\nElseIf( nDims = 9 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09 );\r\nElseIf( nDims = 10 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10 );\r\nElseIf( nDims = 11 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11 );\r\nElseIf( nDims = 12 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12 );\r\nElseIf( nDims = 13 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13 );\r\nElseIf( nDims = 14 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14 );\r\nElseIf( nDims = 15 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15 );\r\nElseIf( nDims = 16 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16 );\r\nElseIf( nDims = 17 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17 );\r\nElseIf( nDims = 18 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18 );\r\nElseIf( nDims = 19 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19 );\r\nElseIf( nDims = 20 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20 );\r\nElseIf( nDims = 21 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21 );\r\nElseIf( nDims = 22 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22 );\r\nElseIf( nDims = 23 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23 );\r\nElseIf( nDims = 24 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24 );\r\nElseIf( nDims = 25 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25 );\r\nElseIf( nDims = 26 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26 );\r\nElseIf( nDims = 27 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27 );\r\nElseIf( nDims = 28 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28 );\r\nElseIf( nDims = 29 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29 );\r\nElseIf( nDims = 30 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30 );\r\nElseIf( nDims = 31 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31 );\r\nElseIf( nDims = 32 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32 );\r\nElseIf( nDims = 33 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33 );\r\nElseIf( nDims = 34 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34 );\r\nElseIf( nDims = 35 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35 );\r\nElseIf( nDims = 36 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36 );\r\nElseIf( nDims = 37 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37 );\r\nElseIf( nDims = 38 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38 );\r\nElseIf( nDims = 39 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39 );\r\nElseIf( nDims = 40 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40 );\r\nElseIf( nDims = 41 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41 );\r\nElseIf( nDims = 42 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42 );\r\nElseIf( nDims = 43 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43 );\r\nElseIf( nDims = 44 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44 );\r\nElseIf( nDims = 45 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45 );\r\nElseIf( nDims = 46 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46 );\r\nElseIf( nDims = 47 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47 );\r\nElseIf( nDims = 48 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48 );\r\nElseIf( nDims = 49 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49 );\r\nElseIf( nDims = 50 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50 );\r\nElseIf( nDims = 51 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51 );\r\nElseIf( nDims = 52 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52 );\r\nElseIf( nDims = 53 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53 );\r\nElseIf( nDims = 54 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54 );\r\nElseIf( nDims = 55 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55 );\r\nElseIf( nDims = 56 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56 );\r\nElseIf( nDims = 57 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57 );\r\nElseIf( nDims = 58 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58 );\r\nElseIf( nDims = 59 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59 );\r\nElseIf( nDims = 60 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60 );\r\nElseIf( nDims = 61 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61 );\r\nElseIf( nDims = 62 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62 );\r\nElseIf( nDims = 63 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63 );\r\nElseIf( nDims = 64 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64 );\r\nElseIf( nDims = 65 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65 );\r\nElseIf( nDims = 66 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66 );\r\nElseIf( nDims = 67 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67 );\r\nElseIf( nDims = 68 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68 );\r\nElseIf( nDims = 69 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69 );\r\nElseIf( nDims = 70 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69, sDim70 );\r\nElseIf( nDims = 71 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69, sDim70, sDim71 );\r\nElseIf( nDims = 72 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69, sDim70, sDim71, sDim72 );\r\nElseIf( nDims = 73 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69, sDim70, sDim71, sDim72, sDim73 );\r\nElseIf( nDims = 74 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69, sDim70, sDim71, sDim72, sDim73, sDim74 );\r\nElseIf( nDims = 75 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69, sDim70, sDim71, sDim72, sDim73, sDim74, sDim75 );\r\nElseIf( nDims = 76 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69, sDim70, sDim71, sDim72, sDim73, sDim74, sDim75, sDim76 );\r\nElseIf( nDims = 77 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69, sDim70, sDim71, sDim72, sDim73, sDim74, sDim75, sDim76, sDim77 );\r\nElseIf( nDims = 78 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69, sDim70, sDim71, sDim72, sDim73, sDim74, sDim75, sDim76, sDim77, sDim78 );\r\nElseIf( nDims = 79 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69, sDim70, sDim71, sDim72, sDim73, sDim74, sDim75, sDim76, sDim77, sDim78, sDim79 );\r\nElseIf( nDims = 80 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69, sDim70, sDim71, sDim72, sDim73, sDim74, sDim75, sDim76, sDim77, sDim78, sDim79, sDim80 );\r\nElseIf( nDims = 81 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69, sDim70, sDim71, sDim72, sDim73, sDim74, sDim75, sDim76, sDim77, sDim78, sDim79, sDim80, sDim81 );\r\nElseIf( nDims = 82 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69, sDim70, sDim71, sDim72, sDim73, sDim74, sDim75, sDim76, sDim77, sDim78, sDim79, sDim80, sDim81, sDim82 );\r\nElseIf( nDims = 83 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69, sDim70, sDim71, sDim72, sDim73, sDim74, sDim75, sDim76, sDim77, sDim78, sDim79, sDim80, sDim81, sDim82, sDim83 );\r\nElseIf( nDims = 84 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69, sDim70, sDim71, sDim72, sDim73, sDim74, sDim75, sDim76, sDim77, sDim78, sDim79, sDim80, sDim81, sDim82, sDim83, sDim84 );\r\nElseIf( nDims = 85 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69, sDim70, sDim71, sDim72, sDim73, sDim74, sDim75, sDim76, sDim77, sDim78, sDim79, sDim80, sDim81, sDim82, sDim83, sDim84, sDim85 );\r\nElseIf( nDims = 86 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69, sDim70, sDim71, sDim72, sDim73, sDim74, sDim75, sDim76, sDim77, sDim78, sDim79, sDim80, sDim81, sDim82, sDim83, sDim84, sDim85, sDim86 );\r\nElseIf( nDims = 87 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69, sDim70, sDim71, sDim72, sDim73, sDim74, sDim75, sDim76, sDim77, sDim78, sDim79, sDim80, sDim81, sDim82, sDim83, sDim84, sDim85, sDim86, sDim87 );\r\nElseIf( nDims = 88 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69, sDim70, sDim71, sDim72, sDim73, sDim74, sDim75, sDim76, sDim77, sDim78, sDim79, sDim80, sDim81, sDim82, sDim83, sDim84, sDim85, sDim86, sDim87, sDim88 );\r\nElseIf( nDims = 89 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69, sDim70, sDim71, sDim72, sDim73, sDim74, sDim75, sDim76, sDim77, sDim78, sDim79, sDim80, sDim81, sDim82, sDim83, sDim84, sDim85, sDim86, sDim87, sDim88, sDim89 );\r\nElseIf( nDims = 90 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69, sDim70, sDim71, sDim72, sDim73, sDim74, sDim75, sDim76, sDim77, sDim78, sDim79, sDim80, sDim81, sDim82, sDim83, sDim84, sDim85, sDim86, sDim87, sDim88, sDim89, sDim90 );\r\nElseIf( nDims = 91 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69, sDim70, sDim71, sDim72, sDim73, sDim74, sDim75, sDim76, sDim77, sDim78, sDim79, sDim80, sDim81, sDim82, sDim83, sDim84, sDim85, sDim86, sDim87, sDim88, sDim89, sDim90, sDim91 );\r\nElseIf( nDims = 92 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69, sDim70, sDim71, sDim72, sDim73, sDim74, sDim75, sDim76, sDim77, sDim78, sDim79, sDim80, sDim81, sDim82, sDim83, sDim84, sDim85, sDim86, sDim87, sDim88, sDim89, sDim90, sDim91, sDim92 );\r\nElseIf( nDims = 93 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69, sDim70, sDim71, sDim72, sDim73, sDim74, sDim75, sDim76, sDim77, sDim78, sDim79, sDim80, sDim81, sDim82, sDim83, sDim84, sDim85, sDim86, sDim87, sDim88, sDim89, sDim90, sDim91, sDim92, sDim93 );\r\nElseIf( nDims = 94 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69, sDim70, sDim71, sDim72, sDim73, sDim74, sDim75, sDim76, sDim77, sDim78, sDim79, sDim80, sDim81, sDim82, sDim83, sDim84, sDim85, sDim86, sDim87, sDim88, sDim89, sDim90, sDim91, sDim92, sDim93, sDim94 );\r\nElseIf( nDims = 95 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69, sDim70, sDim71, sDim72, sDim73, sDim74, sDim75, sDim76, sDim77, sDim78, sDim79, sDim80, sDim81, sDim82, sDim83, sDim84, sDim85, sDim86, sDim87, sDim88, sDim89, sDim90, sDim91, sDim92, sDim93, sDim94, sDim95 );\r\nElseIf( nDims = 96 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69, sDim70, sDim71, sDim72, sDim73, sDim74, sDim75, sDim76, sDim77, sDim78, sDim79, sDim80, sDim81, sDim82, sDim83, sDim84, sDim85, sDim86, sDim87, sDim88, sDim89, sDim90, sDim91, sDim92, sDim93, sDim94, sDim95, sDim96 );\r\nElseIf( nDims = 97 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69, sDim70, sDim71, sDim72, sDim73, sDim74, sDim75, sDim76, sDim77, sDim78, sDim79, sDim80, sDim81, sDim82, sDim83, sDim84, sDim85, sDim86, sDim87, sDim88, sDim89, sDim90, sDim91, sDim92, sDim93, sDim94, sDim95, sDim96, sDim97 );\r\nElseIf( nDims = 98 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69, sDim70, sDim71, sDim72, sDim73, sDim74, sDim75, sDim76, sDim77, sDim78, sDim79, sDim80, sDim81, sDim82, sDim83, sDim84, sDim85, sDim86, sDim87, sDim88, sDim89, sDim90, sDim91, sDim92, sDim93, sDim94, sDim95, sDim96, sDim97, sDim98 );\r\nElseIf( nDims = 99 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69, sDim70, sDim71, sDim72, sDim73, sDim74, sDim75, sDim76, sDim77, sDim78, sDim79, sDim80, sDim81, sDim82, sDim83, sDim84, sDim85, sDim86, sDim87, sDim88, sDim89, sDim90, sDim91, sDim92, sDim93, sDim94, sDim95, sDim96, sDim97, sDim98, sDim99 );\r\nElseIf( nDims = 100 );\r\n CubeCreate( Trim( pCube ), sDim01, sDim02, sDim03, sDim04, sDim05, sDim06, sDim07, sDim08, sDim09, sDim10, sDim11, sDim12, sDim13, sDim14, sDim15, sDim16, sDim17, sDim18, sDim19, sDim20, sDim21, sDim22, sDim23, sDim24, sDim25, sDim26, sDim27, sDim28, sDim29, sDim30, sDim31, sDim32, sDim33, sDim34, sDim35, sDim36, sDim37, sDim38, sDim39, sDim40, sDim41, sDim42, sDim43, sDim44, sDim45, sDim46, sDim47, sDim48, sDim49, sDim50, sDim51, sDim52, sDim53, sDim54, sDim55, sDim56, sDim57, sDim58, sDim59, sDim60, sDim61, sDim62, sDim63, sDim64, sDim65, sDim66, sDim67, sDim68, sDim69, sDim70, sDim71, sDim72, sDim73, sDim74, sDim75, sDim76, sDim77, sDim78, sDim79, sDim80, sDim81, sDim82, sDim83, sDim84, sDim85, sDim86, sDim87, sDim88, sDim89, sDim90, sDim91, sDim92, sDim93, sDim94, sDim95, sDim96, sDim97, sDim98, sDim99, sDim100 );\r\nEndIf;\r\n\r\n", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully created %pCube% with %pDims%.' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogOutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction) );\r\n EndIf;\r\nEndIf;\r\n\r\n### End Epilog ###\r\n\r\n\r\n\r\n\r\n", @@ -10,41 +10,47 @@ "Type": "None" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pCube", - "Prompt": "REQUIRED: Cube Name", + "Prompt": "REQUIRED: Cube name", "Value": "", "Type": "String" }, { "Name": "pDims", - "Prompt": "REQUIRED: Dim1 & Dim2 & Dim3 & Dim4 & Dim5", + "Prompt": "REQUIRED: Delimited dimension list. E.g. dim_one & dim_two & dim_three & dim_four & dim_five", "Value": "", "Type": "String" }, { "Name": "pRecreate", - "Prompt": "OPTIONAL: If cube exists delete and recreate (Default=0)", + "Prompt": "OPTIONAL: If target objects exists, delete and recreate (Default = 0)", "Value": 0, "Type": "Numeric" }, { "Name": "pDelim", - "Prompt": "OPTIONAL: Delimiter for Dimension list (default value if blank = '&')", + "Prompt": "OPTIONAL: Delimiter for list parameters (Default = '&')", "Value": "&", "Type": "String" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [], diff --git a/bedrock_processes_json/}bedrock.cube.data.clear.json b/bedrock_processes_json/}bedrock.cube.data.clear.json index 2923f11..8fb1ac9 100644 --- a/bedrock_processes_json/}bedrock.cube.data.clear.json +++ b/bedrock_processes_json/}bedrock.cube.data.clear.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.cube.data.clear", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.cube.data.clear', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pCube', '', 'pView', '', 'pFilter', '',\r\n \t'pFilterParallel', '', 'pParallelThreads', 0,\r\n \t'pDimDelim', '&', 'pEleStartDelim', '\u00a6', 'pEleDelim', '+', 'pSuppressConsolStrings', 0, \r\n \t'pCubeLogging', 0, 'pTemp', 1, 'pSandbox', pSandbox, 'pSubN', 0\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process could be used extensively by custom TIs in production to clear certain data out of a cube before copying data to that cube.\r\n\r\n# Use case: Primarily for production systems.\r\n# 1/ In production system this is a \"workhorse\" process called from the prolog of most custom processes prior to querying a data source to refresh cube data.\r\n# 2/ During development/prototyping can be run manually to clear out a portion of a cube.\r\n\r\n# Note:\r\n# Wildcards can be used or a list of cubes specified to clear data out of multiple cubes simultaneouly. \r\n# If no cube (pCube) or an invalid cube is specified, the process will abort.\r\n# CAUTION: If no view (pView) or filter (pFilter) is specified, the entire cube(s) will be cleared out.\r\n# If a valid view is specified the process will simply zero out that view and ignore any filter (pFilter) specified.\r\n# If no valid view is specified then a temporary view will be built using the filter and its data deleted.\r\n# The filter can handle specific element references for any number of dimensions and elements.\r\n# - The pFilter parameter contains the dimension and elements to be used for filtering.\r\n# - The dimension parameters do not need to be given in the index order of dimensions in the cube.\r\n# - The dimension name is specified as the first member of the delimited string of elements.\r\n# If using the pFilterParallel parameter the **single dimension** used as the \"parallelization slicer\" cannot appear in\r\n# the pFilter parameters.\r\n# When using parallelization via the *RunProcess* function the elements listed in pFilterParallel will be split one_at_a_time\r\n# and passed to a recursive call of the process being added to pFilter.\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent= 'Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pCube:%pCube%, pView:%pView%, pFilter:%pFilter%, pFilterParallel:%pFilterParallel%, pParallelThreads:%pParallelThreads%, pDimDelim:%pDimDelim%, pEleStartDelim:%pEleStartDelim%, pEleDelim:%pEleDelim%, pSuppressConsolStrings:%pSuppressConsolStrings%, pCubeLogging:%pCubeLogging%, pTemp:%pTemp%, pSandbox:%pSandbox%'; \r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncDefaultView = Expand( '%cThisProcName%_%cTimeStamp%_%cRandomInt%' );\r\ncTempSub = cDefaultView | '_Temp';\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n# Trim delimiters\r\nsDelimDim = TRIM(pDimDelim);\r\nsElementStartDelim = TRIM(pEleStartDelim);\r\nsDelimElem = TRIM(pEleDelim);\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\n## Default filter delimiters\r\nIf( pDimDelim @= '' );\r\n pDimDelim = '&';\r\nEndIf;\r\nIf( pEleStartDelim@= '' );\r\n pEleStartDelim= '\u00a6';\r\nEndIf;\r\nIf( pEleDelim @= '' );\r\n pEleDelim = '+';\r\nEndIf;\r\n\r\n# Check the delimiters\r\nIf( Trim( pFilter ) @<> '' );\r\n If( sDelimDim @= sElementStartDelim % sDelimDim @= sDelimElem % sElementStartDelim @= sDelimElem );\r\n sMessage = 'The delimiters cannot be the same.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n EndIf;\r\nEndIf; \r\n\r\n# consolidated strings\r\nIf( pSuppressConsolStrings <> 0 );\r\n pSuppressConsolStrings = 1;\r\nEndIf;\r\n\r\n# Validate cubelogging parameter\r\nIf( pCubeLogging <> 0 & pCubeLogging <> 1 & pCubeLogging <> 2);\r\n sMessage = 'The cube logging parameter incorrect';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# If no cube has been specified then terminate process\r\nIf( Trim( pCube ) @= '' );\r\n sMessage = 'No cube(s) specified.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate parallelization filter\r\nIf( Scan( pEleStartDelim, pFilterParallel ) > 0 );\r\n sDimParallel = SubSt( pFilterParallel, 1, Scan( pEleStartDelim, pFilterParallel ) - 1 );\r\n If( Scan( Lower(sDimParallel) | pEleStartDelim, Lower(pFilter) ) > 0 );\r\n sMessage = 'Parallelization dimension %sDimParallel% cannot exist in filter.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n EndIf;\r\nEndIf;\r\n\r\n# Validate Max Threads\r\nIf( pParallelThreads >= 1 );\r\n nMaxThreads = Round(pParallelThreads);\r\nElse;\r\n # Single thread mode\r\n nMaxThreads = 1;\r\nEndIf;\r\n\r\n# Validate Sandbox\r\nIf( TRIM( pSandbox ) @<> '' );\r\n If( ServerSandboxExists( pSandbox ) = 0 );\r\n SetUseActiveSandboxProperty( 0 );\r\n nErrors = nErrors + 1;\r\n sMessage = Expand('Sandbox %pSandbox% is invalid for the current user.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n Else;\r\n ServerActiveSandboxSet( pSandbox );\r\n SetUseActiveSandboxProperty( 1 );\r\n EndIf;\r\nElse;\r\n SetUseActiveSandboxProperty( 0 );\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n# Loop through cubes in pCube\r\nsCubes = pCube;\r\nnCubeDelimiterIndex = 1;\r\n# Get 1st cube\r\nWhile( nCubeDelimiterIndex <> 0 );\r\n\r\n # Extract 1st cube > sCube\r\n nCubeDelimiterIndex = Scan( pDimDelim, sCubes );\r\n If( nCubeDelimiterIndex = 0 );\r\n sCube = sCubes;\r\n Else;\r\n sCube = Trim( SubSt( sCubes, 1, nCubeDelimiterIndex - 1 ) );\r\n sCubes = Trim( Subst( sCubes, nCubeDelimiterIndex + Long(pDimDelim), Long( sCubes ) ) );\r\n EndIf;\r\n \r\n bParallel = 0;\r\n \r\n # Check if sCube has wildcard\r\n If( Scan( '*', sCube ) = 0);\r\n # Validate cube\r\n If( CubeExists(sCube) = 0 );\r\n nErrors = 1;\r\n sMessage = Expand( 'Cube %sCube% does not exist.' );\r\n LogOutput( 'ERROR', Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n Else;\r\n If( Scan( pEleStartDelim, pFilterParallel ) > 0 );\r\n nDim = 1;\r\n sDim = TABDIM( sCube, nDim);\r\n While ( sDim @<> '' );\r\n sDim = TABDIM( sCube, nDim);\r\n If ( sDim @= sDimParallel );\r\n bParallel = 1;\r\n sDim = '';\r\n EndIf;\r\n nDim = nDim + 1;\r\n End;\r\n EndIf;\r\n If( bParallel = 1 );\r\n sDimParallel = SubSt( pFilterParallel, 1, Scan( pEleStartDelim, pFilterParallel ) - 1 );\r\n sElementList = SubSt( pFilterParallel, Scan( pEleStartDelim, pFilterParallel ) + 1, Long( pFilterParallel ) );\r\n If( SubSt( sElementList, Long( sElementList ), 1 ) @<> pEleDelim );\r\n sElementList = sElementList | pEleDelim;\r\n EndIf;\r\n ## Counting elements in element list\r\n sElementListCount = sElementList;\r\n nElements = 0;\r\n While( Scan( pEleDelim, sElementListCount ) > 0 );\r\n nElements = nElements + 1;\r\n sElementListCount = SubSt( sElementListCount, Scan( pEleDelim, sElementListCount ) + 1, Long( sElementListCount ) );\r\n End;\r\n IF( Mod( nElements, nMaxThreads ) = 0 );\r\n nElemsPerThread = INT( nElements / nMaxThreads );\r\n ELSE;\r\n nElemsPerThread = INT( nElements / nMaxThreads ) + 1;\r\n ENDIF;\r\n nThreadElCounter = 0;\r\n While( Scan( pEleDelim, sElementList ) > 0 );\r\n sSlicerEle = SubSt( sElementList, 1, Scan( pEleDelim, sElementList ) - 1 );\r\n sElementList = SubSt( sElementList, Scan( pEleDelim, sElementList ) + 1, Long( sElementList ) );\r\n # Do recursive process call with new RunProcess function\r\n nThreadElCounter = nThreadElCounter + 1;\r\n sDimDelim = If(pFilter @= '', '', pDimDelim );\r\n IF( nThreadElCounter = 1 );\r\n sFilter = Expand('%pFilter%%sDimDelim%%sDimParallel%%pEleStartDelim%%sSlicerEle%');\r\n ELSE;\r\n sFilter = Expand('%sFilter%%pEleDelim%%sSlicerEle%');\r\n ENDIF;\r\n IF( nThreadElCounter >= nElemsPerThread );\r\n RunProcess( cThisProcName, 'pLogoutput', pLogoutput,\r\n \t 'pCube', pCube, 'pView', pView, 'pFilter', sFilter, 'pFilterParallel', '', \r\n \t 'pDimDelim', pDimDelim, 'pEleStartDelim', pEleStartDelim, 'pEleDelim', pEleDelim, \r\n \t 'pSuppressConsolStrings', pSuppressConsolStrings, 'pCubeLogging', pCubeLogging, 'pTemp', pTemp, 'pSandbox', pSandbox\r\n \t );\r\n \t nThreadElCounter = 0;\r\n \t sFilter = '';\r\n \t ENDIF;\r\n End;\r\n ## Process last elements - only when filter is not empty (there are still elements) otherwise the entire cube is emptied\r\n IF( sFilter @<> '' );\r\n RunProcess( cThisProcName, 'pLogoutput', pLogoutput,\r\n \t 'pCube', pCube, 'pView', pView, 'pFilter', sFilter, 'pFilterParallel', '', \r\n \t 'pDimDelim', pDimDelim, 'pEleStartDelim', pEleStartDelim, 'pEleDelim', pEleDelim, \r\n \t 'pSuppressConsolStrings', pSuppressConsolStrings, 'pCubeLogging', pCubeLogging, 'pTemp', pTemp, 'pSandbox', pSandbox\r\n \t );\r\n \t ENDIF;\r\n Else;\r\n ## Validate the View & filter parameter\r\n If( Trim( pView ) @= '' & Trim( pFilter ) @= '' & Trim( pSandbox ) @= '' );\r\n sMessage = Expand('No view OR filter specified so the entire %sCube% cube has been cleared.');\r\n\t IF( pLogoutput = 1 );\r\n \tLogOutput( 'INFO' , Expand( 'Process:%cThisProcName% Message:%sMessage%' ) );\r\n\t ENDIF;\r\n CubeClearData( sCube );\r\n Else;\r\n # Use different view/subset for different cubes\r\n sTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\n sRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\n cDefaultView = Expand( '%cThisProcName%_%sTimeStamp%_%sRandomInt%' );\r\n #cTempSub = cDefaultView;\r\n \r\n If( Trim( pView ) @= '' );\r\n cView = cDefaultView ;\r\n Else;\r\n cView = Trim( pView );\r\n EndIf;\r\n \r\n # Clear view\r\n If( ViewExists( sCube , cView ) = 0 );\r\n ## Validate that a Filter has been provided so that a view can be created.\r\n If( Trim( pFilter ) @= '' );\r\n sMessage = Expand('View %cView% does not exist in the %sCube% cube AND no Filter has not been specified in order to create a view.');\r\n LogOutput( 'INFO' , Expand( cMsgErrorContent ) );\r\n #ProcessBreak;\r\n EndIf;\r\n\r\n ### Create View using filter (temp view, therefore no need to destroy) ###\r\n sProc = '}bedrock.cube.view.create';\r\n nRet = ExecuteProcess( sProc,\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pCube', sCube, 'pView', cView, 'pFilter', pFilter,\r\n 'pSuppressZero', 1, 'pSuppressConsol', 1, 'pSuppressRules', 1, 'pSuppressConsolStrings', pSuppressConsolStrings,\r\n 'pDimDelim', pDimDelim, 'pEleStartDelim', pEleStartDelim, 'pEleDelim', pEleDelim,\r\n 'pTemp', pTemp, 'pSubN', pSubN\r\n );\r\n\r\n # Validate Sandbox\r\n If( TRIM( pSandbox ) @<> '' );\r\n If( ServerSandboxExists( pSandbox ) = 0 );\r\n SetUseActiveSandboxProperty( 0 );\r\n nErrors = nErrors + 1;\r\n sMessage = Expand('Sandbox %pSandbox% is invalid for the current user.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n Else;\r\n ServerActiveSandboxSet( pSandbox );\r\n SetUseActiveSandboxProperty( 1 );\r\n EndIf;\r\n Else;\r\n SetUseActiveSandboxProperty( 0 );\r\n EndIf;\r\n\r\n ### Zero Out View ###\r\n If ( nRet = ProcessExitNormal() );\r\n ViewZeroOut( sCube, cView );\r\n sMessage = Expand( 'Succeeded in creating the %cView% view in the %sCube% cube and data has been cleared.' );\r\n \t If( pLogoutput = 1 );\r\n \tLogOutput( 'INFO', Expand( 'Process:%cThisProcName% Message:%sMessage%' ) );\r\n \t EndIf;\r\n Else;\r\n nErrors = nErrors + 1;\r\n sMessage = Expand( 'Creating view by %sProc% has failed. Nothing has been cleared in the %sCube% cube.' );\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n EndIf;\r\n Else;\r\n ViewZeroOut( sCube, cView );\r\n Endif;\r\n Endif;\r\n EndIf;\r\n Endif;\r\n Else;\r\n # Create subset of cubes using Wildcard to loop through cubes in pCube with wildcard\r\n sCubeExp = '\"'|sCube|'\"';\r\n sMdx = '{TM1FILTERBYPATTERN( {TM1SUBSETALL( [}Cubes] )},'|sCubeExp| ')}';\r\n If( SubsetExists( '}Cubes' , cTempSub ) = 1 );\r\n # If a delimited list of cube names includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( '}Cubes' , cTempSub, sMDX );\r\n Else;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSub, sMDX, '}Cubes' , 1 );\r\n EndIf;\r\n \r\n # Loop through cubes in subset created based on wildcard\r\n nCountCube = SubsetGetSize( '}Cubes' , cTempSub );\r\n While( nCountCube >= 1 );\r\n # Use different view/subset for different cubes\r\n sTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\n sRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\n cDefaultView = Expand( '%cThisProcName%_%sTimeStamp%_%sRandomInt%' );\r\n sCube = SubsetGetElementName( '}Cubes' , cTempSub, nCountCube );\r\n # Validate cube name Not necessary as derived from subset of }Cubes\r\n If( CubeExists(sCube) = 0 );\r\n nErrors = 1;\r\n sMessage = Expand( '%sCube% does not exist.' );\r\n LogOutput( 'ERROR', Expand( cMsgErrorContent ) );\r\n Else;\r\n If( Scan( pEleStartDelim, pFilterParallel ) > 0 );\r\n nDim = 1;\r\n sDim = TABDIM( sCube, nDim);\r\n While ( sDim @<> '' );\r\n sDim = TABDIM( sCube, nDim);\r\n If ( sDim @= sDimParallel );\r\n bParallel = 1;\r\n sDim = '';\r\n EndIf;\r\n nDim = nDim + 1;\r\n End;\r\n EndIf;\r\n If( bParallel = 1 );\r\n sDimParallel = SubSt( pFilterParallel, 1, Scan( pEleStartDelim, pFilterParallel ) - 1 );\r\n sElementList = SubSt( pFilterParallel, Scan( pEleStartDelim, pFilterParallel ) + 1, Long( pFilterParallel ) );\r\n If( SubSt( sElementList, Long( sElementList ), 1 ) @<> pEleDelim );\r\n sElementList = sElementList | pEleDelim;\r\n EndIf;\r\n ## Counting elements in element list\r\n sElementListCount = sElementList;\r\n nElements = 0;\r\n While( Scan( pEleDelim, sElementListCount ) > 0 );\r\n nElements = nElements + 1;\r\n sElementListCount = SubSt( sElementListCount, Scan( pEleDelim, sElementListCount ) + 1, Long( sElementListCount ) );\r\n End;\r\n IF( Mod( nElements, nMaxThreads ) = 0 );\r\n nElemsPerThread = INT( nElements / nMaxThreads );\r\n ELSE;\r\n nElemsPerThread = INT( nElements / nMaxThreads ) + 1;\r\n ENDIF;\r\n nThreadElCounter = 0;\r\n While( Scan( pEleDelim, sElementList ) > 0 );\r\n sSlicerEle = SubSt( sElementList, 1, Scan( pEleDelim, sElementList ) - 1 );\r\n sElementList = SubSt( sElementList, Scan( pEleDelim, sElementList ) + 1, Long( sElementList ) );\r\n # Do recursive process call with new RunProcess function\r\n nThreadElCounter = nThreadElCounter + 1;\r\n sDimDelim = If(pFilter @= '', '', pDimDelim );\r\n IF( nThreadElCounter = 1 );\r\n sFilter = Expand('%pFilter%%sDimDelim%%sDimParallel%%pEleStartDelim%%sSlicerEle%');\r\n ELSE;\r\n sFilter = Expand('%sFilter%%pEleDelim%%sSlicerEle%');\r\n ENDIF;\r\n IF( nThreadElCounter >= nElemsPerThread );\r\n RunProcess( cThisProcName, 'pLogoutput', pLogoutput,\r\n \t 'pCube', pCube, 'pView', pView, 'pFilter', sFilter, 'pFilterParallel', '', \r\n \t 'pDimDelim', pDimDelim, 'pEleStartDelim', pEleStartDelim, 'pEleDelim', pEleDelim, \r\n \t 'pSuppressConsolStrings', pSuppressConsolStrings, 'pCubeLogging', pCubeLogging, 'pTemp', pTemp, 'pSandbox', pSandbox\r\n \t );\r\n \t nThreadElCounter = 0;\r\n \t sFilter = '';\r\n \t ENDIF;\r\n End;\r\n ## Process last elements\r\n IF( sFilter @<> '' );\r\n RunProcess( cThisProcName, 'pLogoutput', pLogoutput,\r\n \t 'pCube', pCube, 'pView', pView, 'pFilter', sFilter, 'pFilterParallel', '', \r\n \t 'pDimDelim', pDimDelim, 'pEleStartDelim', pEleStartDelim, 'pEleDelim', pEleDelim, \r\n \t 'pSuppressConsolStrings', pSuppressConsolStrings, 'pCubeLogging', pCubeLogging, 'pTemp', pTemp, 'pSandbox', pSandbox\r\n \t );\r\n \t ENDIF;\r\n Else;\r\n ## Validate the View & filter parameter\r\n If( Trim( pView ) @= '' & Trim( pFilter ) @= '' & Trim( pSandbox ) @= '' );\r\n # Clear entire cube\r\n sMessage = Expand('No view OR filter specified so the entire %sCube% cube has been cleared.');\r\n\t IF( pLogoutput = 1 );\r\n \tLogOutput( 'INFO' , Expand( 'Process:%cThisProcName% Message:%sMessage%' ) );\r\n\t ENDIF;\r\n CubeClearData( sCube );\r\n Else;\r\n # Clear view cView\r\n If( Trim( pView ) @= '' );\r\n cView = cDefaultView ;\r\n Else;\r\n cView = Trim( pView );\r\n EndIf;\r\n \r\n If( ViewExists( sCube, cView ) = 0 );\r\n ## Validate that a Filter has been provided so that a view can be created.\r\n If( Trim( pFilter ) @= '' );\r\n sMessage = Expand('View %cView% does not exist for %sCube% AND no Filter has not been specified in order to create a view.');\r\n LogOutput( 'ERROR' , Expand( cMsgErrorContent ) );\r\n #ProcessBreak;\r\n EndIf;\r\n \r\n ### Create View using filter (temp view, therefore no need to destroy) ###\r\n sProc = '}bedrock.cube.view.create';\r\n nRet = ExecuteProcess( sProc,\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pCube', sCube, 'pView', cView, 'pFilter', pFilter,\r\n 'pSuppressZero', 1, 'pSuppressConsol', 1, 'pSuppressRules', 1, 'pSuppressConsolStrings', pSuppressConsolStrings,\r\n 'pDimDelim', pDimDelim, 'pEleStartDelim', pEleStartDelim, 'pEleDelim', pEleDelim,\r\n 'pTemp', pTemp, 'pSubN', pSubN\r\n );\r\n \r\n # Validate Sandbox\r\n If( TRIM( pSandbox ) @<> '' );\r\n If( ServerSandboxExists( pSandbox ) = 0 );\r\n SetUseActiveSandboxProperty( 0 );\r\n nErrors = nErrors + 1;\r\n sMessage = Expand('Sandbox %pSandbox% is invalid for the current user.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n Else;\r\n ServerActiveSandboxSet( pSandbox );\r\n SetUseActiveSandboxProperty( 1 );\r\n EndIf;\r\n Else;\r\n SetUseActiveSandboxProperty( 0 );\r\n EndIf;\r\n \r\n \r\n ### Zero Out View ###\r\n IF ( nRet = ProcessExitNormal() );\r\n ViewZeroOut( sCube, cView );\r\n sMessage = Expand( 'Succeeded in creating the %cView% view in the %sCube% cube and data has been cleared.' );\r\n \t\tIF( pLogoutput = 1 );\r\n LogOutput( 'INFO', Expand( 'Process:%cThisProcName% Message:%sMessage%' ) );\r\n \t\tENDIF;\r\n ELSE;\r\n nErrors = nErrors + 1;\r\n sMessage = Expand( 'Creating view by %sProc% has failed. Nothing has been cleared in the %sCube% cube.' );\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n ENDIF;\r\n Else;\r\n ViewZeroOut( sCube, cView );\r\n Endif;\r\n EndIf;\r\n EndIf;\r\n nCountCube = nCountCube - 1;\r\n # Use different view/subset for different cubes\r\n sTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\n sRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\n cDefaultView = Expand( '%cThisProcName%_%sTimeStamp%_%sRandomInt%' );\r\n #cTempSub = cDefaultView; \r\n EndIf;\r\n End;\r\n EndIf;\r\nEnd;\r\n\r\n### End Prolog ###", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.cube.data.clear', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pCube', '', 'pView', '', 'pFilter', '',\r\n \t'pFilterParallel', '', 'pParallelThreads', 0,\r\n \t'pDimDelim', '&', 'pEleStartDelim', '\u00a6', 'pEleDelim', '+', 'pSuppressConsolStrings', 0, \r\n \t'pCubeLogging', 0, 'pTemp', 1, 'pSandbox', pSandbox, 'pSubN', 0\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process could be used extensively by custom TIs in production to clear certain data out of a cube before copying data to that cube.\r\n\r\n# Use case: Primarily for production systems.\r\n# 1/ In production system this is a \"workhorse\" process called from the prolog of most custom processes prior to querying a data source to refresh cube data.\r\n# 2/ During development/prototyping can be run manually to clear out a portion of a cube.\r\n\r\n# Note:\r\n# Wildcards can be used or a list of cubes specified to clear data out of multiple cubes simultaneouly. \r\n# If no cube (pCube) or an invalid cube is specified, the process will abort.\r\n# CAUTION: If no view (pView) or filter (pFilter) is specified, the entire cube(s) will be cleared out.\r\n# If a valid view is specified the process will simply zero out that view and ignore any filter (pFilter) specified.\r\n# If no valid view is specified then a temporary view will be built using the filter and its data deleted.\r\n# The filter can handle specific element references for any number of dimensions and elements.\r\n# - The pFilter parameter contains the dimension and elements to be used for filtering.\r\n# - The dimension parameters do not need to be given in the index order of dimensions in the cube.\r\n# - The dimension name is specified as the first member of the delimited string of elements.\r\n# If using the pFilterParallel parameter the **single dimension** used as the \"parallelization slicer\" cannot appear in\r\n# the pFilter parameters.\r\n# When using parallelization via the *RunProcess* function the elements listed in pFilterParallel will be split one_at_a_time\r\n# and passed to a recursive call of the process being added to pFilter.\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent= 'Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pCube:%pCube%, pView:%pView%, pFilter:%pFilter%, pFilterParallel:%pFilterParallel%, pParallelThreads:%pParallelThreads%, pDimDelim:%pDimDelim%, pEleStartDelim:%pEleStartDelim%, pEleDelim:%pEleDelim%, pSuppressConsolStrings:%pSuppressConsolStrings%, pCubeLogging:%pCubeLogging%, pTemp:%pTemp%, pSandbox:%pSandbox%'; \r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncDefaultView = Expand( '%cThisProcName%_%cTimeStamp%_%cRandomInt%' );\r\ncTempSub = cDefaultView | '_Temp';\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pCube\": null,\r\n \"pDimDelim\": \"&\",\r\n \"pEleDelim\": \"+\",\r\n \"pEleStartDelim\": \"\u00a6\",\r\n \"pFilter\": \"\",\r\n \"pFilterParallel\": \"\",\r\n \"pSandbox\": \"\",\r\n \"pView\": \"\",\r\n \"pLogOutput\": 0,\r\n \"pParallelThreads\": 0,\r\n \"pStrictErrorHandling\": 0,\r\n \"pSubN\": 0,\r\n \"pSuppressConsolStrings\": 1,\r\n \"pTemp\": 1\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pCube\": '|StringToJson ( pCube )|',\r\n \"pDimDelim\": '|StringToJson ( pDimDelim )|',\r\n \"pEleDelim\": '|StringToJson ( pEleDelim )|',\r\n \"pEleStartDelim\": '|StringToJson ( pEleStartDelim )|',\r\n \"pFilter\": '|StringToJson ( pFilter )|',\r\n \"pFilterParallel\": '|StringToJson ( pFilterParallel )|',\r\n \"pSandbox\": '|StringToJson ( pSandbox )|',\r\n \"pView\": '|StringToJson ( pView )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pParallelThreads\": '|NumberToString( pParallelThreads )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|',\r\n \"pSubN\": '|NumberToString( pSubN )|',\r\n \"pSuppressConsolStrings\": '|NumberToString( pSuppressConsolStrings )|',\r\n \"pTemp\": '|NumberToString( pTemp )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npCube = JsonToString( JsonGet( pJson, 'pCube' ) );\r\npDimDelim = JsonToString( JsonGet( pJson, 'pDimDelim' ) );\r\npEleDelim = JsonToString( JsonGet( pJson, 'pEleDelim' ) );\r\npEleStartDelim = JsonToString( JsonGet( pJson, 'pEleStartDelim' ) );\r\npFilter = JsonToString( JsonGet( pJson, 'pFilter' ) );\r\npFilterParallel = JsonToString( JsonGet( pJson, 'pFilterParallel' ) );\r\npSandbox = JsonToString( JsonGet( pJson, 'pSandbox' ) );\r\npView = JsonToString( JsonGet( pJson, 'pView' ) );\r\n# Numeric Parameters\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npParallelThreads = StringToNumber( JsonToString( JsonGet( pJson, 'pParallelThreads' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\npSubN = StringToNumber( JsonToString( JsonGet( pJson, 'pSubN' ) ) );\r\npSuppressConsolStrings = StringToNumber( JsonToString( JsonGet( pJson, 'pSuppressConsolStrings' ) ) );\r\npTemp = StringToNumber( JsonToString( JsonGet( pJson, 'pTemp' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n# Trim delimiters\r\nsDelimDim = TRIM(pDimDelim);\r\nsElementStartDelim = TRIM(pEleStartDelim);\r\nsDelimElem = TRIM(pEleDelim);\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\n## Default filter delimiters\r\nIf( pDimDelim @= '' );\r\n pDimDelim = '&';\r\nEndIf;\r\nIf( pEleStartDelim@= '' );\r\n pEleStartDelim= '\u00a6';\r\nEndIf;\r\nIf( pEleDelim @= '' );\r\n pEleDelim = '+';\r\nEndIf;\r\n\r\n# Check the delimiters\r\nIf( Trim( pFilter ) @<> '' );\r\n If( sDelimDim @= sElementStartDelim % sDelimDim @= sDelimElem % sElementStartDelim @= sDelimElem );\r\n sMessage = 'The delimiters cannot be the same.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n EndIf;\r\nEndIf; \r\n\r\n# consolidated strings\r\nIf( pSuppressConsolStrings <> 0 );\r\n pSuppressConsolStrings = 1;\r\nEndIf;\r\n\r\n# Validate cubelogging parameter\r\nIf( pCubeLogging <> 0 & pCubeLogging <> 1 & pCubeLogging <> 2);\r\n sMessage = 'The cube logging parameter incorrect';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# If no cube has been specified then terminate process\r\nIf( Trim( pCube ) @= '' );\r\n sMessage = 'No cube(s) specified.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate parallelization filter\r\nIf( Scan( pEleStartDelim, pFilterParallel ) > 0 );\r\n sDimParallel = SubSt( pFilterParallel, 1, Scan( pEleStartDelim, pFilterParallel ) - 1 );\r\n If( Scan( Lower(sDimParallel) | pEleStartDelim, Lower(pFilter) ) > 0 );\r\n sMessage = 'Parallelization dimension %sDimParallel% cannot exist in filter.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n EndIf;\r\nEndIf;\r\n\r\n# Validate Max Threads\r\nIf( pParallelThreads >= 1 );\r\n nMaxThreads = Round(pParallelThreads);\r\nElse;\r\n # Single thread mode\r\n nMaxThreads = 1;\r\nEndIf;\r\n\r\n# Validate Sandbox\r\nIf( TRIM( pSandbox ) @<> '' );\r\n If( ServerSandboxExists( pSandbox ) = 0 );\r\n SetUseActiveSandboxProperty( 0 );\r\n nErrors = nErrors + 1;\r\n sMessage = Expand('Sandbox %pSandbox% is invalid for the current user.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n Else;\r\n ServerActiveSandboxSet( pSandbox );\r\n SetUseActiveSandboxProperty( 1 );\r\n EndIf;\r\nElse;\r\n SetUseActiveSandboxProperty( 0 );\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n# Loop through cubes in pCube\r\nsCubes = pCube;\r\nnCubeDelimiterIndex = 1;\r\n# Get 1st cube\r\nWhile( nCubeDelimiterIndex <> 0 );\r\n\r\n # Extract 1st cube > sCube\r\n nCubeDelimiterIndex = Scan( pDimDelim, sCubes );\r\n If( nCubeDelimiterIndex = 0 );\r\n sCube = sCubes;\r\n Else;\r\n sCube = Trim( SubSt( sCubes, 1, nCubeDelimiterIndex - 1 ) );\r\n sCubes = Trim( Subst( sCubes, nCubeDelimiterIndex + Long(pDimDelim), Long( sCubes ) ) );\r\n EndIf;\r\n \r\n bParallel = 0;\r\n \r\n # Check if sCube has wildcard\r\n If( Scan( '*', sCube ) = 0);\r\n # Validate cube\r\n If( CubeExists(sCube) = 0 );\r\n nErrors = 1;\r\n sMessage = Expand( 'Cube %sCube% does not exist.' );\r\n LogOutput( 'ERROR', Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n Else;\r\n If( Scan( pEleStartDelim, pFilterParallel ) > 0 );\r\n nDim = 1;\r\n sDim = TABDIM( sCube, nDim);\r\n While ( sDim @<> '' );\r\n sDim = TABDIM( sCube, nDim);\r\n If ( sDim @= sDimParallel );\r\n bParallel = 1;\r\n sDim = '';\r\n EndIf;\r\n nDim = nDim + 1;\r\n End;\r\n EndIf;\r\n If( bParallel = 1 );\r\n sDimParallel = SubSt( pFilterParallel, 1, Scan( pEleStartDelim, pFilterParallel ) - 1 );\r\n sElementList = SubSt( pFilterParallel, Scan( pEleStartDelim, pFilterParallel ) + 1, Long( pFilterParallel ) );\r\n If( SubSt( sElementList, Long( sElementList ), 1 ) @<> pEleDelim );\r\n sElementList = sElementList | pEleDelim;\r\n EndIf;\r\n ## Counting elements in element list\r\n sElementListCount = sElementList;\r\n nElements = 0;\r\n While( Scan( pEleDelim, sElementListCount ) > 0 );\r\n nElements = nElements + 1;\r\n sElementListCount = SubSt( sElementListCount, Scan( pEleDelim, sElementListCount ) + 1, Long( sElementListCount ) );\r\n End;\r\n IF( Mod( nElements, nMaxThreads ) = 0 );\r\n nElemsPerThread = INT( nElements / nMaxThreads );\r\n ELSE;\r\n nElemsPerThread = INT( nElements / nMaxThreads ) + 1;\r\n ENDIF;\r\n nThreadElCounter = 0;\r\n While( Scan( pEleDelim, sElementList ) > 0 );\r\n sSlicerEle = SubSt( sElementList, 1, Scan( pEleDelim, sElementList ) - 1 );\r\n sElementList = SubSt( sElementList, Scan( pEleDelim, sElementList ) + 1, Long( sElementList ) );\r\n # Do recursive process call with new RunProcess function\r\n nThreadElCounter = nThreadElCounter + 1;\r\n sDimDelim = If(pFilter @= '', '', pDimDelim );\r\n IF( nThreadElCounter = 1 );\r\n sFilter = Expand('%pFilter%%sDimDelim%%sDimParallel%%pEleStartDelim%%sSlicerEle%');\r\n ELSE;\r\n sFilter = Expand('%sFilter%%pEleDelim%%sSlicerEle%');\r\n ENDIF;\r\n IF( nThreadElCounter >= nElemsPerThread );\r\n RunProcess( cThisProcName, 'pLogoutput', pLogoutput,\r\n \t 'pCube', pCube, 'pView', pView, 'pFilter', sFilter, 'pFilterParallel', '', \r\n \t 'pDimDelim', pDimDelim, 'pEleStartDelim', pEleStartDelim, 'pEleDelim', pEleDelim, \r\n \t 'pSuppressConsolStrings', pSuppressConsolStrings, 'pCubeLogging', pCubeLogging, 'pTemp', pTemp, 'pSandbox', pSandbox\r\n \t );\r\n \t nThreadElCounter = 0;\r\n \t sFilter = '';\r\n \t ENDIF;\r\n End;\r\n ## Process last elements - only when filter is not empty (there are still elements) otherwise the entire cube is emptied\r\n IF( sFilter @<> '' );\r\n RunProcess( cThisProcName, 'pLogoutput', pLogoutput,\r\n \t 'pCube', pCube, 'pView', pView, 'pFilter', sFilter, 'pFilterParallel', '', \r\n \t 'pDimDelim', pDimDelim, 'pEleStartDelim', pEleStartDelim, 'pEleDelim', pEleDelim, \r\n \t 'pSuppressConsolStrings', pSuppressConsolStrings, 'pCubeLogging', pCubeLogging, 'pTemp', pTemp, 'pSandbox', pSandbox\r\n \t );\r\n \t ENDIF;\r\n Else;\r\n ## Validate the View & filter parameter\r\n If( Trim( pView ) @= '' & Trim( pFilter ) @= '' & Trim( pSandbox ) @= '' );\r\n sMessage = Expand('No view OR filter specified so the entire %sCube% cube has been cleared.');\r\n\t IF( pLogoutput = 1 );\r\n \tLogOutput( 'INFO' , Expand( 'Process:%cThisProcName% Message:%sMessage%' ) );\r\n\t ENDIF;\r\n CubeClearData( sCube );\r\n Else;\r\n # Use different view/subset for different cubes\r\n sTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\n sRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\n cDefaultView = Expand( '%cThisProcName%_%sTimeStamp%_%sRandomInt%' );\r\n #cTempSub = cDefaultView;\r\n \r\n If( Trim( pView ) @= '' );\r\n cView = cDefaultView ;\r\n Else;\r\n cView = Trim( pView );\r\n EndIf;\r\n \r\n # Clear view\r\n If( ViewExists( sCube , cView ) = 0 );\r\n ## Validate that a Filter has been provided so that a view can be created.\r\n If( Trim( pFilter ) @= '' );\r\n sMessage = Expand('View %cView% does not exist in the %sCube% cube AND no Filter has not been specified in order to create a view.');\r\n LogOutput( 'INFO' , Expand( cMsgErrorContent ) );\r\n #ProcessBreak;\r\n EndIf;\r\n\r\n ### Create View using filter (temp view, therefore no need to destroy) ###\r\n sProc = '}bedrock.cube.view.create';\r\n nRet = ExecuteProcess( sProc,\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pCube', sCube, 'pView', cView, 'pFilter', pFilter,\r\n 'pSuppressZero', 1, 'pSuppressConsol', 1, 'pSuppressRules', 1, 'pSuppressConsolStrings', pSuppressConsolStrings,\r\n 'pDimDelim', pDimDelim, 'pEleStartDelim', pEleStartDelim, 'pEleDelim', pEleDelim,\r\n 'pTemp', pTemp, 'pSubN', pSubN\r\n );\r\n\r\n # Validate Sandbox\r\n If( TRIM( pSandbox ) @<> '' );\r\n If( ServerSandboxExists( pSandbox ) = 0 );\r\n SetUseActiveSandboxProperty( 0 );\r\n nErrors = nErrors + 1;\r\n sMessage = Expand('Sandbox %pSandbox% is invalid for the current user.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n Else;\r\n ServerActiveSandboxSet( pSandbox );\r\n SetUseActiveSandboxProperty( 1 );\r\n EndIf;\r\n Else;\r\n SetUseActiveSandboxProperty( 0 );\r\n EndIf;\r\n\r\n ### Zero Out View ###\r\n If ( nRet = ProcessExitNormal() );\r\n ViewZeroOut( sCube, cView );\r\n sMessage = Expand( 'Succeeded in creating the %cView% view in the %sCube% cube and data has been cleared.' );\r\n \t If( pLogoutput = 1 );\r\n \tLogOutput( 'INFO', Expand( 'Process:%cThisProcName% Message:%sMessage%' ) );\r\n \t EndIf;\r\n Else;\r\n nErrors = nErrors + 1;\r\n sMessage = Expand( 'Creating view by %sProc% has failed. Nothing has been cleared in the %sCube% cube.' );\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n EndIf;\r\n Else;\r\n ViewZeroOut( sCube, cView );\r\n Endif;\r\n Endif;\r\n EndIf;\r\n Endif;\r\n Else;\r\n # Create subset of cubes using Wildcard to loop through cubes in pCube with wildcard\r\n sCubeExp = '\"'|sCube|'\"';\r\n sMdx = '{TM1FILTERBYPATTERN( {TM1SUBSETALL( [}Cubes] )},'|sCubeExp| ')}';\r\n If( SubsetExists( '}Cubes' , cTempSub ) = 1 );\r\n # If a delimited list of cube names includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( '}Cubes' , cTempSub, sMDX );\r\n Else;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSub, sMDX, '}Cubes' , 1 );\r\n EndIf;\r\n \r\n # Loop through cubes in subset created based on wildcard\r\n nCountCube = SubsetGetSize( '}Cubes' , cTempSub );\r\n While( nCountCube >= 1 );\r\n # Use different view/subset for different cubes\r\n sTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\n sRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\n cDefaultView = Expand( '%cThisProcName%_%sTimeStamp%_%sRandomInt%' );\r\n sCube = SubsetGetElementName( '}Cubes' , cTempSub, nCountCube );\r\n # Validate cube name Not necessary as derived from subset of }Cubes\r\n If( CubeExists(sCube) = 0 );\r\n nErrors = 1;\r\n sMessage = Expand( '%sCube% does not exist.' );\r\n LogOutput( 'ERROR', Expand( cMsgErrorContent ) );\r\n Else;\r\n If( Scan( pEleStartDelim, pFilterParallel ) > 0 );\r\n nDim = 1;\r\n sDim = TABDIM( sCube, nDim);\r\n While ( sDim @<> '' );\r\n sDim = TABDIM( sCube, nDim);\r\n If ( sDim @= sDimParallel );\r\n bParallel = 1;\r\n sDim = '';\r\n EndIf;\r\n nDim = nDim + 1;\r\n End;\r\n EndIf;\r\n If( bParallel = 1 );\r\n sDimParallel = SubSt( pFilterParallel, 1, Scan( pEleStartDelim, pFilterParallel ) - 1 );\r\n sElementList = SubSt( pFilterParallel, Scan( pEleStartDelim, pFilterParallel ) + 1, Long( pFilterParallel ) );\r\n If( SubSt( sElementList, Long( sElementList ), 1 ) @<> pEleDelim );\r\n sElementList = sElementList | pEleDelim;\r\n EndIf;\r\n ## Counting elements in element list\r\n sElementListCount = sElementList;\r\n nElements = 0;\r\n While( Scan( pEleDelim, sElementListCount ) > 0 );\r\n nElements = nElements + 1;\r\n sElementListCount = SubSt( sElementListCount, Scan( pEleDelim, sElementListCount ) + 1, Long( sElementListCount ) );\r\n End;\r\n IF( Mod( nElements, nMaxThreads ) = 0 );\r\n nElemsPerThread = INT( nElements / nMaxThreads );\r\n ELSE;\r\n nElemsPerThread = INT( nElements / nMaxThreads ) + 1;\r\n ENDIF;\r\n nThreadElCounter = 0;\r\n While( Scan( pEleDelim, sElementList ) > 0 );\r\n sSlicerEle = SubSt( sElementList, 1, Scan( pEleDelim, sElementList ) - 1 );\r\n sElementList = SubSt( sElementList, Scan( pEleDelim, sElementList ) + 1, Long( sElementList ) );\r\n # Do recursive process call with new RunProcess function\r\n nThreadElCounter = nThreadElCounter + 1;\r\n sDimDelim = If(pFilter @= '', '', pDimDelim );\r\n IF( nThreadElCounter = 1 );\r\n sFilter = Expand('%pFilter%%sDimDelim%%sDimParallel%%pEleStartDelim%%sSlicerEle%');\r\n ELSE;\r\n sFilter = Expand('%sFilter%%pEleDelim%%sSlicerEle%');\r\n ENDIF;\r\n IF( nThreadElCounter >= nElemsPerThread );\r\n RunProcess( cThisProcName, 'pLogoutput', pLogoutput,\r\n \t 'pCube', pCube, 'pView', pView, 'pFilter', sFilter, 'pFilterParallel', '', \r\n \t 'pDimDelim', pDimDelim, 'pEleStartDelim', pEleStartDelim, 'pEleDelim', pEleDelim, \r\n \t 'pSuppressConsolStrings', pSuppressConsolStrings, 'pCubeLogging', pCubeLogging, 'pTemp', pTemp, 'pSandbox', pSandbox\r\n \t );\r\n \t nThreadElCounter = 0;\r\n \t sFilter = '';\r\n \t ENDIF;\r\n End;\r\n ## Process last elements\r\n IF( sFilter @<> '' );\r\n RunProcess( cThisProcName, 'pLogoutput', pLogoutput,\r\n \t 'pCube', pCube, 'pView', pView, 'pFilter', sFilter, 'pFilterParallel', '', \r\n \t 'pDimDelim', pDimDelim, 'pEleStartDelim', pEleStartDelim, 'pEleDelim', pEleDelim, \r\n \t 'pSuppressConsolStrings', pSuppressConsolStrings, 'pCubeLogging', pCubeLogging, 'pTemp', pTemp, 'pSandbox', pSandbox\r\n \t );\r\n \t ENDIF;\r\n Else;\r\n ## Validate the View & filter parameter\r\n If( Trim( pView ) @= '' & Trim( pFilter ) @= '' & Trim( pSandbox ) @= '' );\r\n # Clear entire cube\r\n sMessage = Expand('No view OR filter specified so the entire %sCube% cube has been cleared.');\r\n\t IF( pLogoutput = 1 );\r\n \tLogOutput( 'INFO' , Expand( 'Process:%cThisProcName% Message:%sMessage%' ) );\r\n\t ENDIF;\r\n CubeClearData( sCube );\r\n Else;\r\n # Clear view cView\r\n If( Trim( pView ) @= '' );\r\n cView = cDefaultView ;\r\n Else;\r\n cView = Trim( pView );\r\n EndIf;\r\n \r\n If( ViewExists( sCube, cView ) = 0 );\r\n ## Validate that a Filter has been provided so that a view can be created.\r\n If( Trim( pFilter ) @= '' );\r\n sMessage = Expand('View %cView% does not exist for %sCube% AND no Filter has not been specified in order to create a view.');\r\n LogOutput( 'ERROR' , Expand( cMsgErrorContent ) );\r\n #ProcessBreak;\r\n EndIf;\r\n \r\n ### Create View using filter (temp view, therefore no need to destroy) ###\r\n sProc = '}bedrock.cube.view.create';\r\n nRet = ExecuteProcess( sProc,\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pCube', sCube, 'pView', cView, 'pFilter', pFilter,\r\n 'pSuppressZero', 1, 'pSuppressConsol', 1, 'pSuppressRules', 1, 'pSuppressConsolStrings', pSuppressConsolStrings,\r\n 'pDimDelim', pDimDelim, 'pEleStartDelim', pEleStartDelim, 'pEleDelim', pEleDelim,\r\n 'pTemp', pTemp, 'pSubN', pSubN\r\n );\r\n \r\n # Validate Sandbox\r\n If( TRIM( pSandbox ) @<> '' );\r\n If( ServerSandboxExists( pSandbox ) = 0 );\r\n SetUseActiveSandboxProperty( 0 );\r\n nErrors = nErrors + 1;\r\n sMessage = Expand('Sandbox %pSandbox% is invalid for the current user.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n Else;\r\n ServerActiveSandboxSet( pSandbox );\r\n SetUseActiveSandboxProperty( 1 );\r\n EndIf;\r\n Else;\r\n SetUseActiveSandboxProperty( 0 );\r\n EndIf;\r\n \r\n \r\n ### Zero Out View ###\r\n IF ( nRet = ProcessExitNormal() );\r\n ViewZeroOut( sCube, cView );\r\n sMessage = Expand( 'Succeeded in creating the %cView% view in the %sCube% cube and data has been cleared.' );\r\n \t\tIF( pLogoutput = 1 );\r\n LogOutput( 'INFO', Expand( 'Process:%cThisProcName% Message:%sMessage%' ) );\r\n \t\tENDIF;\r\n ELSE;\r\n nErrors = nErrors + 1;\r\n sMessage = Expand( 'Creating view by %sProc% has failed. Nothing has been cleared in the %sCube% cube.' );\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n ENDIF;\r\n Else;\r\n ViewZeroOut( sCube, cView );\r\n Endif;\r\n EndIf;\r\n EndIf;\r\n nCountCube = nCountCube - 1;\r\n # Use different view/subset for different cubes\r\n sTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\n sRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\n cDefaultView = Expand( '%cThisProcName%_%sTimeStamp%_%sRandomInt%' );\r\n #cTempSub = cDefaultView; \r\n EndIf;\r\n End;\r\n EndIf;\r\nEnd;\r\n\r\n### End Prolog ###", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully cleared data out of the %pCube% cube(s).' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n### End Epilog ###", @@ -10,21 +10,9 @@ "Type": "None" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pCube", - "Prompt": "REQUIRED: Cube Name (wildcard * and/or cube1 & cube2 list)", + "Prompt": "REQUIRED: Cube name", "Value": "", "Type": "String" }, @@ -36,61 +24,73 @@ }, { "Name": "pFilter", - "Prompt": "Optional but ignored if view is specified: Year\u00a6 2006 + 2007 & Scenario\u00a6 Actual + Budget & Organization\u00a6 North America Operations", + "Prompt": "OPTIONAL: Filter on cube in format: 'dim_one\u00a6 el_one + el_two & dim_two\u00a6 el_one + el_two'", "Value": "", "Type": "String" }, { "Name": "pFilterParallel", - "Prompt": "OPTIONAL: Parallelization Filter: Month:Q1+Q2+Q3+Q4 (Blank=run single threaded). Single dimension parallel slices. Will be added to filter single element at a time. Dimension must not be part of filter", + "Prompt": "OPTIONAL: Parallelization filter in format: dim_one\u00a6 el_one + el_two. Dimension must not be part of filter", "Value": "", "Type": "String" }, { "Name": "pParallelThreads", - "Prompt": "OPTIONAL: Ignored if pFilterParallel is empty. Maximum number of threads to run when parallel processing is enabled ( if <2 will execute one thread, but parallel filter is still applied )", + "Prompt": "OPTIONAL: Maximum number of threads to run when parallel processing is enabled (Default = 0)", "Value": 0, "Type": "Numeric" }, { "Name": "pDimDelim", - "Prompt": "OPTIONAL: Delimiter for start of Dimension/Element set (default value if blank = '&')", + "Prompt": "OPTIONAL: Delimiter for start of dimension/element set in filter parameters (Default = '&')", "Value": "&", "Type": "String" }, { "Name": "pEleStartDelim", - "Prompt": "OPTIONAL: Delimiter for start of element list (default value if blank = '\u00a6')", + "Prompt": "OPTIONAL: Delimiter for start of element list in filter parameters (Default = '\u00a6')", "Value": "\u00a6", "Type": "String" }, { "Name": "pEleDelim", - "Prompt": "OPTIONAL: Delimiter between elements (default value if blank = '+')", + "Prompt": "OPTIONAL: Delimiter between elements in filter parameters (Default = '+')", "Value": "+", "Type": "String" }, { "Name": "pSuppressConsolStrings", - "Prompt": "OPTIONAL: Suppress Consolidated String Cells (Skip = 1)", - "Value": 0, + "Prompt": "OPTIONAL: Suppress consolidated string cells (Boolean. Default = 1)", + "Value": 1, "Type": "Numeric" }, { "Name": "pTemp", - "Prompt": "OPTIONAL: Make Views and subsets Temporary (1=Temporary)", + "Prompt": "OPTIONAL: Delete/create temporary objects (0 = Do not delete, 1 = Delete, 2 = if view and subsets are created, keep only subsets)", "Value": 1, "Type": "Numeric" }, { "Name": "pSandbox", - "Prompt": "OPTIONAL: To use sandbox not base data enter the sandbox name (invalid name will result in process error)", + "Prompt": "OPTIONAL: Use sandbox", "Value": "", "Type": "String" }, { "Name": "pSubN", - "Prompt": "OPTIONAL: Create N level subset for all dims not mentioned in pFilter", + "Prompt": "OPTIONAL: Create N level subset for all dims not specified (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, @@ -99,6 +99,12 @@ "Prompt": "OBSOLETE: This parameter does nothing and is only included for backwards compatability", "Value": 0, "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [], diff --git a/bedrock_processes_json/}bedrock.cube.data.copy.intercube.json b/bedrock_processes_json/}bedrock.cube.data.copy.intercube.json index 9b749d3..9ee5867 100644 --- a/bedrock_processes_json/}bedrock.cube.data.copy.intercube.json +++ b/bedrock_processes_json/}bedrock.cube.data.copy.intercube.json @@ -1,11 +1,11 @@ { "Name": "}bedrock.cube.data.copy.intercube", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.cube.data.copy.intercube', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pSrcCube', '', 'pFilter', '',\r\n \t'pFilterParallel', '', 'pParallelThreads', 0,\r\n \t'pTgtCube', '', 'pMappingToNewDims', '',\r\n \t'pSuppressConsol', 1, 'pSuppressConsolStrings', 0, 'pSuppressRules', 1, 'pSuppressZero', 1, \r\n \t'pZeroTarget', 1, 'pZeroSource', 0,\r\n \t'pFactor', 1,\r\n \t'pDimDelim', '&', 'pEleStartDelim', '\u00a6', 'pEleDelim', '+',\r\n \t'pTemp', 1, 'pCubeLogging', 0, 'pSandbox', pSandbox, 'pSubN', 0, \r\n \t'pFile', 0, 'pDelim', ',', 'pQuote', '\"', 'pDecimalSeparator', '.', 'pThousandSeparator', ','\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# ## Description\r\n# This is the process used to copy data from a source cube to a different target cube.\r\n# \r\n# ## Use Cases \r\n# 1. This process could be used to populate a Reporting cube from multiple source cubes.\r\n# 2. The process could be used to archive data from one cube to another one for any use.\r\n#\r\n# ## Notes\r\n# * The target cube may have a different number of dimensions as the source cube.\r\n# * Where the target and source cubes share the same dimensions, the process will match the dimensions even if their position in the cube is different.\r\n# * An input element must be specified for each dimension which is in the target but not in the source using the parameter pMappingToNewDims.\r\n# * The format of parameter pMappingToNewDims using default delimiters & and : is DimInTargetButNotSource1:ElementOfDim & DimInTargetButNotSource2:ElementOfDim.\r\n# * The input element must be an N level unless pSuppressConsol is set to 0.\r\n# * The maximum number of dimensions catered for in the target cube is 27. (In principle adding support for cubes with higher dimensionality is not difficult).\r\n#\r\n# For dimensions in the source but not the target, the process will accumulate the values of all n level elements\r\n# (or all n level elements specified by the pFilter parameter).\r\n# The pFilter parameter contains the dimensions and elements to be used for filtering the source cube.\r\n# The format of the pFilter parameter is as follows, using default delimiters & + : Dim1: Elem1 + Elem2 & Dim2: Elem3 + Elem4.\r\n# The dimension parameters do not need to be given in the index order of dimensions in the cube.\r\n# The dimension name is specified as the first member of the delimited string of elements.\r\n# If consolidations are skipped the N level children of any consolidated filter elements will be used.\r\n# Spaces are ignored so use them to make your filter more readable.\r\n# If using the pFilterParallel parameter the **single dimension** used as the \"parallelization slicer\" cannot appear in\r\n# the pFilter parameters.\r\n# When using parallelization via the *RunProcess* function the elements listed in pFilterParallel will be split one_at_a_time\r\n# and passed to a recursive call of the process being added to pFilter.\r\n#\r\n# An example:\r\n# To copy the 2011 Actual Sales data from the Sales cube to the General Ledger cube set pFilter to Year: 2011 & Version: Actual.\r\n# Say the General Ledger cube has an Account dimension but the Sales cube doesn't and the Account for sales is 9999 (an n level element).\r\n# Set the pMappingToNewDims parameter to Account:9999.\r\n# This will copy all Actual 2011 Sales to Account 9999 in the General Ledger.\r\n# If only sales for Company X are to be copied, set pFilter to Year: 2011 & Version: Actual & Company:X.\r\n# If sales from other companies are already in the General Ledger set pZeroTarget to 0 to add Company X's data to the existing data.\r\n# Setting pZeroTarget to 1 will clear our data in the target cube for the elements specified in the\r\n# pMappingToNewDims parameter and the pFilter parameter for dimensions that are in the target.\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = '%cThisProcName% : %sMessage% : %cUserName%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pSrcCube:%pSrcCube%, pFilter:%pFilter%, pFilterParallel:%pFilterParallel%, pParallelThreads:%pParallelThreads%, pTgtCube:%pTgtCube%, pMappingToNewDims:%pMappingToNewDims%, pSuppressConsol:%pSuppressConsol%, pSuppressConsolStrings:%pSuppressConsolStrings%, pSuppressRules:%pSuppressRules%, pSuppressZero:%pSuppressZero%, pZeroTarget:%pZeroTarget%, pZeroSource:%pZeroSource%, pFactor:%pFactor%, pDimDelim:%pDimDelim%, pEleStartDelim:%pEleStartDelim%, pEleDelim:%pEleDelim%, pTemp:%pTemp%, pCubeLogging:%pCubeLogging%, pSandbox:%pSandbox%, pFile:%pFile%, pThreadMode:%pThreadMode%.'; \r\n\r\nsDelimDim = TRIM(pDimDelim);\r\nsElementStartDelim = TRIM(pElEStartDelim);\r\nsDelimElem = TRIM(pEleDelim);\r\nnErrors = 0;\r\ncLenASCIICode = 3;\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n# Make sure pFactor not zero\r\nnFactor = If( pFactor = 0, 1, pFactor );\r\n\r\nsView = cThisProcName | cTimeStamp | cRandomInt;\r\nsSubset = sView;\r\nsTargetView = 'Target '| sView;\r\nsTargetSubset = sTargetView;\r\n\r\n## check operating system\r\nIf( SubSt( GetProcessErrorFileDirectory, 2, 1 ) @= ':' );\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nElseIf( Scan( '/', GetProcessErrorFileDirectory ) > 0 );\r\n sOS = 'Linux';\r\n sOSDelim = '/';\r\nElse;\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nEndIf;\r\n\r\n## File location for indirect data copy\r\ncDir = GetProcessErrorFileDirectory;\r\ncFileName = pSrcCube | cTimeStamp | cRandomInt | '.csv';\r\ncFile = cDir | cFileName;\r\ncTitleRows = 1;\r\n\r\n# Validate file delimiter & quote character\r\nIf( pDelim @= '' );\r\n pDelim = ',';\r\nElse;\r\n # If length of pDelim is exactly 3 chars and each of them is decimal digit, then the pDelim is entered as ASCII code\r\n nValid = 0;\r\n If ( LONG(pDelim) = cLenASCIICode );\r\n nChar = 1;\r\n While ( nChar <= cLenASCIICode );\r\n If( CODE( pDelim, nChar ) >= CODE( '0', 1 ) & CODE( pDelim, nChar ) <= CODE( '9', 1 ) );\r\n nValid = 1;\r\n Else;\r\n nValid = 0;\r\n Break;\r\n EndIf;\r\n nChar = nChar + 1;\r\n End;\r\n EndIf;\r\n If ( nValid<>0 );\r\n pDelim=CHAR(StringToNumber( pDelim ));\r\n Else;\r\n pDelim = SubSt( Trim( pDelim ), 1, 1 );\r\n EndIf;\r\nEndIf;\r\ncDelimiter = pDelim;\r\n\r\nIf( pQuote @= '' );\r\n ## Use no quote character\r\nElse;\r\n # If length of pQuote is exactly 3 chars and each of them is decimal digit, then the pQuote is entered as ASCII code\r\n nValid = 0;\r\n If ( LONG(pQuote) = cLenASCIICode );\r\n nChar = 1;\r\n While ( nChar <= cLenASCIICode );\r\n If( CODE( pQuote, nChar ) >= CODE( '0', 1 ) & CODE( pQuote, nChar ) <= CODE( '9', 1 ) );\r\n nValid = 1;\r\n Else;\r\n nValid = 0;\r\n Break;\r\n EndIf;\r\n nChar = nChar + 1;\r\n End;\r\n EndIf;\r\n If ( nValid<>0 );\r\n pQuote=CHAR(StringToNumber( pQuote ));\r\n Else;\r\n pQuote = SubSt( Trim( pQuote ), 1, 1 );\r\n EndIf;\r\nEndIf;\r\ncQuote = pQuote;\r\n\r\n#Region ## Check Parameters ###\r\n\r\n## Default filter delimiters\r\nIf( pDimDelim @= '' );\r\n pDimDelim = '&';\r\nEndIf;\r\nIf( pEleStartDelim@= '' );\r\n pEleStartDelim= '\u00a6';\r\nEndIf;\r\nIf( pEleDelim @= '' );\r\n pEleDelim = '+';\r\nEndIf;\r\n\r\nIf( pDecimalSeparator @= '' );\r\n \tpDecimalSeparator = '.';\r\nEndIf;\r\nIf ( LONG(pDecimalSeparator) = cLenASCIICode );\r\n nValid = 0;\r\n nChar = 1;\r\n While ( nChar <= cLenASCIICode );\r\n If( CODE( pDecimalSeparator, nChar ) >= CODE( '0', 1 ) & CODE( pDecimalSeparator, nChar ) <= CODE( '9', 1 ) );\r\n nValid = 1;\r\n Else;\r\n nValid = 0;\r\n Break;\r\n EndIf;\r\n nChar = nChar + 1;\r\n End;\r\n If ( nValid<>0 );\r\n pDecimalSeparator = CHAR(StringToNumber( pDecimalSeparator ));\r\n Else;\r\n pDecimalSeparator = SubSt( Trim( pDecimalSeparator ), 1, 1 );\r\n EndIf;\r\nEndIf;\r\nsDecimalSeparator = pDecimalSeparator;\r\n\r\nIf( pThousandSeparator @= '' );\r\n \tpThousandSeparator = ',';\r\nEndIf;\r\nIf ( LONG(pThousandSeparator) = cLenASCIICode );\r\n nValid = 0;\r\n nChar = 1;\r\n While ( nChar <= cLenASCIICode );\r\n If( CODE( pThousandSeparator, nChar ) >= CODE( '0', 1 ) & CODE( pThousandSeparator, nChar ) <= CODE( '9', 1 ) );\r\n nValid = 1;\r\n Else;\r\n nValid = 0;\r\n Break;\r\n EndIf;\r\n nChar = nChar + 1;\r\n End;\r\n If ( nValid<>0 );\r\n pThousandSeparator = CHAR(StringToNumber( pThousandSeparator ));\r\n Else;\r\n pThousandSeparator = SubSt( Trim( pThousandSeparator ), 1, 1 );\r\n EndIf;\r\nEndIf;\r\nsThousandSeparator = pThousandSeparator;\r\n\r\n# If specified source cube doesn't exist then terminate process\r\nIf( CubeExists( pSrcCube ) = 0 );\r\n nErrors = nErrors + 1;\r\n sMessage = Expand( 'Invalid source cube specified: %pSrcCube%.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# If specified target cube doesn't exist then terminate process\r\nIf( CubeExists( pTgtCube ) = 0 );\r\n nErrors = nErrors + 1;\r\n sMessage = Expand( 'Invalid target cube specified: %pTgtCube%.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate parallelization filter\r\nIf( Scan( pEleStartDelim, pFilterParallel ) > 0 );\r\n sDimParallel = SubSt( pFilterParallel, 1, Scan( pEleStartDelim, pFilterParallel ) - 1 );\r\n If( Scan( Lower(sDimParallel) | pEleStartDelim, Lower(pFilter) ) > 0 );\r\n sMessage = 'Parallelization dimension %sDimParallel% cannot exist in filter.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n EndIf;\r\nEndIf;\r\n\r\n# Validate Max Threads\r\nIf( pParallelThreads > 0 );\r\n nMaxThreads = pParallelThreads;\r\nElse;\r\n nMaxThreads = 1;\r\nEndIf;\r\n\r\n# Validate Sandbox\r\nIf( TRIM( pSandbox ) @<> '' );\r\n If( ServerSandboxExists( pSandbox ) = 0 );\r\n SetUseActiveSandboxProperty( 0 );\r\n nErrors = nErrors + 1;\r\n sMessage = Expand('Sandbox %pSandbox% is invalid for the current user.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n Else;\r\n ServerActiveSandboxSet( pSandbox );\r\n SetUseActiveSandboxProperty( 1 );\r\n EndIf;\r\nElse;\r\n SetUseActiveSandboxProperty( 0 );\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n#EndRegion\r\n#Region \r\n## Set variables =0 or '' ################################################################################################# ########################\r\n### Placeholders for mappped dimensions\r\nnMappedDim1 = 0;\r\nnMappedDim2 = 0;\r\nnMappedDim3 = 0;\r\nnMappedDim4 = 0;\r\nnMappedDim5 = 0;\r\nnMappedDim6 = 0;\r\nnMappedDim7 = 0;\r\nnMappedDim8 = 0;\r\nnMappedDim9 = 0;\r\nnMappedDim10 = 0;\r\nnMappedDim11 = 0;\r\nnMappedDim12 = 0;\r\nnMappedDim13 = 0;\r\nnMappedDim14 = 0;\r\nnMappedDim15 = 0;\r\nnMappedDim16 = 0;\r\nnMappedDim17 = 0;\r\nnMappedDim18 = 0;\r\nnMappedDim19 = 0;\r\nnMappedDim20 = 0;\r\nnMappedDim21 = 0;\r\nnMappedDim22 = 0;\r\nnMappedDim23 = 0;\r\nnMappedDim24 = 0;\r\nnMappedDim25 = 0;\r\nnMappedDim26 = 0;\r\nnMappedDim27 = 0;\r\n\r\nsMappedV1 = '';\r\nsMappedV2 = '';\r\nsMappedV3 = '';\r\nsMappedV4 = '';\r\nsMappedV5 = '';\r\nsMappedV6 = '';\r\nsMappedV7 = '';\r\nsMappedV8 = '';\r\nsMappedV9 = '';\r\nsMappedV10 = '';\r\nsMappedV11 = '';\r\nsMappedV12 = '';\r\nsMappedV13 = '';\r\nsMappedV14 = '';\r\nsMappedV15 = '';\r\nsMappedV16 = '';\r\nsMappedV17 = '';\r\nsMappedV18 = '';\r\nsMappedV19 = '';\r\nsMappedV20 = '';\r\nsMappedV21 = '';\r\nsMappedV22 = '';\r\nsMappedV23 = '';\r\nsMappedV24 = '';\r\nsMappedV25 = '';\r\nsMappedV26 = '';\r\nsMappedV27 = '';\r\nsMappedV28 = '';\r\n\r\n### Placeholders for new dimensions\r\nnNewDim1 = 0;\r\nnNewDim2 = 0;\r\nnNewDim3 = 0;\r\nnNewDim4 = 0;\r\nnNewDim5 = 0;\r\nnNewDim6 = 0;\r\nnNewDim7 = 0;\r\nnNewDim8 = 0;\r\nnNewDim9 = 0;\r\nnNewDim10 = 0;\r\nnNewDim11 = 0;\r\nnNewDim12 = 0;\r\nnNewDim13 = 0;\r\nnNewDim14 = 0;\r\nnNewDim15 = 0;\r\nnNewDim16 = 0;\r\nnNewDim17 = 0;\r\nnNewDim18 = 0;\r\nnNewDim19 = 0;\r\nnNewDim20 = 0;\r\nnNewDim21 = 0;\r\nnNewDim22 = 0;\r\nnNewDim23 = 0;\r\nnNewDim24 = 0;\r\nnNewDim25 = 0;\r\nnNewDim26 = 0;\r\nnNewDim27 = 0;\r\n\r\nsNewV1 = '';\r\nsNewV2 = '';\r\nsNewV3 = '';\r\nsNewV4 = '';\r\nsNewV5 = '';\r\nsNewV6 = '';\r\nsNewV7 = '';\r\nsNewV8 = '';\r\nsNewV9 = '';\r\nsNewV10 = '';\r\nsNewV11 = '';\r\nsNewV12 = '';\r\nsNewV13 = '';\r\nsNewV14 = '';\r\nsNewV15 = '';\r\nsNewV16 = '';\r\nsNewV17 = '';\r\nsNewV18 = '';\r\nsNewV19 = '';\r\nsNewV20 = '';\r\nsNewV21 = '';\r\nsNewV22 = '';\r\nsNewV23 = '';\r\nsNewV24 = '';\r\nsNewV25 = '';\r\nsNewV26 = '';\r\nsNewV27 = '';\r\n\r\n### Determine dimensions in target cube, we need to know this to test cell type before loading ###\r\n# only numbers get converted from strings to numbers\r\nsDim1 = TabDim( pTgtCube, 1 );\r\nsDim2 = TabDim( pTgtCube, 2 );\r\nsDim3 = TabDim( pTgtCube, 3 );\r\nsDim4 = TabDim( pTgtCube, 4 );\r\nsDim5 = TabDim( pTgtCube, 5 );\r\nsDim6 = TabDim( pTgtCube, 6 );\r\nsDim7 = TabDim( pTgtCube, 7 );\r\nsDim8 = TabDim( pTgtCube, 8 );\r\nsDim9 = TabDim( pTgtCube, 9 );\r\nsDim10 = TabDim( pTgtCube, 10 );\r\nsDim11 = TabDim( pTgtCube, 11 );\r\nsDim12 = TabDim( pTgtCube, 12 );\r\nsDim13 = TabDim( pTgtCube, 13 );\r\nsDim14 = TabDim( pTgtCube, 14 );\r\nsDim15 = TabDim( pTgtCube, 15 );\r\nsDim16 = TabDim( pTgtCube, 16 );\r\nsDim17 = TabDim( pTgtCube, 17 );\r\nsDim18 = TabDim( pTgtCube, 18 );\r\nsDim19 = TabDim( pTgtCube, 19 );\r\nsDim20 = TabDim( pTgtCube, 20 );\r\nsDim21 = TabDim( pTgtCube, 21 );\r\nsDim22 = TabDim( pTgtCube, 22 );\r\nsDim23 = TabDim( pTgtCube, 23 );\r\nsDim24 = TabDim( pTgtCube, 24 );\r\nsDim25 = TabDim( pTgtCube, 25 );\r\nsDim26 = TabDim( pTgtCube, 26 );\r\nsDim27 = TabDim( pTgtCube, 27 );\r\n#EndRegion\r\nsTgtDimString = '^^'|sDim1|'^^'|sDim2|'^^'|sDim3|'^^'|sDim4|'^^'|sDim5|'^^'|sDim6|'^^'|sDim7|'^^'|sDim8|'^^'|sDim9|'^^'|sDim10|'^^'\r\n |sDim11|'^^'|sDim12|'^^'|sDim13|'^^'|sDim14|'^^'|sDim15|'^^'|sDim16|'^^'|sDim17|'^^'|sDim18|'^^'|sDim19|'^^'|sDim20|'^^'\r\n |sDim21|'^^'|sDim22|'^^'|sDim23|'^^'|sDim24|'^^'|sDim25|'^^'|sDim26|'^^'|sDim27|'^^';\r\n\r\n### We have to remove spaces from the search string before going to include the string in searching loop\r\nsTgtDimString = UPPER( sTgtDimString );\r\nnSPIndex = SCAN( ' ', sTgtDimString );\r\nWhile ( nSPIndex <> 0);\r\n sTgtDimString = DELET( sTgtDimString, nSPIndex, 1 );\r\n nSPIndex = SCAN( ' ', sTgtDimString );\r\nEnd;\r\n\r\n###########################################\r\n#Region ### MAPPING Target DIMENSIONS #####\r\n###########################################\r\nnSourceIndex = 1;\r\nWhile( TabDim( pSrcCube, nSourceIndex ) @<> '' );\r\n sSourceDim = TabDim( pSrcCube, nSourceIndex);\r\n # reset target index if another source dimension has been found\r\n nTargetIndex = 1;\r\n WHILE(TabDim( pTgtCube, nTargetIndex ) @<> '');\r\n sTargetDim = TabDim( pTgtCube, nTargetIndex );\r\n If(sSourceDim @= sTargetDim);\r\n If( pFile = 0 );\r\n If(nTargetIndex = 1);\r\n nMappedDim1 = 1;\r\n sMappedV1 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 2);\r\n nMappedDim2 = 1;\r\n sMappedV2 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 3);\r\n nMappedDim3 = 1;\r\n sMappedV3 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 4);\r\n nMappedDim4 = 1;\r\n sMappedV4 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 5);\r\n nMappedDim5 = 1;\r\n sMappedV5 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 6);\r\n nMappedDim6 = 1;\r\n sMappedV6 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 7);\r\n nMappedDim7 = 1;\r\n sMappedV7 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 8);\r\n nMappedDim8 = 1;\r\n sMappedV8 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 9);\r\n nMappedDim9 = 1;\r\n sMappedV9 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 10);\r\n nMappedDim10 = 1;\r\n sMappedV10 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 11);\r\n nMappedDim11 = 1;\r\n sMappedV11 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 12);\r\n nMappedDim12 = 1;\r\n sMappedV12 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 13);\r\n nMappedDim13 = 1;\r\n sMappedV13 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 14);\r\n nMappedDim14 = 1;\r\n sMappedV14 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 15);\r\n nMappedDim15 = 1;\r\n sMappedV15 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 16);\r\n nMappedDim16 = 1;\r\n sMappedV16 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 17);\r\n nMappedDim17 = 1;\r\n sMappedV17 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 18);\r\n nMappedDim18 = 1;\r\n sMappedV18 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 19);\r\n nMappedDim19 = 1;\r\n sMappedV19 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 20);\r\n nMappedDim20 = 1;\r\n sMappedV20 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 21);\r\n nMappedDim21 = 1;\r\n sMappedV21 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 22);\r\n nMappedDim22 = 1;\r\n sMappedV22 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 23);\r\n nMappedDim23 = 1;\r\n sMappedV23 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 24);\r\n nMappedDim24 = 1;\r\n sMappedV24 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 25);\r\n nMappedDim25 = 1;\r\n sMappedV25 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 26);\r\n nMappedDim26 = 1;\r\n sMappedV26 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 27);\r\n nMappedDim27 = 1;\r\n sMappedV27 = 'V' | NumberToString(nSourceIndex);\r\n EndIf;\r\n ElseIf( pFile > 0 );\r\n ## If using source file first variable holds tha cube name, so all the other ones have the index increased by 1\r\n If(nTargetIndex = 1);\r\n nMappedDim1 = 1;\r\n sMappedV1 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 2);\r\n nMappedDim2 = 1;\r\n sMappedV2 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 3);\r\n nMappedDim3 = 1;\r\n sMappedV3 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 4);\r\n nMappedDim4 = 1;\r\n sMappedV4 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 5);\r\n nMappedDim5 = 1;\r\n sMappedV5 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 6);\r\n nMappedDim6 = 1;\r\n sMappedV6 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 7);\r\n nMappedDim7 = 1;\r\n sMappedV7 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 8);\r\n nMappedDim8 = 1;\r\n sMappedV8 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 9);\r\n nMappedDim9 = 1;\r\n sMappedV9 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 10);\r\n nMappedDim10 = 1;\r\n sMappedV10 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 11);\r\n nMappedDim11 = 1;\r\n sMappedV11 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 12);\r\n nMappedDim12 = 1;\r\n sMappedV12 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 13);\r\n nMappedDim13 = 1;\r\n sMappedV13 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 14);\r\n nMappedDim14 = 1;\r\n sMappedV14 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 15);\r\n nMappedDim15 = 1;\r\n sMappedV15 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 16);\r\n nMappedDim16 = 1;\r\n sMappedV16 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 17);\r\n nMappedDim17 = 1;\r\n sMappedV17 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 18);\r\n nMappedDim18 = 1;\r\n sMappedV18 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 19);\r\n nMappedDim19 = 1;\r\n sMappedV19 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 20);\r\n nMappedDim20 = 1;\r\n sMappedV20 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 21);\r\n nMappedDim21 = 1;\r\n sMappedV21 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 22);\r\n nMappedDim22 = 1;\r\n sMappedV22 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 23);\r\n nMappedDim23 = 1;\r\n sMappedV23 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 24);\r\n nMappedDim24 = 1;\r\n sMappedV24 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 25);\r\n nMappedDim25 = 1;\r\n sMappedV25 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 26);\r\n nMappedDim26 = 1;\r\n sMappedV26 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 27);\r\n nMappedDim27 = 1;\r\n sMappedV27 = 'V' | NumberToString(nSourceIndex + 1);\r\n EndIf;\r\n EndIf;\r\n\r\n EndIf;\r\n\r\n nTargetIndex = nTargetIndex + 1;\r\n\r\n END;\r\n\r\n nSourceIndex = nSourceIndex + 1;\r\n\r\nEND;\r\n\r\n# The last variable in the data source holds the values\r\n# which need to be mapped to the last variable in the target\r\n\r\nIf( pFile = 0 );\r\n If(nTargetIndex = 1);\r\n nMappedDim1 = 1;\r\n sMappedV1 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 2);\r\n nMappedDim2 = 1;\r\n sMappedV2 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 3);\r\n nMappedDim3 = 1;\r\n sMappedV3 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 4);\r\n nMappedDim4 = 1;\r\n sMappedV4 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 5);\r\n nMappedDim5 = 1;\r\n sMappedV5 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 6);\r\n nMappedDim6 = 1;\r\n sMappedV6 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 7);\r\n nMappedDim7 = 1;\r\n sMappedV7 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 8);\r\n nMappedDim8 = 1;\r\n sMappedV8 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 9);\r\n nMappedDim9 = 1;\r\n sMappedV9 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 10);\r\n nMappedDim10 = 1;\r\n sMappedV10 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 11);\r\n nMappedDim11 = 1;\r\n sMappedV11 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 12);\r\n nMappedDim12 = 1;\r\n sMappedV12 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 13);\r\n nMappedDim13 = 1;\r\n sMappedV13 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 14);\r\n nMappedDim14 = 1;\r\n sMappedV14 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 15);\r\n nMappedDim15 = 1;\r\n sMappedV15 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 16);\r\n nMappedDim16 = 1;\r\n sMappedV16 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 17);\r\n nMappedDim17 = 1;\r\n sMappedV17 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 18);\r\n nMappedDim18 = 1;\r\n sMappedV18 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 19);\r\n nMappedDim19 = 1;\r\n sMappedV19 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 20);\r\n nMappedDim20 = 1;\r\n sMappedV20 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 21);\r\n nMappedDim21 = 1;\r\n sMappedV21 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 22);\r\n nMappedDim22 = 1;\r\n sMappedV22 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 23);\r\n nMappedDim23 = 1;\r\n sMappedV23 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 24);\r\n nMappedDim24 = 1;\r\n sMappedV24 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 25);\r\n nMappedDim25 = 1;\r\n sMappedV25 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 26);\r\n nMappedDim26 = 1;\r\n sMappedV26 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 27);\r\n nMappedDim27 = 1;\r\n sMappedV27 = 'V' | NumberToString(nSourceIndex);\r\n \r\n # a cube with 27 dimensions uses V28 to hold the values\r\n ElseIf(nTargetIndex = 28);\r\n nMappedDim28 = 1;\r\n sMapped28 = 'V' | NumberToString(nSourceIndex);\r\n EndIf;\r\nElseIf( pFile > 0 );\r\n If(nTargetIndex = 1);\r\n nMappedDim1 = 1;\r\n sMappedV1 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 2);\r\n nMappedDim2 = 1;\r\n sMappedV2 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 3);\r\n nMappedDim3 = 1;\r\n sMappedV3 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 4);\r\n nMappedDim4 = 1;\r\n sMappedV4 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 5);\r\n nMappedDim5 = 1;\r\n sMappedV5 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 6);\r\n nMappedDim6 = 1;\r\n sMappedV6 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 7);\r\n nMappedDim7 = 1;\r\n sMappedV7 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 8);\r\n nMappedDim8 = 1;\r\n sMappedV8 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 9);\r\n nMappedDim9 = 1;\r\n sMappedV9 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 10);\r\n nMappedDim10 = 1;\r\n sMappedV10 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 11);\r\n nMappedDim11 = 1;\r\n sMappedV11 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 12);\r\n nMappedDim12 = 1;\r\n sMappedV12 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 13);\r\n nMappedDim13 = 1;\r\n sMappedV13 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 14);\r\n nMappedDim14 = 1;\r\n sMappedV14 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 15);\r\n nMappedDim15 = 1;\r\n sMappedV15 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 16);\r\n nMappedDim16 = 1;\r\n sMappedV16 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 17);\r\n nMappedDim17 = 1;\r\n sMappedV17 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 18);\r\n nMappedDim18 = 1;\r\n sMappedV18 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 19);\r\n nMappedDim19 = 1;\r\n sMappedV19 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 20);\r\n nMappedDim20 = 1;\r\n sMappedV20 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 21);\r\n nMappedDim21 = 1;\r\n sMappedV21 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 22);\r\n nMappedDim22 = 1;\r\n sMappedV22 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 23);\r\n nMappedDim23 = 1;\r\n sMappedV23 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 24);\r\n nMappedDim24 = 1;\r\n sMappedV24 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 25);\r\n nMappedDim25 = 1;\r\n sMappedV25 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 26);\r\n nMappedDim26 = 1;\r\n sMappedV26 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 27);\r\n nMappedDim27 = 1;\r\n sMappedV27 = 'V' | NumberToString(nSourceIndex + 1);\r\n \r\n # a cube with 27 dimensions uses V29 to hold the values if export file is used as source\r\n ElseIf(nTargetIndex = 28);\r\n nMappedDim28 = 1;\r\n sMapped28 = 'V' | NumberToString(nSourceIndex + 1);\r\n EndIf;\r\nEndIf;\r\n#EndRegion\r\n\r\n###########################################\r\n### SPLIT MAPPING TO NEW DIMS PARAMETER ###\r\n###########################################\r\n\r\n# now deduct 1 to set these indices to the number of dimensions in each cube\r\nnSourceDimensionCount = nSourceIndex - 1;\r\nnTargetCubeDimensionCount = nTargetIndex - 1;\r\n# default dimension count is for target\r\nnDimensionCount = nTargetIndex - 1;\r\n\r\nsElementMapping = TRIM( pMappingToNewDims );\r\nnChar = 1;\r\nnCharCount = LONG( sElementMapping );\r\n\r\nsTargetFilter = '';\r\nsWord = '';\r\nsLastDelim = '';\r\nnIndex = 1;\r\n\r\n# Add a trailing element delimiter so that the last element is picked up\r\nIf( nCharCount > 0 );\r\n sElementMapping = sElementMapping | sDelimDim;\r\n nCharCount = nCharCount + LONG(sDelimDim);\r\nEndIf;\r\n\r\nWHILE (nChar <= nCharCount);\r\n sChar = SUBST( sElementMapping, nChar, 1);\r\n\r\n # Used for delimiters, required for multiple character delimiters\r\n sDelim = '';\r\n nAddExtra = 0;\r\n\r\n # Ignore spaces\r\n IF (TRIM(sChar) @<> '' );\r\n\r\n ### Dimension Name ###\r\n\r\n # If the delimiter is more than 1 character peek ahead the same amount\r\n # Ignore the first character\r\n sDelim = sChar;\r\n nCount = LONG(sElementStartDelim) - 1;\r\n If( nCount > 0 & nChar + nCount <= nCharCount );\r\n # Add the extra characters\r\n sDelim = sDelim | SUBST( sElementMapping, nChar + 1, nCount);\r\n # Move to the end of the delimter\r\n nAddExtra = nCount;\r\n EndIf;\r\n\r\n If( sDelim @= sElementStartDelim );\r\n\r\n sChar = sDelim;\r\n\r\n If( sLastDelim @<> '' & sLastDelim @<> sDelimDim );\r\n sMessage = 'In pMappingToNewDims the name of a dimension must follow a dimension delimiter (' | sDelimDim | ')';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n #ProcessError();\r\n EndIf;\r\n\r\n # Found a dimension\r\n sDimension = sWord;\r\n\r\n If( DimensionExists( sDimension ) = 0 );\r\n # The dimension does not exist in the model. Cancel process\r\n sMessage = 'In pMappingToNewDims - Dimension: ' | sDimension | ' does not exist';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n #ProcessError();\r\n EndIf;\r\n\r\n # Find the index of the dimension is in the Target cube\r\n nTargetIndexCounter = 1;\r\n\r\n WHILE(nTargetIndexCounter <= nTargetCubeDimensionCount );\r\n sNthDimension = TabDim( pTgtCube, nTargetIndexCounter );\r\n\r\n If(sDimension @= sNthDimension);\r\n nTargetIndex = nTargetIndexCounter;\r\n nTargetIndexCounter = 1000;\r\n EndIf;\r\n\r\n nTargetIndexCounter = nTargetIndexCounter + 1;\r\n END;\r\n \r\n #Add to the Target filter\r\n IF(sTargetFilter@='');\r\n sTargetFilter=sDimension; \r\n Else;\r\n sTargetFilter=sTargetFilter|sDelimDim|sDimension;\r\n Endif; \r\n \r\n sLastDelim = sChar;\r\n # Clear the word\r\n sWord = '';\r\n\r\n Else;\r\n\r\n # Reset extra chars\r\n nAddExtra = 0;\r\n\r\n ### Check both dim delimiter and element delimiter ###\r\n nIsDelimiter = 0;\r\n\r\n ## Check dimension delimiter first\r\n # If the delimiter is more than 1 character peek ahead the same amount\r\n # Ignore the first character\r\n sDelim = sChar;\r\n nCount = LONG(sDelimDim) - 1;\r\n If( nCount > 0 & nChar + nCount <= nCharCount );\r\n # Add the extra characters\r\n sDelim = sDelim | SUBST( sElementMapping, nChar + 1, nCount);\r\n EndIf;\r\n\r\n If( sDelim @= sDelimDim );\r\n nIsDelimiter = 1;\r\n sChar = sDelim;\r\n \r\n # Move to the end of the delimter\r\n nAddExtra = nCount;\r\n EndIf;\r\n\r\n If ( nIsDelimiter = 1 );\r\n\r\n If( sLastDelim @= '' % sLastDelim @= sDelimDim );\r\n sMessage = 'In pMappingToNewDims - an element delimiter must follow a dimension name: ' | sChar | ' (' | NumberToString(nChar) | ')';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n #ProcessError();\r\n EndIf;\r\n\r\n # an element has been found\r\n sElement = sWord;\r\n\r\n If( DIMIX( sDimension, sElement ) = 0 );\r\n # The element does not exist in the dimension. Cancel process\r\n sMessage = 'In pMappingToNewDims - Element: ' | sElement | ' in dimension ' | sDimension | ' does not exist';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n #ProcessError();\r\n EndIf;\r\n\r\n # Allow consolidations only if pSuppressConsol is set to 0\r\n\r\n If ( DTYPE( sDimension, sElement) @= 'C' );\r\n sMessage = Expand( 'In pMappingToNewDims - Target element: %sElement% for dimension %sDimension% is consolidated' );\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n #ProcessError();\r\n Endif; \r\n \r\n\r\n # Add the element to the source or target depending on whether it's the first or the second element\r\n # Get principal name\r\n # in case source element and this element are using different aliases\r\n\r\n sElement = DimensionElementPrincipalName(sDimension,sElement);\r\n\r\n ### Update the variable for InputElement Target Dim ######################################\r\n If(nTargetIndex = 1);\r\n nNewDim1 = 1;\r\n sNewV1 = sElement;\r\n ElseIf(nTargetIndex = 2);\r\n nNewDim2 = 1;\r\n sNewV2 = sElement;\r\n ElseIf(nTargetIndex = 3);\r\n nNewDim3 = 1;\r\n sNewV3 = sElement;\r\n ElseIf(nTargetIndex = 4);\r\n nNewDim4 = 1;\r\n sNewV4 = sElement;\r\n ElseIf(nTargetIndex = 5);\r\n nNewDim5 = 1;\r\n sNewV5 = sElement;\r\n ElseIf(nTargetIndex = 6);\r\n nNewDim6 = 1;\r\n sNewV6 = sElement;\r\n ElseIf(nTargetIndex = 7);\r\n nNewDim7 = 1;\r\n sNewV7 = sElement;\r\n ElseIf(nTargetIndex = 8);\r\n nNewDim8 = 1;\r\n sNewV8 = sElement;\r\n ElseIf(nTargetIndex = 9);\r\n nNewDim9 = 1;\r\n sNewV9 = sElement;\r\n ElseIf(nTargetIndex = 10);\r\n nNewDim10 = 1;\r\n sNewV10 = sElement;\r\n ElseIf(nTargetIndex = 11);\r\n nNewDim11 = 1;\r\n sNewV11 = sElement;\r\n ElseIf(nTargetIndex = 12);\r\n nNewDim12 = 1;\r\n sNewV12 = sElement;\r\n ElseIf(nTargetIndex = 13);\r\n nNewDim13 = 1;\r\n sNewV13 = sElement;\r\n ElseIf(nTargetIndex = 14);\r\n nNewDim14 = 1;\r\n sNewV14 = sElement;\r\n ElseIf(nTargetIndex = 15);\r\n nNewDim15 = 1;\r\n sNewV15 = sElement;\r\n ElseIf(nTargetIndex = 16);\r\n nNewDim16 = 1;\r\n sNewV16 = sElement;\r\n ElseIf(nTargetIndex = 17);\r\n nNewDim17 = 1;\r\n sNewV17 = sElement;\r\n ElseIf(nTargetIndex = 18);\r\n nNewDim18 = 1;\r\n sNewV18 = sElement;\r\n ElseIf(nTargetIndex = 19);\r\n nNewDim19 = 1;\r\n sNewV19 = sElement;\r\n ElseIf(nTargetIndex = 20);\r\n nNewDim20 = 1;\r\n sNewV20 = sElement;\r\n ElseIf(nTargetIndex = 21);\r\n nNewDim21 = 1;\r\n sNewV21 = sElement;\r\n ElseIf(nTargetIndex = 22);\r\n nNewDim22 = 1;\r\n sNewV22 = sElement;\r\n ElseIf(nTargetIndex = 23);\r\n nNewDim23 = 1;\r\n sNewV23 = sElement;\r\n ElseIf(nTargetIndex = 24);\r\n nNewDim24 = 1;\r\n sNewV24 = sElement;\r\n ElseIf(nTargetIndex = 25);\r\n nNewDim25 = 1;\r\n sNewV25 = sElement;\r\n ElseIf(nTargetIndex = 26);\r\n nNewDim26 = 1;\r\n sNewV26 = sElement;\r\n ElseIf(nTargetIndex = 27);\r\n nNewDim27 = 1;\r\n sNewV27 = sElement;\r\n EndIf;\r\n\r\n #Add to the Target filter\r\n sTargetFilter=sTargetFilter|sElementStartDelim|sElement;\r\n \r\n # Clear the word\r\n sWord = '';\r\n sLastDelim = sChar;\r\n \r\n Else;\r\n sWord = sWord | sChar;\r\n EndIf;\r\n\r\n EndIf;\r\n\r\n EndIf;\r\n\r\n nChar = nChar + nAddExtra + 1;\r\n\r\nEND;\r\n\r\n# Check that an input element or variable has been specified for all dimensions in the target cube\r\n\r\nnIndexInTarget = 1;\r\nWHILE(nIndexInTarget <= nTargetCubeDimensionCount);\r\n \r\n sMapped = Expand('%nMappedDim'| NumberToString(nIndexInTarget) |'%'); \r\n sMapped = Subst( sMapped , Scan( '.' , sMapped )-1 , 99);\r\n nMapped = StringToNumber( Trim( sMapped ) );\r\n sNew = Expand('%nNewDim'| NumberToString(nIndexInTarget) |'%'); \r\n sNew = Subst( sNew , Scan( '.' , sNew )-1 , 99);\r\n nNew = StringToNumber( Trim( sNew ) );\r\n \r\n If(nMapped = 0 & nNew = 0 );\r\n # there's no input element and this dimension is not in the source\r\n nErrors = nErrors + 1;\r\n sTargetDimName = TabDim( pTgtCube, nIndexInTarget );\r\n sMessage = 'Dimension ' | sTargetDimName | ' is missing an input element in pMappingToNewDims';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n EndIf;\r\n \r\n nIndexInTarget = nIndexInTarget + 1;\r\nEND;\r\n\r\n\r\n############################# Clear out target ################################\r\n\r\n# Target is cleared for the elements specified in pMappingToNewDims\r\n# and for the parts of pFilter for dimensions in the target\r\n# This code works through pFilter looking for the parts relating to the target cube\r\n# the code which finds individual elements has been left in\r\n# so that it can be changed later to deal with consolidated elements\r\n\r\nsFilter = TRIM( pFilter );\r\nnChar = 1;\r\nnCharCount = LONG( sFilter );\r\nsWord = '';\r\nsLastDelim = '';\r\n\r\n# Add a trailing element delimiter so that the last Dimension:Element/s clause is picked up\r\nIf( nCharCount > 0 );\r\n sFilter = sFilter | sDelimElem;\r\n nCharCount = nCharCount + LONG(sDelimElem);\r\nEndIf;\r\n\r\nWHILE (nChar <= nCharCount);\r\n\r\n sChar = SUBST( sFilter, nChar, 1);\r\n\r\n # Used for delimiters, required for multiple character dilimiters\r\n sDelim = '';\r\n nAddExtra = 0;\r\n\r\n # Ignore spaces\r\n IF (TRIM(sChar) @<> '' );\r\n\r\n ### Dimension Name ###\r\n\r\n # If the delimiter is more than 1 character peek ahead the same amount\r\n # Ignore the first character\r\n sDelim = sChar;\r\n nCount = LONG(sElementStartDelim) - 1;\r\n If( nCount > 0 & nChar + nCount <= nCharCount );\r\n # Add the extra characters\r\n sDelim = sDelim | SUBST( sFilter, nChar + 1, nCount);\r\n # Move to the end of the delimter\r\n nAddExtra = nCount;\r\n EndIf;\r\n\r\n If( sDelim @= sElementStartDelim );\r\n\r\n sChar = sDelim;\r\n\r\n If( sLastDelim @<> '' & sLastDelim @<> sDelimDim );\r\n sMessage = 'In pFilter - the name of a dimension must follow a dimension delimiter (' | sDelimDim | ')';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n #ProcessError();\r\n EndIf;\r\n\r\n # Found a dimension!\r\n sDimension = UPPER( sWord );\r\n nDimInTgt=0;\r\n # See if the dimension is in the target cube\r\n IF(scan('^^'|sDimension|'^^', sTgtDimString)>0);\r\n If(sTargetFilter@='');\r\n sTargetFilter = sDimension;\r\n Else; \r\n sTargetFilter = sTargetFilter | sDelimDim | sDimension;\r\n endif;\r\n nDimInTgt=1;\r\n Endif; \r\n\r\n sLastDelim = sChar;\r\n # Clear the word\r\n sWord = '';\r\n #reset element count\r\n nElementCount = 1;\r\n\r\n Else;\r\n\r\n # Reset extra chars\r\n nAddExtra = 0;\r\n\r\n ### Check both both dim delimiter and element delimiter ###\r\n nIsDelimiter = 0;\r\n\r\n ## Check dimension delimiter first\r\n # If the delimiter is more than 1 character peek ahead the same amount\r\n # Ignore the first character\r\n sDelim = sChar;\r\n nCount = LONG(sDelimDim) - 1;\r\n If( nCount > 0 & nChar + nCount <= nCharCount );\r\n # Add the extra characters\r\n sDelim = sDelim | SUBST( sFilter, nChar + 1, nCount);\r\n # Move to the end of the delimter\r\n nAddExtra = nCount;\r\n EndIf;\r\n\r\n If( sDelim @= sDelimDim );\r\n nIsDelimiter = 1;\r\n sChar = sDelim;\r\n Else;\r\n # Reset extra chars\r\n nAddExtra = 0;\r\n\r\n ## Check element delimiter\r\n\r\n # If the delimiter is more than 1 character peek ahead the same amount\r\n # Ignore the first character\r\n sDelim = sChar;\r\n nCount = LONG(sDelimElem) - 1;\r\n If( nCount > 0 & nChar + nCount <= nCharCount );\r\n # Add the extra characters\r\n sDelim = sDelim | SUBST( sFilter, nChar + 1, nCount);\r\n # Move to the end of the delimter\r\n nAddExtra = nCount;\r\n EndIf;\r\n\r\n If( sDelim @= sDelimElem );\r\n nIsDelimiter = 1;\r\n sChar = sDelim;\r\n Else;\r\n # Reset extra chars\r\n nAddExtra = 0;\r\n EndIf;\r\n\r\n EndIf;\r\n\r\n If ( nIsDelimiter = 1 );\r\n\r\n If( sLastDelim @= '' % sLastDelim @= sDelimDim );\r\n sMessage = 'In pFilter - an element delimiter must follow a dimension name: ' | sChar | ' (' | NumberToString(nChar) | ')';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n #ProcessError();\r\n EndIf;\r\n\r\n # Found an element\r\n sElement = sWord;\r\n\r\n IF(DIMIX(sDimension, sElement) > 0 & nDimInTgt=1);\r\n # first element\r\n IF(nElementCount = 1);\r\n sTargetFilter = sTargetFilter | sElementStartDelim | sElement;\r\n # later elements\r\n Else;\r\n sTargetFilter = sTargetFilter | sDelimElem | sElement;\r\n EndIf;\r\n EndIf;\r\n\r\n nElementCount = nElementCount + 1;\r\n sLastDelim = sChar;\r\n\r\n # Clear the word\r\n sWord = '';\r\n Else;\r\n sWord = sWord | sChar;\r\n EndIf;\r\n\r\n EndIf;\r\n\r\n EndIf;\r\n\r\n nChar = nChar + nAddExtra + 1;\r\n\r\nEND;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n# Branch depending on whether to do recursive calls to self on independent threads or run all in this thread\r\nIf( Scan( pEleStartDelim, pFilterParallel ) > 0 );\r\n sDimParallel = SubSt( pFilterParallel, 1, Scan( pEleStartDelim, pFilterParallel ) - 1 );\r\n sElementList = SubSt( pFilterParallel, Scan( pEleStartDelim, pFilterParallel ) + 1, Long( pFilterParallel ) );\r\n If( SubSt( sElementList, Long( sElementList ), 1 ) @<> pEleDelim );\r\n sElementList = sElementList | pEleDelim;\r\n EndIf;\r\n ## Counting elements in element list\r\n sElementListCount = sElementList;\r\n nElements = 0;\r\n While( Scan( pEleDelim, sElementListCount ) > 0 );\r\n nElements = nElements + 1;\r\n sElementListCount = SubSt( sElementListCount, Scan( pEleDelim, sElementListCount ) + 1, Long( sElementListCount ) );\r\n End;\r\n IF( Mod( nElements, nMaxThreads ) = 0 );\r\n nElemsPerThread = INT( nElements / nMaxThreads );\r\n ELSE;\r\n nElemsPerThread = INT( nElements / nMaxThreads ) + 1;\r\n ENDIF;\r\n nThreadElCounter = 0;\r\n While( Scan( pEleDelim, sElementList ) > 0 );\r\n sSlicerEle = SubSt( sElementList, 1, Scan( pEleDelim, sElementList ) - 1 );\r\n sElementList = SubSt( sElementList, Scan( pEleDelim, sElementList ) + 1, Long( sElementList ) );\r\n # Do recursive process call with new RunProcess function\r\n nThreadElCounter = nThreadElCounter + 1;\r\n sDimDelim = If(pFilter @= '', '', pDimDelim );\r\n IF( nThreadElCounter = 1 );\r\n sFilter = Expand('%pFilter%%sDimDelim%%sDimParallel%%pEleStartDelim%%sSlicerEle%');\r\n ELSE;\r\n sFilter = Expand('%sFilter%%pEleDelim%%sSlicerEle%');\r\n ENDIF;\r\n IF( nThreadElCounter >= nElemsPerThread );\r\n RunProcess( cThisProcName, 'pLogoutput', pLogoutput,\r\n \t'pSrcCube', pSrcCube, 'pFilter', sFilter, 'pFilterParallel', '', 'pTgtCube', pTgtCube, 'pMappingToNewDims', pMappingToNewDims,\r\n \t'pSuppressConsol', pSuppressConsol, 'pSuppressConsolStrings', pSuppressConsolStrings, 'pSuppressRules', pSuppressRules, 'pSuppressZero', pSuppressZero, 'pZeroTarget', pZeroTarget, 'pZeroSource', pZeroSource,\r\n 'pFactor', pFactor, 'pDimDelim', pDimDelim, 'pEleStartDelim', pEleStartDelim, 'pEleDelim', pEleDelim,\r\n 'pTemp', pTemp, 'pCubeLogging', pCubeLogging, 'pSandbox', pSandbox, 'pFile', pFile, 'pThreadMode', 1\r\n );\r\n \t nThreadElCounter = 0;\r\n \t sFilter = '';\r\n \t ENDIF;\r\n End;\r\n ## Process last elements - only when filter is not empty (there are still elements)\r\n IF( sFilter @<> '' );\r\n RunProcess( cThisProcName, 'pLogoutput', pLogoutput,\r\n \t'pSrcCube', pSrcCube, 'pFilter', sFilter, 'pFilterParallel', '', 'pTgtCube', pTgtCube, 'pMappingToNewDims', pMappingToNewDims,\r\n \t'pSuppressConsol', pSuppressConsol, 'pSuppressConsolStrings', pSuppressConsolStrings, 'pSuppressRules', pSuppressRules, 'pSuppressZero', pSuppressZero, 'pZeroTarget', pZeroTarget, 'pZeroSource', pZeroSource,\r\n 'pFactor', pFactor, 'pDimDelim', pDimDelim, 'pEleStartDelim', pEleStartDelim, 'pEleDelim', pEleDelim,\r\n 'pTemp', pTemp, 'pCubeLogging', pCubeLogging, 'pSandbox', pSandbox, 'pFile', pFile, 'pThreadMode', 1\r\n );\r\n ENDIF; \r\n DataSourceType = 'NULL';\r\nElse;\r\n # Clear out target view\r\n If(pZeroTarget = 1 & LONG(sTargetFilter)>= 0 & nErrors = 0);\r\n ###### Create View of target to clear out ###\r\n # Create View of target ###\r\n nRet = ExecuteProcess('}bedrock.cube.view.create',\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pCube', pTgtCube,\r\n 'pView', sTargetView ,\r\n 'pFilter', sTargetFilter,\r\n 'pSuppressZero', pSuppressZero,\r\n 'pSuppressConsol', pSuppressConsol,\r\n 'pSuppressRules', pSuppressRules,\r\n 'pSuppressConsolStrings', pSuppressConsolStrings, \r\n 'pDimDelim', pDimDelim,\r\n 'pEleStartDelim', pEleStartDelim,\r\n 'pEleDelim', pEleDelim ,\r\n 'pTemp', pTemp\r\n );\r\n \r\n IF(nRet <> 0);\r\n sMessage = 'Error creating the view from the filter.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n ENDIF;\r\n \r\n nRet = ExecuteProcess( '}bedrock.cube.data.clear',\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pCube', pTgtCube,\r\n 'pView', sTargetView,\r\n 'pFilter', sTargetFilter,\r\n 'pDimDelim', pDimDelim,\r\n 'pEleStartDelim', pEleStartDelim,\r\n 'pEleDelim', pEleDelim,\r\n 'pTemp', pTemp,\r\n 'pCubeLogging', pCubeLogging,\r\n 'pSandbox', pSandbox\r\n );\r\n \r\n IF(nRet <> 0);\r\n sMessage = 'Error clearing the target view.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n ENDIF;\r\n \r\n Endif;\r\n \r\n If( pFile = 0 );\r\n ### Create View of Source ###\r\n IF(pSuppressConsol = 0 & pSuppressConsolStrings = 1);\r\n pSubN=1;\r\n else;\r\n pSubN=0;\r\n Endif; \r\n \r\n nRet = ExecuteProcess('}bedrock.cube.view.create',\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pCube', pSrcCube,\r\n 'pView', sView,\r\n 'pFilter', pFilter,\r\n 'pSuppressZero', pSuppressZero,\r\n 'pSuppressConsol', pSuppressConsol,\r\n 'pSuppressRules', pSuppressRules,\r\n 'pSuppressConsolStrings', pSuppressConsolStrings, \r\n 'pDimDelim', pDimDelim,\r\n 'pEleStartDelim', pEleStartDelim,\r\n 'pEleDelim', pEleDelim ,\r\n 'pTemp', pTemp,\r\n 'pSubN', pSubN\r\n );\r\n \r\n IF(nRet <> 0);\r\n sMessage = 'Error creating the view from the filter.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n ENDIF;\r\n \r\n ElseIf( pFile > 0 );\r\n ### Export to File in case of Copy Data Via File ###\r\n IF(pSuppressConsol = 0);\r\n pSubN=1;\r\n else;\r\n pSubN=0;\r\n Endif; \r\n \r\n nRet = ExecuteProcess('}bedrock.cube.data.export',\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pCube', pSrcCube,\r\n 'pView', sView,\r\n 'pFilter', pFilter,\r\n 'pFilterParallel', '',\r\n 'pParallelThreads', 0,\r\n 'pDimDelim', pDimDelim,\r\n 'pEleStartDelim', pEleStartDelim,\r\n 'pEleDelim', pEleDelim,\r\n 'pSuppressZero', pSuppressZero,\r\n 'pSuppressConsol', pSuppressConsol,\r\n 'pSuppressRules', pSuppressRules,\r\n 'pSuppressConsolStrings', pSuppressConsolStrings, \r\n 'pZeroSource', 0,\r\n 'pCubeLogging', pCubeLogging,\r\n 'pTemp', pTemp,\r\n 'pFilePath', cDir,\r\n 'pFileName', cFileName,\r\n 'pDelim', cDelimiter,\r\n 'pDecimalSeparator', sDecimalSeparator,\r\n 'pThousandSeparator', sThousandSeparator,\r\n 'pQuote', cQuote,\r\n 'pTitleRecord', cTitleRows,\r\n 'pSandbox', pSandbox,\r\n 'pSubN', pSubN\r\n );\r\n \r\n IF(nRet <> 0);\r\n sMessage = 'Error exporting data to file.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n ENDIF;\r\n ENDIF;\r\n \r\n ### Assign Datasource ###\r\n If( pFile = 0 );\r\n DataSourceType = 'VIEW';\r\n DatasourceNameForServer = pSrcCube;\r\n DatasourceNameForClient = pSrcCube;\r\n DatasourceCubeView = sView;\r\n ElseIf( pFile > 0 );\r\n DataSourceType = 'CHARACTERDELIMITED';\r\n DatasourceNameForServer = cFile;\r\n DatasourceNameForClient = cFile;\r\n DatasourceASCIIHeaderRecords = cTitleRows;\r\n DatasourceASCIIDelimiter = cDelimiter;\r\n DatasourceASCIIQuoteCharacter = cQuote;\r\n EndIf;\r\nEndIf;\r\n\r\n### End Prolog ###", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.cube.data.copy.intercube', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pSrcCube', '', 'pFilter', '',\r\n \t'pFilterParallel', '', 'pParallelThreads', 0,\r\n \t'pTgtCube', '', 'pMappingToNewDims', '',\r\n \t'pSuppressConsol', 1, 'pSuppressConsolStrings', 0, 'pSuppressRules', 1, 'pSuppressZero', 1, \r\n \t'pZeroTarget', 1, 'pZeroSource', 0,\r\n \t'pFactor', 1,\r\n \t'pDimDelim', '&', 'pEleStartDelim', '\u00a6', 'pEleDelim', '+',\r\n \t'pTemp', 1, 'pCubeLogging', 0, 'pSandbox', pSandbox, 'pSubN', 0, \r\n \t'pFile', 0, 'pDelim', ',', 'pQuote', '\"', 'pDecimalSeparator', '.', 'pThousandSeparator', ','\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# ## Description\r\n# This is the process used to copy data from a source cube to a different target cube.\r\n# \r\n# ## Use Cases \r\n# 1. This process could be used to populate a Reporting cube from multiple source cubes.\r\n# 2. The process could be used to archive data from one cube to another one for any use.\r\n#\r\n# ## Notes\r\n# * The target cube may have a different number of dimensions as the source cube.\r\n# * Where the target and source cubes share the same dimensions, the process will match the dimensions even if their position in the cube is different.\r\n# * An input element must be specified for each dimension which is in the target but not in the source using the parameter pMappingToNewDims.\r\n# * The format of parameter pMappingToNewDims using default delimiters & and : is DimInTargetButNotSource1:ElementOfDim & DimInTargetButNotSource2:ElementOfDim.\r\n# * The input element must be an N level unless pSuppressConsol is set to 0.\r\n# * The maximum number of dimensions catered for in the target cube is 27. (In principle adding support for cubes with higher dimensionality is not difficult).\r\n#\r\n# For dimensions in the source but not the target, the process will accumulate the values of all n level elements\r\n# (or all n level elements specified by the pFilter parameter).\r\n# The pFilter parameter contains the dimensions and elements to be used for filtering the source cube.\r\n# The format of the pFilter parameter is as follows, using default delimiters & + : Dim1: Elem1 + Elem2 & Dim2: Elem3 + Elem4.\r\n# The dimension parameters do not need to be given in the index order of dimensions in the cube.\r\n# The dimension name is specified as the first member of the delimited string of elements.\r\n# If consolidations are skipped the N level children of any consolidated filter elements will be used.\r\n# Spaces are ignored so use them to make your filter more readable.\r\n# If using the pFilterParallel parameter the **single dimension** used as the \"parallelization slicer\" cannot appear in\r\n# the pFilter parameters.\r\n# When using parallelization via the *RunProcess* function the elements listed in pFilterParallel will be split one_at_a_time\r\n# and passed to a recursive call of the process being added to pFilter.\r\n#\r\n# An example:\r\n# To copy the 2011 Actual Sales data from the Sales cube to the General Ledger cube set pFilter to Year: 2011 & Version: Actual.\r\n# Say the General Ledger cube has an Account dimension but the Sales cube doesn't and the Account for sales is 9999 (an n level element).\r\n# Set the pMappingToNewDims parameter to Account:9999.\r\n# This will copy all Actual 2011 Sales to Account 9999 in the General Ledger.\r\n# If only sales for Company X are to be copied, set pFilter to Year: 2011 & Version: Actual & Company:X.\r\n# If sales from other companies are already in the General Ledger set pZeroTarget to 0 to add Company X's data to the existing data.\r\n# Setting pZeroTarget to 1 will clear our data in the target cube for the elements specified in the\r\n# pMappingToNewDims parameter and the pFilter parameter for dimensions that are in the target.\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = '%cThisProcName% : %sMessage% : %cUserName%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pSrcCube:%pSrcCube%, pFilter:%pFilter%, pFilterParallel:%pFilterParallel%, pParallelThreads:%pParallelThreads%, pTgtCube:%pTgtCube%, pMappingToNewDims:%pMappingToNewDims%, pSuppressConsol:%pSuppressConsol%, pSuppressConsolStrings:%pSuppressConsolStrings%, pSuppressRules:%pSuppressRules%, pSuppressZero:%pSuppressZero%, pZeroTarget:%pZeroTarget%, pZeroSource:%pZeroSource%, pFactor:%pFactor%, pDimDelim:%pDimDelim%, pEleStartDelim:%pEleStartDelim%, pEleDelim:%pEleDelim%, pTemp:%pTemp%, pCubeLogging:%pCubeLogging%, pSandbox:%pSandbox%, pFile:%pFile%, pThreadMode:%pThreadMode%.';\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pDecimalSeparator\": \".\",\r\n \"pDelim\": \"&\",\r\n \"pDimDelim\": \"&\",\r\n \"pEleDelim\": \"+\",\r\n \"pEleStartDelim\": \"\u00a6\",\r\n \"pFilter\": \"\",\r\n \"pFilterParallel\": \"\",\r\n \"pMappingToNewDims\": \"\",\r\n \"pQuote\": \"\"\",\r\n \"pSandbox\": \"\",\r\n \"pSrcCube\": null,\r\n \"pTgtCube\": null,\r\n \"pThousandSeparator\": \",\",\r\n \"pFactor\": 1,\r\n \"pFile\": 0,\r\n \"pLogOutput\": 0,\r\n \"pParallelThreads\": 0,\r\n \"pStrictErrorHandling\": 0,\r\n \"pSubN\": 0,\r\n \"pSuppressConsol\": 1,\r\n \"pSuppressConsolStrings\": 1,\r\n \"pSuppressRules\": 1,\r\n \"pSuppressZero\": 1,\r\n \"pTemp\": 1,\r\n \"pThreadMode\": 0,\r\n \"pZeroSource\": 0,\r\n \"pZeroTarget\": 1\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pDecimalSeparator\": '|StringToJson ( pDecimalSeparator )|',\r\n \"pDelim\": '|StringToJson ( pDelim )|',\r\n \"pDimDelim\": '|StringToJson ( pDimDelim )|',\r\n \"pEleDelim\": '|StringToJson ( pEleDelim )|',\r\n \"pEleStartDelim\": '|StringToJson ( pEleStartDelim )|',\r\n \"pFilter\": '|StringToJson ( pFilter )|',\r\n \"pFilterParallel\": '|StringToJson ( pFilterParallel )|',\r\n \"pMappingToNewDims\": '|StringToJson ( pMappingToNewDims )|',\r\n \"pQuote\": '|StringToJson ( pQuote )|',\r\n \"pSandbox\": '|StringToJson ( pSandbox )|',\r\n \"pSrcCube\": '|StringToJson ( pSrcCube )|',\r\n \"pTgtCube\": '|StringToJson ( pTgtCube )|',\r\n \"pThousandSeparator\": '|StringToJson ( pThousandSeparator )|',\r\n \"pFactor\": '|NumberToString( pFactor )|',\r\n \"pFile\": '|NumberToString( pFile )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pParallelThreads\": '|NumberToString( pParallelThreads )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|',\r\n \"pSubN\": '|NumberToString( pSubN )|',\r\n \"pSuppressConsol\": '|NumberToString( pSuppressConsol )|',\r\n \"pSuppressConsolStrings\": '|NumberToString( pSuppressConsolStrings )|',\r\n \"pSuppressRules\": '|NumberToString( pSuppressRules )|',\r\n \"pSuppressZero\": '|NumberToString( pSuppressZero )|',\r\n \"pTemp\": '|NumberToString( pTemp )|',\r\n \"pThreadMode\": '|NumberToString( pThreadMode )|',\r\n \"pZeroSource\": '|NumberToString( pZeroSource )|',\r\n \"pZeroTarget\": '|NumberToString( pZeroTarget )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npDecimalSeparator = JsonToString( JsonGet( pJson, 'pDecimalSeparator' ) );\r\npDelim = JsonToString( JsonGet( pJson, 'pDelim' ) );\r\npDimDelim = JsonToString( JsonGet( pJson, 'pDimDelim' ) );\r\npEleDelim = JsonToString( JsonGet( pJson, 'pEleDelim' ) );\r\npEleStartDelim = JsonToString( JsonGet( pJson, 'pEleStartDelim' ) );\r\npFilter = JsonToString( JsonGet( pJson, 'pFilter' ) );\r\npFilterParallel = JsonToString( JsonGet( pJson, 'pFilterParallel' ) );\r\npMappingToNewDims = JsonToString( JsonGet( pJson, 'pMappingToNewDims' ) );\r\npQuote = JsonToString( JsonGet( pJson, 'pQuote' ) );\r\npSandbox = JsonToString( JsonGet( pJson, 'pSandbox' ) );\r\npSrcCube = JsonToString( JsonGet( pJson, 'pSrcCube' ) );\r\npTgtCube = JsonToString( JsonGet( pJson, 'pTgtCube' ) );\r\npThousandSeparator = JsonToString( JsonGet( pJson, 'pThousandSeparator' ) );\r\n# Numeric Parameters\r\npFactor = StringToNumber( JsonToString( JsonGet( pJson, 'pFactor' ) ) );\r\npFile = StringToNumber( JsonToString( JsonGet( pJson, 'pFile' ) ) );\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npParallelThreads = StringToNumber( JsonToString( JsonGet( pJson, 'pParallelThreads' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\npSubN = StringToNumber( JsonToString( JsonGet( pJson, 'pSubN' ) ) );\r\npSuppressConsol = StringToNumber( JsonToString( JsonGet( pJson, 'pSuppressConsol' ) ) );\r\npSuppressConsolStrings = StringToNumber( JsonToString( JsonGet( pJson, 'pSuppressConsolStrings' ) ) );\r\npSuppressRules = StringToNumber( JsonToString( JsonGet( pJson, 'pSuppressRules' ) ) );\r\npSuppressZero = StringToNumber( JsonToString( JsonGet( pJson, 'pSuppressZero' ) ) );\r\npTemp = StringToNumber( JsonToString( JsonGet( pJson, 'pTemp' ) ) );\r\npThreadMode = StringToNumber( JsonToString( JsonGet( pJson, 'pThreadMode' ) ) );\r\npZeroSource = StringToNumber( JsonToString( JsonGet( pJson, 'pZeroSource' ) ) );\r\npZeroTarget = StringToNumber( JsonToString( JsonGet( pJson, 'pZeroTarget' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\nsDelimDim = TRIM(pDimDelim);\r\nsElementStartDelim = TRIM(pElEStartDelim);\r\nsDelimElem = TRIM(pEleDelim);\r\nnErrors = 0;\r\ncLenASCIICode = 3;\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n# Make sure pFactor not zero\r\nnFactor = If( pFactor = 0, 1, pFactor );\r\n\r\nsView = cThisProcName | cTimeStamp | cRandomInt;\r\nsSubset = sView;\r\nsTargetView = 'Target '| sView;\r\nsTargetSubset = sTargetView;\r\n\r\n## check operating system\r\nIf( SubSt( GetProcessErrorFileDirectory, 2, 1 ) @= ':' );\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nElseIf( Scan( '/', GetProcessErrorFileDirectory ) > 0 );\r\n sOS = 'Linux';\r\n sOSDelim = '/';\r\nElse;\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nEndIf;\r\n\r\n## File location for indirect data copy\r\ncDir = GetProcessErrorFileDirectory;\r\ncFileName = pSrcCube | cTimeStamp | cRandomInt | '.csv';\r\ncFile = cDir | cFileName;\r\ncTitleRows = 1;\r\n\r\n# Validate file delimiter & quote character\r\nIf( pDelim @= '' );\r\n pDelim = ',';\r\nElse;\r\n # If length of pDelim is exactly 3 chars and each of them is decimal digit, then the pDelim is entered as ASCII code\r\n nValid = 0;\r\n If ( LONG(pDelim) = cLenASCIICode );\r\n nChar = 1;\r\n While ( nChar <= cLenASCIICode );\r\n If( CODE( pDelim, nChar ) >= CODE( '0', 1 ) & CODE( pDelim, nChar ) <= CODE( '9', 1 ) );\r\n nValid = 1;\r\n Else;\r\n nValid = 0;\r\n Break;\r\n EndIf;\r\n nChar = nChar + 1;\r\n End;\r\n EndIf;\r\n If ( nValid<>0 );\r\n pDelim=CHAR(StringToNumber( pDelim ));\r\n Else;\r\n pDelim = SubSt( Trim( pDelim ), 1, 1 );\r\n EndIf;\r\nEndIf;\r\ncDelimiter = pDelim;\r\n\r\nIf( pQuote @= '' );\r\n ## Use no quote character\r\nElse;\r\n # If length of pQuote is exactly 3 chars and each of them is decimal digit, then the pQuote is entered as ASCII code\r\n nValid = 0;\r\n If ( LONG(pQuote) = cLenASCIICode );\r\n nChar = 1;\r\n While ( nChar <= cLenASCIICode );\r\n If( CODE( pQuote, nChar ) >= CODE( '0', 1 ) & CODE( pQuote, nChar ) <= CODE( '9', 1 ) );\r\n nValid = 1;\r\n Else;\r\n nValid = 0;\r\n Break;\r\n EndIf;\r\n nChar = nChar + 1;\r\n End;\r\n EndIf;\r\n If ( nValid<>0 );\r\n pQuote=CHAR(StringToNumber( pQuote ));\r\n Else;\r\n pQuote = SubSt( Trim( pQuote ), 1, 1 );\r\n EndIf;\r\nEndIf;\r\ncQuote = pQuote;\r\n\r\n#Region ## Check Parameters ###\r\n\r\n## Default filter delimiters\r\nIf( pDimDelim @= '' );\r\n pDimDelim = '&';\r\nEndIf;\r\nIf( pEleStartDelim@= '' );\r\n pEleStartDelim= '\u00a6';\r\nEndIf;\r\nIf( pEleDelim @= '' );\r\n pEleDelim = '+';\r\nEndIf;\r\n\r\nIf( pDecimalSeparator @= '' );\r\n \tpDecimalSeparator = '.';\r\nEndIf;\r\nIf ( LONG(pDecimalSeparator) = cLenASCIICode );\r\n nValid = 0;\r\n nChar = 1;\r\n While ( nChar <= cLenASCIICode );\r\n If( CODE( pDecimalSeparator, nChar ) >= CODE( '0', 1 ) & CODE( pDecimalSeparator, nChar ) <= CODE( '9', 1 ) );\r\n nValid = 1;\r\n Else;\r\n nValid = 0;\r\n Break;\r\n EndIf;\r\n nChar = nChar + 1;\r\n End;\r\n If ( nValid<>0 );\r\n pDecimalSeparator = CHAR(StringToNumber( pDecimalSeparator ));\r\n Else;\r\n pDecimalSeparator = SubSt( Trim( pDecimalSeparator ), 1, 1 );\r\n EndIf;\r\nEndIf;\r\nsDecimalSeparator = pDecimalSeparator;\r\n\r\nIf( pThousandSeparator @= '' );\r\n \tpThousandSeparator = ',';\r\nEndIf;\r\nIf ( LONG(pThousandSeparator) = cLenASCIICode );\r\n nValid = 0;\r\n nChar = 1;\r\n While ( nChar <= cLenASCIICode );\r\n If( CODE( pThousandSeparator, nChar ) >= CODE( '0', 1 ) & CODE( pThousandSeparator, nChar ) <= CODE( '9', 1 ) );\r\n nValid = 1;\r\n Else;\r\n nValid = 0;\r\n Break;\r\n EndIf;\r\n nChar = nChar + 1;\r\n End;\r\n If ( nValid<>0 );\r\n pThousandSeparator = CHAR(StringToNumber( pThousandSeparator ));\r\n Else;\r\n pThousandSeparator = SubSt( Trim( pThousandSeparator ), 1, 1 );\r\n EndIf;\r\nEndIf;\r\nsThousandSeparator = pThousandSeparator;\r\n\r\n# If specified source cube doesn't exist then terminate process\r\nIf( CubeExists( pSrcCube ) = 0 );\r\n nErrors = nErrors + 1;\r\n sMessage = Expand( 'Invalid source cube specified: %pSrcCube%.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# If specified target cube doesn't exist then terminate process\r\nIf( CubeExists( pTgtCube ) = 0 );\r\n nErrors = nErrors + 1;\r\n sMessage = Expand( 'Invalid target cube specified: %pTgtCube%.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate parallelization filter\r\nIf( Scan( pEleStartDelim, pFilterParallel ) > 0 );\r\n sDimParallel = SubSt( pFilterParallel, 1, Scan( pEleStartDelim, pFilterParallel ) - 1 );\r\n If( Scan( Lower(sDimParallel) | pEleStartDelim, Lower(pFilter) ) > 0 );\r\n sMessage = 'Parallelization dimension %sDimParallel% cannot exist in filter.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n EndIf;\r\nEndIf;\r\n\r\n# Validate Max Threads\r\nIf( pParallelThreads > 0 );\r\n nMaxThreads = pParallelThreads;\r\nElse;\r\n nMaxThreads = 1;\r\nEndIf;\r\n\r\n# Validate Sandbox\r\nIf( TRIM( pSandbox ) @<> '' );\r\n If( ServerSandboxExists( pSandbox ) = 0 );\r\n SetUseActiveSandboxProperty( 0 );\r\n nErrors = nErrors + 1;\r\n sMessage = Expand('Sandbox %pSandbox% is invalid for the current user.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n Else;\r\n ServerActiveSandboxSet( pSandbox );\r\n SetUseActiveSandboxProperty( 1 );\r\n EndIf;\r\nElse;\r\n SetUseActiveSandboxProperty( 0 );\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n#EndRegion\r\n#Region \r\n## Set variables =0 or '' ################################################################################################# ########################\r\n### Placeholders for mappped dimensions\r\nnMappedDim1 = 0;\r\nnMappedDim2 = 0;\r\nnMappedDim3 = 0;\r\nnMappedDim4 = 0;\r\nnMappedDim5 = 0;\r\nnMappedDim6 = 0;\r\nnMappedDim7 = 0;\r\nnMappedDim8 = 0;\r\nnMappedDim9 = 0;\r\nnMappedDim10 = 0;\r\nnMappedDim11 = 0;\r\nnMappedDim12 = 0;\r\nnMappedDim13 = 0;\r\nnMappedDim14 = 0;\r\nnMappedDim15 = 0;\r\nnMappedDim16 = 0;\r\nnMappedDim17 = 0;\r\nnMappedDim18 = 0;\r\nnMappedDim19 = 0;\r\nnMappedDim20 = 0;\r\nnMappedDim21 = 0;\r\nnMappedDim22 = 0;\r\nnMappedDim23 = 0;\r\nnMappedDim24 = 0;\r\nnMappedDim25 = 0;\r\nnMappedDim26 = 0;\r\nnMappedDim27 = 0;\r\n\r\nsMappedV1 = '';\r\nsMappedV2 = '';\r\nsMappedV3 = '';\r\nsMappedV4 = '';\r\nsMappedV5 = '';\r\nsMappedV6 = '';\r\nsMappedV7 = '';\r\nsMappedV8 = '';\r\nsMappedV9 = '';\r\nsMappedV10 = '';\r\nsMappedV11 = '';\r\nsMappedV12 = '';\r\nsMappedV13 = '';\r\nsMappedV14 = '';\r\nsMappedV15 = '';\r\nsMappedV16 = '';\r\nsMappedV17 = '';\r\nsMappedV18 = '';\r\nsMappedV19 = '';\r\nsMappedV20 = '';\r\nsMappedV21 = '';\r\nsMappedV22 = '';\r\nsMappedV23 = '';\r\nsMappedV24 = '';\r\nsMappedV25 = '';\r\nsMappedV26 = '';\r\nsMappedV27 = '';\r\nsMappedV28 = '';\r\n\r\n### Placeholders for new dimensions\r\nnNewDim1 = 0;\r\nnNewDim2 = 0;\r\nnNewDim3 = 0;\r\nnNewDim4 = 0;\r\nnNewDim5 = 0;\r\nnNewDim6 = 0;\r\nnNewDim7 = 0;\r\nnNewDim8 = 0;\r\nnNewDim9 = 0;\r\nnNewDim10 = 0;\r\nnNewDim11 = 0;\r\nnNewDim12 = 0;\r\nnNewDim13 = 0;\r\nnNewDim14 = 0;\r\nnNewDim15 = 0;\r\nnNewDim16 = 0;\r\nnNewDim17 = 0;\r\nnNewDim18 = 0;\r\nnNewDim19 = 0;\r\nnNewDim20 = 0;\r\nnNewDim21 = 0;\r\nnNewDim22 = 0;\r\nnNewDim23 = 0;\r\nnNewDim24 = 0;\r\nnNewDim25 = 0;\r\nnNewDim26 = 0;\r\nnNewDim27 = 0;\r\n\r\nsNewV1 = '';\r\nsNewV2 = '';\r\nsNewV3 = '';\r\nsNewV4 = '';\r\nsNewV5 = '';\r\nsNewV6 = '';\r\nsNewV7 = '';\r\nsNewV8 = '';\r\nsNewV9 = '';\r\nsNewV10 = '';\r\nsNewV11 = '';\r\nsNewV12 = '';\r\nsNewV13 = '';\r\nsNewV14 = '';\r\nsNewV15 = '';\r\nsNewV16 = '';\r\nsNewV17 = '';\r\nsNewV18 = '';\r\nsNewV19 = '';\r\nsNewV20 = '';\r\nsNewV21 = '';\r\nsNewV22 = '';\r\nsNewV23 = '';\r\nsNewV24 = '';\r\nsNewV25 = '';\r\nsNewV26 = '';\r\nsNewV27 = '';\r\n\r\n### Determine dimensions in target cube, we need to know this to test cell type before loading ###\r\n# only numbers get converted from strings to numbers\r\nsDim1 = TabDim( pTgtCube, 1 );\r\nsDim2 = TabDim( pTgtCube, 2 );\r\nsDim3 = TabDim( pTgtCube, 3 );\r\nsDim4 = TabDim( pTgtCube, 4 );\r\nsDim5 = TabDim( pTgtCube, 5 );\r\nsDim6 = TabDim( pTgtCube, 6 );\r\nsDim7 = TabDim( pTgtCube, 7 );\r\nsDim8 = TabDim( pTgtCube, 8 );\r\nsDim9 = TabDim( pTgtCube, 9 );\r\nsDim10 = TabDim( pTgtCube, 10 );\r\nsDim11 = TabDim( pTgtCube, 11 );\r\nsDim12 = TabDim( pTgtCube, 12 );\r\nsDim13 = TabDim( pTgtCube, 13 );\r\nsDim14 = TabDim( pTgtCube, 14 );\r\nsDim15 = TabDim( pTgtCube, 15 );\r\nsDim16 = TabDim( pTgtCube, 16 );\r\nsDim17 = TabDim( pTgtCube, 17 );\r\nsDim18 = TabDim( pTgtCube, 18 );\r\nsDim19 = TabDim( pTgtCube, 19 );\r\nsDim20 = TabDim( pTgtCube, 20 );\r\nsDim21 = TabDim( pTgtCube, 21 );\r\nsDim22 = TabDim( pTgtCube, 22 );\r\nsDim23 = TabDim( pTgtCube, 23 );\r\nsDim24 = TabDim( pTgtCube, 24 );\r\nsDim25 = TabDim( pTgtCube, 25 );\r\nsDim26 = TabDim( pTgtCube, 26 );\r\nsDim27 = TabDim( pTgtCube, 27 );\r\n#EndRegion\r\nsTgtDimString = '^^'|sDim1|'^^'|sDim2|'^^'|sDim3|'^^'|sDim4|'^^'|sDim5|'^^'|sDim6|'^^'|sDim7|'^^'|sDim8|'^^'|sDim9|'^^'|sDim10|'^^'\r\n |sDim11|'^^'|sDim12|'^^'|sDim13|'^^'|sDim14|'^^'|sDim15|'^^'|sDim16|'^^'|sDim17|'^^'|sDim18|'^^'|sDim19|'^^'|sDim20|'^^'\r\n |sDim21|'^^'|sDim22|'^^'|sDim23|'^^'|sDim24|'^^'|sDim25|'^^'|sDim26|'^^'|sDim27|'^^';\r\n\r\n### We have to remove spaces from the search string before going to include the string in searching loop\r\nsTgtDimString = UPPER( sTgtDimString );\r\nnSPIndex = SCAN( ' ', sTgtDimString );\r\nWhile ( nSPIndex <> 0);\r\n sTgtDimString = DELET( sTgtDimString, nSPIndex, 1 );\r\n nSPIndex = SCAN( ' ', sTgtDimString );\r\nEnd;\r\n\r\n###########################################\r\n#Region ### MAPPING Target DIMENSIONS #####\r\n###########################################\r\nnSourceIndex = 1;\r\nWhile( TabDim( pSrcCube, nSourceIndex ) @<> '' );\r\n sSourceDim = TabDim( pSrcCube, nSourceIndex);\r\n # reset target index if another source dimension has been found\r\n nTargetIndex = 1;\r\n WHILE(TabDim( pTgtCube, nTargetIndex ) @<> '');\r\n sTargetDim = TabDim( pTgtCube, nTargetIndex );\r\n If(sSourceDim @= sTargetDim);\r\n If( pFile = 0 );\r\n If(nTargetIndex = 1);\r\n nMappedDim1 = 1;\r\n sMappedV1 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 2);\r\n nMappedDim2 = 1;\r\n sMappedV2 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 3);\r\n nMappedDim3 = 1;\r\n sMappedV3 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 4);\r\n nMappedDim4 = 1;\r\n sMappedV4 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 5);\r\n nMappedDim5 = 1;\r\n sMappedV5 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 6);\r\n nMappedDim6 = 1;\r\n sMappedV6 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 7);\r\n nMappedDim7 = 1;\r\n sMappedV7 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 8);\r\n nMappedDim8 = 1;\r\n sMappedV8 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 9);\r\n nMappedDim9 = 1;\r\n sMappedV9 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 10);\r\n nMappedDim10 = 1;\r\n sMappedV10 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 11);\r\n nMappedDim11 = 1;\r\n sMappedV11 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 12);\r\n nMappedDim12 = 1;\r\n sMappedV12 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 13);\r\n nMappedDim13 = 1;\r\n sMappedV13 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 14);\r\n nMappedDim14 = 1;\r\n sMappedV14 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 15);\r\n nMappedDim15 = 1;\r\n sMappedV15 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 16);\r\n nMappedDim16 = 1;\r\n sMappedV16 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 17);\r\n nMappedDim17 = 1;\r\n sMappedV17 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 18);\r\n nMappedDim18 = 1;\r\n sMappedV18 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 19);\r\n nMappedDim19 = 1;\r\n sMappedV19 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 20);\r\n nMappedDim20 = 1;\r\n sMappedV20 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 21);\r\n nMappedDim21 = 1;\r\n sMappedV21 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 22);\r\n nMappedDim22 = 1;\r\n sMappedV22 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 23);\r\n nMappedDim23 = 1;\r\n sMappedV23 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 24);\r\n nMappedDim24 = 1;\r\n sMappedV24 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 25);\r\n nMappedDim25 = 1;\r\n sMappedV25 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 26);\r\n nMappedDim26 = 1;\r\n sMappedV26 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 27);\r\n nMappedDim27 = 1;\r\n sMappedV27 = 'V' | NumberToString(nSourceIndex);\r\n EndIf;\r\n ElseIf( pFile > 0 );\r\n ## If using source file first variable holds tha cube name, so all the other ones have the index increased by 1\r\n If(nTargetIndex = 1);\r\n nMappedDim1 = 1;\r\n sMappedV1 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 2);\r\n nMappedDim2 = 1;\r\n sMappedV2 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 3);\r\n nMappedDim3 = 1;\r\n sMappedV3 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 4);\r\n nMappedDim4 = 1;\r\n sMappedV4 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 5);\r\n nMappedDim5 = 1;\r\n sMappedV5 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 6);\r\n nMappedDim6 = 1;\r\n sMappedV6 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 7);\r\n nMappedDim7 = 1;\r\n sMappedV7 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 8);\r\n nMappedDim8 = 1;\r\n sMappedV8 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 9);\r\n nMappedDim9 = 1;\r\n sMappedV9 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 10);\r\n nMappedDim10 = 1;\r\n sMappedV10 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 11);\r\n nMappedDim11 = 1;\r\n sMappedV11 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 12);\r\n nMappedDim12 = 1;\r\n sMappedV12 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 13);\r\n nMappedDim13 = 1;\r\n sMappedV13 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 14);\r\n nMappedDim14 = 1;\r\n sMappedV14 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 15);\r\n nMappedDim15 = 1;\r\n sMappedV15 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 16);\r\n nMappedDim16 = 1;\r\n sMappedV16 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 17);\r\n nMappedDim17 = 1;\r\n sMappedV17 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 18);\r\n nMappedDim18 = 1;\r\n sMappedV18 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 19);\r\n nMappedDim19 = 1;\r\n sMappedV19 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 20);\r\n nMappedDim20 = 1;\r\n sMappedV20 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 21);\r\n nMappedDim21 = 1;\r\n sMappedV21 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 22);\r\n nMappedDim22 = 1;\r\n sMappedV22 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 23);\r\n nMappedDim23 = 1;\r\n sMappedV23 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 24);\r\n nMappedDim24 = 1;\r\n sMappedV24 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 25);\r\n nMappedDim25 = 1;\r\n sMappedV25 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 26);\r\n nMappedDim26 = 1;\r\n sMappedV26 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 27);\r\n nMappedDim27 = 1;\r\n sMappedV27 = 'V' | NumberToString(nSourceIndex + 1);\r\n EndIf;\r\n EndIf;\r\n\r\n EndIf;\r\n\r\n nTargetIndex = nTargetIndex + 1;\r\n\r\n END;\r\n\r\n nSourceIndex = nSourceIndex + 1;\r\n\r\nEND;\r\n\r\n# The last variable in the data source holds the values\r\n# which need to be mapped to the last variable in the target\r\n\r\nIf( pFile = 0 );\r\n If(nTargetIndex = 1);\r\n nMappedDim1 = 1;\r\n sMappedV1 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 2);\r\n nMappedDim2 = 1;\r\n sMappedV2 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 3);\r\n nMappedDim3 = 1;\r\n sMappedV3 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 4);\r\n nMappedDim4 = 1;\r\n sMappedV4 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 5);\r\n nMappedDim5 = 1;\r\n sMappedV5 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 6);\r\n nMappedDim6 = 1;\r\n sMappedV6 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 7);\r\n nMappedDim7 = 1;\r\n sMappedV7 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 8);\r\n nMappedDim8 = 1;\r\n sMappedV8 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 9);\r\n nMappedDim9 = 1;\r\n sMappedV9 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 10);\r\n nMappedDim10 = 1;\r\n sMappedV10 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 11);\r\n nMappedDim11 = 1;\r\n sMappedV11 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 12);\r\n nMappedDim12 = 1;\r\n sMappedV12 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 13);\r\n nMappedDim13 = 1;\r\n sMappedV13 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 14);\r\n nMappedDim14 = 1;\r\n sMappedV14 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 15);\r\n nMappedDim15 = 1;\r\n sMappedV15 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 16);\r\n nMappedDim16 = 1;\r\n sMappedV16 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 17);\r\n nMappedDim17 = 1;\r\n sMappedV17 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 18);\r\n nMappedDim18 = 1;\r\n sMappedV18 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 19);\r\n nMappedDim19 = 1;\r\n sMappedV19 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 20);\r\n nMappedDim20 = 1;\r\n sMappedV20 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 21);\r\n nMappedDim21 = 1;\r\n sMappedV21 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 22);\r\n nMappedDim22 = 1;\r\n sMappedV22 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 23);\r\n nMappedDim23 = 1;\r\n sMappedV23 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 24);\r\n nMappedDim24 = 1;\r\n sMappedV24 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 25);\r\n nMappedDim25 = 1;\r\n sMappedV25 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 26);\r\n nMappedDim26 = 1;\r\n sMappedV26 = 'V' | NumberToString(nSourceIndex);\r\n ElseIf(nTargetIndex = 27);\r\n nMappedDim27 = 1;\r\n sMappedV27 = 'V' | NumberToString(nSourceIndex);\r\n \r\n # a cube with 27 dimensions uses V28 to hold the values\r\n ElseIf(nTargetIndex = 28);\r\n nMappedDim28 = 1;\r\n sMapped28 = 'V' | NumberToString(nSourceIndex);\r\n EndIf;\r\nElseIf( pFile > 0 );\r\n If(nTargetIndex = 1);\r\n nMappedDim1 = 1;\r\n sMappedV1 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 2);\r\n nMappedDim2 = 1;\r\n sMappedV2 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 3);\r\n nMappedDim3 = 1;\r\n sMappedV3 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 4);\r\n nMappedDim4 = 1;\r\n sMappedV4 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 5);\r\n nMappedDim5 = 1;\r\n sMappedV5 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 6);\r\n nMappedDim6 = 1;\r\n sMappedV6 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 7);\r\n nMappedDim7 = 1;\r\n sMappedV7 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 8);\r\n nMappedDim8 = 1;\r\n sMappedV8 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 9);\r\n nMappedDim9 = 1;\r\n sMappedV9 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 10);\r\n nMappedDim10 = 1;\r\n sMappedV10 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 11);\r\n nMappedDim11 = 1;\r\n sMappedV11 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 12);\r\n nMappedDim12 = 1;\r\n sMappedV12 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 13);\r\n nMappedDim13 = 1;\r\n sMappedV13 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 14);\r\n nMappedDim14 = 1;\r\n sMappedV14 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 15);\r\n nMappedDim15 = 1;\r\n sMappedV15 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 16);\r\n nMappedDim16 = 1;\r\n sMappedV16 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 17);\r\n nMappedDim17 = 1;\r\n sMappedV17 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 18);\r\n nMappedDim18 = 1;\r\n sMappedV18 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 19);\r\n nMappedDim19 = 1;\r\n sMappedV19 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 20);\r\n nMappedDim20 = 1;\r\n sMappedV20 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 21);\r\n nMappedDim21 = 1;\r\n sMappedV21 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 22);\r\n nMappedDim22 = 1;\r\n sMappedV22 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 23);\r\n nMappedDim23 = 1;\r\n sMappedV23 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 24);\r\n nMappedDim24 = 1;\r\n sMappedV24 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 25);\r\n nMappedDim25 = 1;\r\n sMappedV25 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 26);\r\n nMappedDim26 = 1;\r\n sMappedV26 = 'V' | NumberToString(nSourceIndex + 1);\r\n ElseIf(nTargetIndex = 27);\r\n nMappedDim27 = 1;\r\n sMappedV27 = 'V' | NumberToString(nSourceIndex + 1);\r\n \r\n # a cube with 27 dimensions uses V29 to hold the values if export file is used as source\r\n ElseIf(nTargetIndex = 28);\r\n nMappedDim28 = 1;\r\n sMapped28 = 'V' | NumberToString(nSourceIndex + 1);\r\n EndIf;\r\nEndIf;\r\n#EndRegion\r\n\r\n###########################################\r\n### SPLIT MAPPING TO NEW DIMS PARAMETER ###\r\n###########################################\r\n\r\n# now deduct 1 to set these indices to the number of dimensions in each cube\r\nnSourceDimensionCount = nSourceIndex - 1;\r\nnTargetCubeDimensionCount = nTargetIndex - 1;\r\n# default dimension count is for target\r\nnDimensionCount = nTargetIndex - 1;\r\n\r\nsElementMapping = TRIM( pMappingToNewDims );\r\nnChar = 1;\r\nnCharCount = LONG( sElementMapping );\r\n\r\nsTargetFilter = '';\r\nsWord = '';\r\nsLastDelim = '';\r\nnIndex = 1;\r\n\r\n# Add a trailing element delimiter so that the last element is picked up\r\nIf( nCharCount > 0 );\r\n sElementMapping = sElementMapping | sDelimDim;\r\n nCharCount = nCharCount + LONG(sDelimDim);\r\nEndIf;\r\n\r\nWHILE (nChar <= nCharCount);\r\n sChar = SUBST( sElementMapping, nChar, 1);\r\n\r\n # Used for delimiters, required for multiple character delimiters\r\n sDelim = '';\r\n nAddExtra = 0;\r\n\r\n # Ignore spaces\r\n IF (TRIM(sChar) @<> '' );\r\n\r\n ### Dimension Name ###\r\n\r\n # If the delimiter is more than 1 character peek ahead the same amount\r\n # Ignore the first character\r\n sDelim = sChar;\r\n nCount = LONG(sElementStartDelim) - 1;\r\n If( nCount > 0 & nChar + nCount <= nCharCount );\r\n # Add the extra characters\r\n sDelim = sDelim | SUBST( sElementMapping, nChar + 1, nCount);\r\n # Move to the end of the delimter\r\n nAddExtra = nCount;\r\n EndIf;\r\n\r\n If( sDelim @= sElementStartDelim );\r\n\r\n sChar = sDelim;\r\n\r\n If( sLastDelim @<> '' & sLastDelim @<> sDelimDim );\r\n sMessage = 'In pMappingToNewDims the name of a dimension must follow a dimension delimiter (' | sDelimDim | ')';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n #ProcessError();\r\n EndIf;\r\n\r\n # Found a dimension\r\n sDimension = sWord;\r\n\r\n If( DimensionExists( sDimension ) = 0 );\r\n # The dimension does not exist in the model. Cancel process\r\n sMessage = 'In pMappingToNewDims - Dimension: ' | sDimension | ' does not exist';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n #ProcessError();\r\n EndIf;\r\n\r\n # Find the index of the dimension is in the Target cube\r\n nTargetIndexCounter = 1;\r\n\r\n WHILE(nTargetIndexCounter <= nTargetCubeDimensionCount );\r\n sNthDimension = TabDim( pTgtCube, nTargetIndexCounter );\r\n\r\n If(sDimension @= sNthDimension);\r\n nTargetIndex = nTargetIndexCounter;\r\n nTargetIndexCounter = 1000;\r\n EndIf;\r\n\r\n nTargetIndexCounter = nTargetIndexCounter + 1;\r\n END;\r\n \r\n #Add to the Target filter\r\n IF(sTargetFilter@='');\r\n sTargetFilter=sDimension; \r\n Else;\r\n sTargetFilter=sTargetFilter|sDelimDim|sDimension;\r\n Endif; \r\n \r\n sLastDelim = sChar;\r\n # Clear the word\r\n sWord = '';\r\n\r\n Else;\r\n\r\n # Reset extra chars\r\n nAddExtra = 0;\r\n\r\n ### Check both dim delimiter and element delimiter ###\r\n nIsDelimiter = 0;\r\n\r\n ## Check dimension delimiter first\r\n # If the delimiter is more than 1 character peek ahead the same amount\r\n # Ignore the first character\r\n sDelim = sChar;\r\n nCount = LONG(sDelimDim) - 1;\r\n If( nCount > 0 & nChar + nCount <= nCharCount );\r\n # Add the extra characters\r\n sDelim = sDelim | SUBST( sElementMapping, nChar + 1, nCount);\r\n EndIf;\r\n\r\n If( sDelim @= sDelimDim );\r\n nIsDelimiter = 1;\r\n sChar = sDelim;\r\n \r\n # Move to the end of the delimter\r\n nAddExtra = nCount;\r\n EndIf;\r\n\r\n If ( nIsDelimiter = 1 );\r\n\r\n If( sLastDelim @= '' % sLastDelim @= sDelimDim );\r\n sMessage = 'In pMappingToNewDims - an element delimiter must follow a dimension name: ' | sChar | ' (' | NumberToString(nChar) | ')';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n #ProcessError();\r\n EndIf;\r\n\r\n # an element has been found\r\n sElement = sWord;\r\n\r\n If( DIMIX( sDimension, sElement ) = 0 );\r\n # The element does not exist in the dimension. Cancel process\r\n sMessage = 'In pMappingToNewDims - Element: ' | sElement | ' in dimension ' | sDimension | ' does not exist';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n #ProcessError();\r\n EndIf;\r\n\r\n # Allow consolidations only if pSuppressConsol is set to 0\r\n\r\n If ( DTYPE( sDimension, sElement) @= 'C' );\r\n sMessage = Expand( 'In pMappingToNewDims - Target element: %sElement% for dimension %sDimension% is consolidated' );\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n #ProcessError();\r\n Endif; \r\n \r\n\r\n # Add the element to the source or target depending on whether it's the first or the second element\r\n # Get principal name\r\n # in case source element and this element are using different aliases\r\n\r\n sElement = DimensionElementPrincipalName(sDimension,sElement);\r\n\r\n ### Update the variable for InputElement Target Dim ######################################\r\n If(nTargetIndex = 1);\r\n nNewDim1 = 1;\r\n sNewV1 = sElement;\r\n ElseIf(nTargetIndex = 2);\r\n nNewDim2 = 1;\r\n sNewV2 = sElement;\r\n ElseIf(nTargetIndex = 3);\r\n nNewDim3 = 1;\r\n sNewV3 = sElement;\r\n ElseIf(nTargetIndex = 4);\r\n nNewDim4 = 1;\r\n sNewV4 = sElement;\r\n ElseIf(nTargetIndex = 5);\r\n nNewDim5 = 1;\r\n sNewV5 = sElement;\r\n ElseIf(nTargetIndex = 6);\r\n nNewDim6 = 1;\r\n sNewV6 = sElement;\r\n ElseIf(nTargetIndex = 7);\r\n nNewDim7 = 1;\r\n sNewV7 = sElement;\r\n ElseIf(nTargetIndex = 8);\r\n nNewDim8 = 1;\r\n sNewV8 = sElement;\r\n ElseIf(nTargetIndex = 9);\r\n nNewDim9 = 1;\r\n sNewV9 = sElement;\r\n ElseIf(nTargetIndex = 10);\r\n nNewDim10 = 1;\r\n sNewV10 = sElement;\r\n ElseIf(nTargetIndex = 11);\r\n nNewDim11 = 1;\r\n sNewV11 = sElement;\r\n ElseIf(nTargetIndex = 12);\r\n nNewDim12 = 1;\r\n sNewV12 = sElement;\r\n ElseIf(nTargetIndex = 13);\r\n nNewDim13 = 1;\r\n sNewV13 = sElement;\r\n ElseIf(nTargetIndex = 14);\r\n nNewDim14 = 1;\r\n sNewV14 = sElement;\r\n ElseIf(nTargetIndex = 15);\r\n nNewDim15 = 1;\r\n sNewV15 = sElement;\r\n ElseIf(nTargetIndex = 16);\r\n nNewDim16 = 1;\r\n sNewV16 = sElement;\r\n ElseIf(nTargetIndex = 17);\r\n nNewDim17 = 1;\r\n sNewV17 = sElement;\r\n ElseIf(nTargetIndex = 18);\r\n nNewDim18 = 1;\r\n sNewV18 = sElement;\r\n ElseIf(nTargetIndex = 19);\r\n nNewDim19 = 1;\r\n sNewV19 = sElement;\r\n ElseIf(nTargetIndex = 20);\r\n nNewDim20 = 1;\r\n sNewV20 = sElement;\r\n ElseIf(nTargetIndex = 21);\r\n nNewDim21 = 1;\r\n sNewV21 = sElement;\r\n ElseIf(nTargetIndex = 22);\r\n nNewDim22 = 1;\r\n sNewV22 = sElement;\r\n ElseIf(nTargetIndex = 23);\r\n nNewDim23 = 1;\r\n sNewV23 = sElement;\r\n ElseIf(nTargetIndex = 24);\r\n nNewDim24 = 1;\r\n sNewV24 = sElement;\r\n ElseIf(nTargetIndex = 25);\r\n nNewDim25 = 1;\r\n sNewV25 = sElement;\r\n ElseIf(nTargetIndex = 26);\r\n nNewDim26 = 1;\r\n sNewV26 = sElement;\r\n ElseIf(nTargetIndex = 27);\r\n nNewDim27 = 1;\r\n sNewV27 = sElement;\r\n EndIf;\r\n\r\n #Add to the Target filter\r\n sTargetFilter=sTargetFilter|sElementStartDelim|sElement;\r\n \r\n # Clear the word\r\n sWord = '';\r\n sLastDelim = sChar;\r\n \r\n Else;\r\n sWord = sWord | sChar;\r\n EndIf;\r\n\r\n EndIf;\r\n\r\n EndIf;\r\n\r\n nChar = nChar + nAddExtra + 1;\r\n\r\nEND;\r\n\r\n# Check that an input element or variable has been specified for all dimensions in the target cube\r\n\r\nnIndexInTarget = 1;\r\nWHILE(nIndexInTarget <= nTargetCubeDimensionCount);\r\n \r\n sMapped = Expand('%nMappedDim'| NumberToString(nIndexInTarget) |'%'); \r\n sMapped = Subst( sMapped , Scan( '.' , sMapped )-1 , 99);\r\n nMapped = StringToNumber( Trim( sMapped ) );\r\n sNew = Expand('%nNewDim'| NumberToString(nIndexInTarget) |'%'); \r\n sNew = Subst( sNew , Scan( '.' , sNew )-1 , 99);\r\n nNew = StringToNumber( Trim( sNew ) );\r\n \r\n If(nMapped = 0 & nNew = 0 );\r\n # there's no input element and this dimension is not in the source\r\n nErrors = nErrors + 1;\r\n sTargetDimName = TabDim( pTgtCube, nIndexInTarget );\r\n sMessage = 'Dimension ' | sTargetDimName | ' is missing an input element in pMappingToNewDims';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n EndIf;\r\n \r\n nIndexInTarget = nIndexInTarget + 1;\r\nEND;\r\n\r\n\r\n############################# Clear out target ################################\r\n\r\n# Target is cleared for the elements specified in pMappingToNewDims\r\n# and for the parts of pFilter for dimensions in the target\r\n# This code works through pFilter looking for the parts relating to the target cube\r\n# the code which finds individual elements has been left in\r\n# so that it can be changed later to deal with consolidated elements\r\n\r\nsFilter = TRIM( pFilter );\r\nnChar = 1;\r\nnCharCount = LONG( sFilter );\r\nsWord = '';\r\nsLastDelim = '';\r\n\r\n# Add a trailing element delimiter so that the last Dimension:Element/s clause is picked up\r\nIf( nCharCount > 0 );\r\n sFilter = sFilter | sDelimElem;\r\n nCharCount = nCharCount + LONG(sDelimElem);\r\nEndIf;\r\n\r\nWHILE (nChar <= nCharCount);\r\n\r\n sChar = SUBST( sFilter, nChar, 1);\r\n\r\n # Used for delimiters, required for multiple character dilimiters\r\n sDelim = '';\r\n nAddExtra = 0;\r\n\r\n # Ignore spaces\r\n IF (TRIM(sChar) @<> '' );\r\n\r\n ### Dimension Name ###\r\n\r\n # If the delimiter is more than 1 character peek ahead the same amount\r\n # Ignore the first character\r\n sDelim = sChar;\r\n nCount = LONG(sElementStartDelim) - 1;\r\n If( nCount > 0 & nChar + nCount <= nCharCount );\r\n # Add the extra characters\r\n sDelim = sDelim | SUBST( sFilter, nChar + 1, nCount);\r\n # Move to the end of the delimter\r\n nAddExtra = nCount;\r\n EndIf;\r\n\r\n If( sDelim @= sElementStartDelim );\r\n\r\n sChar = sDelim;\r\n\r\n If( sLastDelim @<> '' & sLastDelim @<> sDelimDim );\r\n sMessage = 'In pFilter - the name of a dimension must follow a dimension delimiter (' | sDelimDim | ')';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n #ProcessError();\r\n EndIf;\r\n\r\n # Found a dimension!\r\n sDimension = UPPER( sWord );\r\n nDimInTgt=0;\r\n # See if the dimension is in the target cube\r\n IF(scan('^^'|sDimension|'^^', sTgtDimString)>0);\r\n If(sTargetFilter@='');\r\n sTargetFilter = sDimension;\r\n Else; \r\n sTargetFilter = sTargetFilter | sDelimDim | sDimension;\r\n endif;\r\n nDimInTgt=1;\r\n Endif; \r\n\r\n sLastDelim = sChar;\r\n # Clear the word\r\n sWord = '';\r\n #reset element count\r\n nElementCount = 1;\r\n\r\n Else;\r\n\r\n # Reset extra chars\r\n nAddExtra = 0;\r\n\r\n ### Check both both dim delimiter and element delimiter ###\r\n nIsDelimiter = 0;\r\n\r\n ## Check dimension delimiter first\r\n # If the delimiter is more than 1 character peek ahead the same amount\r\n # Ignore the first character\r\n sDelim = sChar;\r\n nCount = LONG(sDelimDim) - 1;\r\n If( nCount > 0 & nChar + nCount <= nCharCount );\r\n # Add the extra characters\r\n sDelim = sDelim | SUBST( sFilter, nChar + 1, nCount);\r\n # Move to the end of the delimter\r\n nAddExtra = nCount;\r\n EndIf;\r\n\r\n If( sDelim @= sDelimDim );\r\n nIsDelimiter = 1;\r\n sChar = sDelim;\r\n Else;\r\n # Reset extra chars\r\n nAddExtra = 0;\r\n\r\n ## Check element delimiter\r\n\r\n # If the delimiter is more than 1 character peek ahead the same amount\r\n # Ignore the first character\r\n sDelim = sChar;\r\n nCount = LONG(sDelimElem) - 1;\r\n If( nCount > 0 & nChar + nCount <= nCharCount );\r\n # Add the extra characters\r\n sDelim = sDelim | SUBST( sFilter, nChar + 1, nCount);\r\n # Move to the end of the delimter\r\n nAddExtra = nCount;\r\n EndIf;\r\n\r\n If( sDelim @= sDelimElem );\r\n nIsDelimiter = 1;\r\n sChar = sDelim;\r\n Else;\r\n # Reset extra chars\r\n nAddExtra = 0;\r\n EndIf;\r\n\r\n EndIf;\r\n\r\n If ( nIsDelimiter = 1 );\r\n\r\n If( sLastDelim @= '' % sLastDelim @= sDelimDim );\r\n sMessage = 'In pFilter - an element delimiter must follow a dimension name: ' | sChar | ' (' | NumberToString(nChar) | ')';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n #ProcessError();\r\n EndIf;\r\n\r\n # Found an element\r\n sElement = sWord;\r\n\r\n IF(DIMIX(sDimension, sElement) > 0 & nDimInTgt=1);\r\n # first element\r\n IF(nElementCount = 1);\r\n sTargetFilter = sTargetFilter | sElementStartDelim | sElement;\r\n # later elements\r\n Else;\r\n sTargetFilter = sTargetFilter | sDelimElem | sElement;\r\n EndIf;\r\n EndIf;\r\n\r\n nElementCount = nElementCount + 1;\r\n sLastDelim = sChar;\r\n\r\n # Clear the word\r\n sWord = '';\r\n Else;\r\n sWord = sWord | sChar;\r\n EndIf;\r\n\r\n EndIf;\r\n\r\n EndIf;\r\n\r\n nChar = nChar + nAddExtra + 1;\r\n\r\nEND;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n# Branch depending on whether to do recursive calls to self on independent threads or run all in this thread\r\nIf( Scan( pEleStartDelim, pFilterParallel ) > 0 );\r\n sDimParallel = SubSt( pFilterParallel, 1, Scan( pEleStartDelim, pFilterParallel ) - 1 );\r\n sElementList = SubSt( pFilterParallel, Scan( pEleStartDelim, pFilterParallel ) + 1, Long( pFilterParallel ) );\r\n If( SubSt( sElementList, Long( sElementList ), 1 ) @<> pEleDelim );\r\n sElementList = sElementList | pEleDelim;\r\n EndIf;\r\n ## Counting elements in element list\r\n sElementListCount = sElementList;\r\n nElements = 0;\r\n While( Scan( pEleDelim, sElementListCount ) > 0 );\r\n nElements = nElements + 1;\r\n sElementListCount = SubSt( sElementListCount, Scan( pEleDelim, sElementListCount ) + 1, Long( sElementListCount ) );\r\n End;\r\n IF( Mod( nElements, nMaxThreads ) = 0 );\r\n nElemsPerThread = INT( nElements / nMaxThreads );\r\n ELSE;\r\n nElemsPerThread = INT( nElements / nMaxThreads ) + 1;\r\n ENDIF;\r\n nThreadElCounter = 0;\r\n While( Scan( pEleDelim, sElementList ) > 0 );\r\n sSlicerEle = SubSt( sElementList, 1, Scan( pEleDelim, sElementList ) - 1 );\r\n sElementList = SubSt( sElementList, Scan( pEleDelim, sElementList ) + 1, Long( sElementList ) );\r\n # Do recursive process call with new RunProcess function\r\n nThreadElCounter = nThreadElCounter + 1;\r\n sDimDelim = If(pFilter @= '', '', pDimDelim );\r\n IF( nThreadElCounter = 1 );\r\n sFilter = Expand('%pFilter%%sDimDelim%%sDimParallel%%pEleStartDelim%%sSlicerEle%');\r\n ELSE;\r\n sFilter = Expand('%sFilter%%pEleDelim%%sSlicerEle%');\r\n ENDIF;\r\n IF( nThreadElCounter >= nElemsPerThread );\r\n RunProcess( cThisProcName, 'pLogoutput', pLogoutput,\r\n \t'pSrcCube', pSrcCube, 'pFilter', sFilter, 'pFilterParallel', '', 'pTgtCube', pTgtCube, 'pMappingToNewDims', pMappingToNewDims,\r\n \t'pSuppressConsol', pSuppressConsol, 'pSuppressConsolStrings', pSuppressConsolStrings, 'pSuppressRules', pSuppressRules, 'pSuppressZero', pSuppressZero, 'pZeroTarget', pZeroTarget, 'pZeroSource', pZeroSource,\r\n 'pFactor', pFactor, 'pDimDelim', pDimDelim, 'pEleStartDelim', pEleStartDelim, 'pEleDelim', pEleDelim,\r\n 'pTemp', pTemp, 'pCubeLogging', pCubeLogging, 'pSandbox', pSandbox, 'pFile', pFile, 'pThreadMode', 1\r\n );\r\n \t nThreadElCounter = 0;\r\n \t sFilter = '';\r\n \t ENDIF;\r\n End;\r\n ## Process last elements - only when filter is not empty (there are still elements)\r\n IF( sFilter @<> '' );\r\n RunProcess( cThisProcName, 'pLogoutput', pLogoutput,\r\n \t'pSrcCube', pSrcCube, 'pFilter', sFilter, 'pFilterParallel', '', 'pTgtCube', pTgtCube, 'pMappingToNewDims', pMappingToNewDims,\r\n \t'pSuppressConsol', pSuppressConsol, 'pSuppressConsolStrings', pSuppressConsolStrings, 'pSuppressRules', pSuppressRules, 'pSuppressZero', pSuppressZero, 'pZeroTarget', pZeroTarget, 'pZeroSource', pZeroSource,\r\n 'pFactor', pFactor, 'pDimDelim', pDimDelim, 'pEleStartDelim', pEleStartDelim, 'pEleDelim', pEleDelim,\r\n 'pTemp', pTemp, 'pCubeLogging', pCubeLogging, 'pSandbox', pSandbox, 'pFile', pFile, 'pThreadMode', 1\r\n );\r\n ENDIF; \r\n DataSourceType = 'NULL';\r\nElse;\r\n # Clear out target view\r\n If(pZeroTarget = 1 & LONG(sTargetFilter)>= 0 & nErrors = 0);\r\n ###### Create View of target to clear out ###\r\n # Create View of target ###\r\n nRet = ExecuteProcess('}bedrock.cube.view.create',\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pCube', pTgtCube,\r\n 'pView', sTargetView ,\r\n 'pFilter', sTargetFilter,\r\n 'pSuppressZero', pSuppressZero,\r\n 'pSuppressConsol', pSuppressConsol,\r\n 'pSuppressRules', pSuppressRules,\r\n 'pSuppressConsolStrings', pSuppressConsolStrings, \r\n 'pDimDelim', pDimDelim,\r\n 'pEleStartDelim', pEleStartDelim,\r\n 'pEleDelim', pEleDelim ,\r\n 'pTemp', pTemp\r\n );\r\n \r\n IF(nRet <> 0);\r\n sMessage = 'Error creating the view from the filter.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n ENDIF;\r\n \r\n nRet = ExecuteProcess( '}bedrock.cube.data.clear',\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pCube', pTgtCube,\r\n 'pView', sTargetView,\r\n 'pFilter', sTargetFilter,\r\n 'pDimDelim', pDimDelim,\r\n 'pEleStartDelim', pEleStartDelim,\r\n 'pEleDelim', pEleDelim,\r\n 'pTemp', pTemp,\r\n 'pCubeLogging', pCubeLogging,\r\n 'pSandbox', pSandbox\r\n );\r\n \r\n IF(nRet <> 0);\r\n sMessage = 'Error clearing the target view.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n ENDIF;\r\n \r\n Endif;\r\n \r\n If( pFile = 0 );\r\n ### Create View of Source ###\r\n IF(pSuppressConsol = 0 & pSuppressConsolStrings = 1);\r\n pSubN=1;\r\n else;\r\n pSubN=0;\r\n Endif; \r\n \r\n nRet = ExecuteProcess('}bedrock.cube.view.create',\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pCube', pSrcCube,\r\n 'pView', sView,\r\n 'pFilter', pFilter,\r\n 'pSuppressZero', pSuppressZero,\r\n 'pSuppressConsol', pSuppressConsol,\r\n 'pSuppressRules', pSuppressRules,\r\n 'pSuppressConsolStrings', pSuppressConsolStrings, \r\n 'pDimDelim', pDimDelim,\r\n 'pEleStartDelim', pEleStartDelim,\r\n 'pEleDelim', pEleDelim ,\r\n 'pTemp', pTemp,\r\n 'pSubN', pSubN\r\n );\r\n \r\n IF(nRet <> 0);\r\n sMessage = 'Error creating the view from the filter.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n ENDIF;\r\n \r\n ElseIf( pFile > 0 );\r\n ### Export to File in case of Copy Data Via File ###\r\n IF(pSuppressConsol = 0);\r\n pSubN=1;\r\n else;\r\n pSubN=0;\r\n Endif; \r\n \r\n nRet = ExecuteProcess('}bedrock.cube.data.export',\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pCube', pSrcCube,\r\n 'pView', sView,\r\n 'pFilter', pFilter,\r\n 'pFilterParallel', '',\r\n 'pParallelThreads', 0,\r\n 'pDimDelim', pDimDelim,\r\n 'pEleStartDelim', pEleStartDelim,\r\n 'pEleDelim', pEleDelim,\r\n 'pSuppressZero', pSuppressZero,\r\n 'pSuppressConsol', pSuppressConsol,\r\n 'pSuppressRules', pSuppressRules,\r\n 'pSuppressConsolStrings', pSuppressConsolStrings, \r\n 'pZeroSource', 0,\r\n 'pCubeLogging', pCubeLogging,\r\n 'pTemp', pTemp,\r\n 'pFilePath', cDir,\r\n 'pFileName', cFileName,\r\n 'pDelim', cDelimiter,\r\n 'pDecimalSeparator', sDecimalSeparator,\r\n 'pThousandSeparator', sThousandSeparator,\r\n 'pQuote', cQuote,\r\n 'pTitleRecord', cTitleRows,\r\n 'pSandbox', pSandbox,\r\n 'pSubN', pSubN\r\n );\r\n \r\n IF(nRet <> 0);\r\n sMessage = 'Error exporting data to file.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n ENDIF;\r\n ENDIF;\r\n \r\n ### Assign Datasource ###\r\n If( pFile = 0 );\r\n DataSourceType = 'VIEW';\r\n DatasourceNameForServer = pSrcCube;\r\n DatasourceNameForClient = pSrcCube;\r\n DatasourceCubeView = sView;\r\n ElseIf( pFile > 0 );\r\n DataSourceType = 'CHARACTERDELIMITED';\r\n DatasourceNameForServer = cFile;\r\n DatasourceNameForClient = cFile;\r\n DatasourceASCIIHeaderRecords = cTitleRows;\r\n DatasourceASCIIDelimiter = cDelimiter;\r\n DatasourceASCIIQuoteCharacter = cQuote;\r\n EndIf;\r\nEndIf;\r\n\r\n### End Prolog ###", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n # The exapand function gives the value of the variable passed to it\r\n # So if the say the third dimension in the source cube is the first dimension in the target cube\r\n # the string variable Source Variable for Target varialbe V1 is set on the prolog to V3 (see Mapped part)\r\n # which means Expand(%V3%) gives the value of V3\r\n # and Target sV1 will equal V3\r\nIf( pFile = 0 ); \r\n sV1 =IF(nMappedDim1=1, Expand('%'|sMappedV1|'%'), IF(nNewDim1=1, sNewV1,V1));\r\n sV2 =IF(nMappedDim2=1, Expand('%'|sMappedV2|'%'), IF(nNewDim2=1, sNewV2,V2));\r\n sV3 =IF(nMappedDim3=1, Expand('%'|sMappedV3|'%'), IF(nNewDim3=1, sNewV3,V3));\r\n sV4 =IF(nMappedDim4=1, Expand('%'|sMappedV4|'%'), IF(nNewDim4=1, sNewV4,V4));\r\n sV5 =IF(nMappedDim5=1, Expand('%'|sMappedV5|'%'), IF(nNewDim5=1, sNewV5,V5));\r\n sV6 =IF(nMappedDim6=1, Expand('%'|sMappedV6|'%'), IF(nNewDim6=1, sNewV6,V6));\r\n sV7 =IF(nMappedDim7=1, Expand('%'|sMappedV7|'%'), IF(nNewDim7=1, sNewV7,V7));\r\n sV8 =IF(nMappedDim8=1, Expand('%'|sMappedV8|'%'), IF(nNewDim8=1, sNewV8,V8));\r\n sV9 =IF(nMappedDim9=1, Expand('%'|sMappedV9|'%'), IF(nNewDim9=1, sNewV9,V9));\r\n sV10=IF(nMappedDim10=1, Expand('%'|sMappedV10|'%'),IF(nNewDim10=1,sNewV10,V10));\r\n sV11=IF(nMappedDim11=1, Expand('%'|sMappedV11|'%'),IF(nNewDim11=1,sNewV11,V11));\r\n sV12=IF(nMappedDim12=1, Expand('%'|sMappedV12|'%'),IF(nNewDim12=1,sNewV12,V12)); \r\n sV13=IF(nMappedDim13=1, Expand('%'|sMappedV13|'%'),IF(nNewDim13=1,sNewV13,V13)); \r\n sV14=IF(nMappedDim14=1, Expand('%'|sMappedV14|'%'),IF(nNewDim14=1,sNewV14,V14)); \r\n sV15=IF(nMappedDim15=1, Expand('%'|sMappedV15|'%'),IF(nNewDim15=1,sNewV15,V15)); \r\n sV16=IF(nMappedDim16=1, Expand('%'|sMappedV16|'%'),IF(nNewDim16=1,sNewV16,V16)); \r\n sV17=IF(nMappedDim17=1, Expand('%'|sMappedV17|'%'),IF(nNewDim17=1,sNewV17,V17)); \r\n sV18=IF(nMappedDim18=1, Expand('%'|sMappedV18|'%'),IF(nNewDim18=1,sNewV18,V18)); \r\n sV19=IF(nMappedDim19=1, Expand('%'|sMappedV19|'%'),IF(nNewDim19=1,sNewV19,V19)); \r\n sV20=IF(nMappedDim20=1, Expand('%'|sMappedV20|'%'),IF(nNewDim20=1,sNewV20,V20)); \r\n sV21=IF(nMappedDim21=1, Expand('%'|sMappedV21|'%'),IF(nNewDim21=1,sNewV21,V21)); \r\n sV22=IF(nMappedDim22=1, Expand('%'|sMappedV22|'%'),IF(nNewDim22=1,sNewV22,V22)); \r\n sV23=IF(nMappedDim23=1, Expand('%'|sMappedV23|'%'),IF(nNewDim23=1,sNewV23,V23)); \r\n sV24=IF(nMappedDim24=1, Expand('%'|sMappedV24|'%'),IF(nNewDim24=1,sNewV24,V24)); \r\n sV25=IF(nMappedDim25=1, Expand('%'|sMappedV25|'%'),IF(nNewDim25=1,sNewV25,V25)); \r\n sV26=IF(nMappedDim26=1, Expand('%'|sMappedV26|'%'),IF(nNewDim26=1,sNewV26,V26)); \r\n sV27=IF(nMappedDim27=1, Expand('%'|sMappedV27|'%'),IF(nNewDim27=1,sNewV27,V27));\r\n sV28=IF(nMappedDim28=1, Expand('%'|sMappedV28|'%'),V28); \r\nElseIf( pFile > 0 );\r\n sV1 =IF(nMappedDim1=1, Expand('%'|sMappedV1|'%'), IF(nNewDim1=1, sNewV1,V2));\r\n sV2 =IF(nMappedDim2=1, Expand('%'|sMappedV2|'%'), IF(nNewDim2=1, sNewV2,V3));\r\n sV3 =IF(nMappedDim3=1, Expand('%'|sMappedV3|'%'), IF(nNewDim3=1, sNewV3,V4));\r\n sV4 =IF(nMappedDim4=1, Expand('%'|sMappedV4|'%'), IF(nNewDim4=1, sNewV4,V5));\r\n sV5 =IF(nMappedDim5=1, Expand('%'|sMappedV5|'%'), IF(nNewDim5=1, sNewV5,V6));\r\n sV6 =IF(nMappedDim6=1, Expand('%'|sMappedV6|'%'), IF(nNewDim6=1, sNewV6,V7));\r\n sV7 =IF(nMappedDim7=1, Expand('%'|sMappedV7|'%'), IF(nNewDim7=1, sNewV7,V8));\r\n sV8 =IF(nMappedDim8=1, Expand('%'|sMappedV8|'%'), IF(nNewDim8=1, sNewV8,V9));\r\n sV9 =IF(nMappedDim9=1, Expand('%'|sMappedV9|'%'), IF(nNewDim9=1, sNewV9,V10));\r\n sV10=IF(nMappedDim10=1, Expand('%'|sMappedV10|'%'),IF(nNewDim10=1,sNewV10,V11));\r\n sV11=IF(nMappedDim11=1, Expand('%'|sMappedV11|'%'),IF(nNewDim11=1,sNewV11,V12));\r\n sV12=IF(nMappedDim12=1, Expand('%'|sMappedV12|'%'),IF(nNewDim12=1,sNewV12,V13)); \r\n sV13=IF(nMappedDim13=1, Expand('%'|sMappedV13|'%'),IF(nNewDim13=1,sNewV13,V14)); \r\n sV14=IF(nMappedDim14=1, Expand('%'|sMappedV14|'%'),IF(nNewDim14=1,sNewV14,V15)); \r\n sV15=IF(nMappedDim15=1, Expand('%'|sMappedV15|'%'),IF(nNewDim15=1,sNewV15,V16)); \r\n sV16=IF(nMappedDim16=1, Expand('%'|sMappedV16|'%'),IF(nNewDim16=1,sNewV16,V17)); \r\n sV17=IF(nMappedDim17=1, Expand('%'|sMappedV17|'%'),IF(nNewDim17=1,sNewV17,V18)); \r\n sV18=IF(nMappedDim18=1, Expand('%'|sMappedV18|'%'),IF(nNewDim18=1,sNewV18,V19)); \r\n sV19=IF(nMappedDim19=1, Expand('%'|sMappedV19|'%'),IF(nNewDim19=1,sNewV19,V20)); \r\n sV20=IF(nMappedDim20=1, Expand('%'|sMappedV20|'%'),IF(nNewDim20=1,sNewV20,V21)); \r\n sV21=IF(nMappedDim21=1, Expand('%'|sMappedV21|'%'),IF(nNewDim21=1,sNewV21,V22)); \r\n sV22=IF(nMappedDim22=1, Expand('%'|sMappedV22|'%'),IF(nNewDim22=1,sNewV22,V23)); \r\n sV23=IF(nMappedDim23=1, Expand('%'|sMappedV23|'%'),IF(nNewDim23=1,sNewV23,V24)); \r\n sV24=IF(nMappedDim24=1, Expand('%'|sMappedV24|'%'),IF(nNewDim24=1,sNewV24,V25)); \r\n sV25=IF(nMappedDim25=1, Expand('%'|sMappedV25|'%'),IF(nNewDim25=1,sNewV25,V26)); \r\n sV26=IF(nMappedDim26=1, Expand('%'|sMappedV26|'%'),IF(nNewDim26=1,sNewV26,V27)); \r\n sV27=IF(nMappedDim27=1, Expand('%'|sMappedV27|'%'),IF(nNewDim27=1,sNewV27,V28));\r\n sV28=IF(nMappedDim28=1, Expand('%'|sMappedV28|'%'),V29);\r\nEndIf;\r\n \r\n##########################################################################################################\r\n### Write data from source file to target cube ###########################################################\r\n\r\n If( nDimensionCount = 2 );\r\n If( CellIsUpdateable( pTgtCube, sV1, sV2 ) = 1 );\r\n sElType = DType( sDim2, sV2 );\r\n IF( SubSt( pTgtCube, 1, 17 ) @= '}ElementSecurity_');\r\n sV3 = IF( sV3 @= '', 'NONE', sV3 );\r\n ElementSecurityPut( sV3, sDim1, sV1, sV2 );\r\n ELSEIF( sElType @= 'AA' );\r\n AttrPutS( sV3, sDim1, sV1, sV2, 1 );\r\n ELSEIF( sElType @= 'AS' );\r\n AttrPutS( sV3, sDim1, sV1, sV2 );\r\n ELSEIF( sElType @= 'AN' );\r\n AttrPutN( StringToNumberEx( sV3, sDecimalSeparator, sThousandSeparator ) * nFactor, sDim1, sV1, sV2 );\r\n ElseIf( sElType @= 'S' );\r\n CellPutS( sV3, pTgtCube, sV1, sV2 );\r\n Else;\r\n nObal = CellGetN( pTgtCube, sV1, sV2 );\r\n nCbal = nObal + StringToNumberEx( sV3, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n CellPutN( nCbal, pTgtCube, sV1, sV2 );\r\n EndIf;\r\n EndIf;\r\n ElseIf( nDimensionCount = 3 );\r\n If( CellIsUpdateable( pTgtCube, sV1, sV2, sV3 ) = 1 );\r\n sElType = DType( sDim3, sV3 );\r\n If( sElType @<> 'S' );\r\n nObal = CellGetN( pTgtCube, sV1, sV2, sV3 );\r\n nCbal = nObal + StringToNumberEx( sV4, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n CellPutN( nCbal, pTgtCube, sV1, sV2, sV3 );\r\n Else;\r\n CellPutS( sV4, pTgtCube, sV1, sV2, sV3 );\r\n EndIf;\r\n EndIf;\r\n ElseIf( nDimensionCount = 4 );\r\n If( CellIsUpdateable( pTgtCube, sV1, sV2, sV3, sV4 ) = 1 );\r\n sElType = DType( sDim4, sV4 );\r\n If( sElType @<> 'S' );\r\n nObal = CellGetN( pTgtCube, sV1, sV2, sV3, sV4);\r\n nCbal = nObal + StringToNumberEx( sV5, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n CellPutN( nCbal, pTgtCube, sV1, sV2, sV3, sV4);\r\n Else;\r\n CellPutS( sV5, pTgtCube, sV1, sV2, sV3, sV4);\r\n EndIf;\r\n EndIf;\r\n ElseIf( nDimensionCount = 5 );\r\n If( CellIsUpdateable( pTgtCube, sV1, sV2, sV3, sV4, sV5 ) = 1 );\r\n sElType = DType( sDim5, sV5 );\r\n If( sElType @<> 'S' );\r\n nObal = CellGetN( pTgtCube, sV1, sV2, sV3, sV4, sV5 );\r\n nCbal = nObal + StringToNumberEx( sV6, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n CellPutN( nCbal, pTgtCube, sV1, sV2, sV3, sV4, sV5 );\r\n Else;\r\n CellPutS( sV6, pTgtCube, sV1, sV2, sV3, sV4, sV5 );\r\n EndIf;\r\n EndIf;\r\n ElseIf( nDimensionCount = 6 );\r\n If( CellIsUpdateable( pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6 ) = 1 );\r\n sElType = DType( sDim6, sV6 );\r\n If( sElType @<> 'S' );\r\n nObal = CellGetN( pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6 );\r\n nCbal = nObal + StringToNumberEx( sV7, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n CellPutN( nCbal, pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6 );\r\n Else;\r\n CellPutS( sV7, pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6 );\r\n EndIf;\r\n EndIf;\r\n ElseIf( nDimensionCount = 7 );\r\n If( CellIsUpdateable( pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7 ) = 1 );\r\n sElType = DType( sDim7, sV7 );\r\n If( sElType @<> 'S' );\r\n nObal = CellGetN( pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7 );\r\n nCbal = nObal + StringToNumberEx( sV8, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n CellPutN( nCbal, pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7 );\r\n Else;\r\n CellPutS( sV8, pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7 );\r\n EndIf;\r\n EndIf;\r\n ElseIf( nDimensionCount = 8 );\r\n If( CellIsUpdateable( pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8 ) = 1 );\r\n sElType = DType( sDim8, sV8 );\r\n If( sElType @<> 'S' );\r\n nObal = CellGetN( pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8 );\r\n nCbal = nObal + StringToNumberEx( sV9, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n CellPutN( nCbal, pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8 );\r\n Else;\r\n CellPutS( sV9, pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8 );\r\n EndIf;\r\n EndIf;\r\n ElseIf( nDimensionCount = 9 );\r\n If( CellIsUpdateable( pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9 ) = 1 );\r\n sElType = DType( sDim9, sV9 );\r\n If( sElType @<> 'S' );\r\n nObal = CellGetN( pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9 );\r\n nCbal = nObal + StringToNumberEx( sV10, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n CellPutN( nCbal, pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9 );\r\n Else;\r\n CellPutS( sV10, pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9 );\r\n EndIf;\r\n EndIf;\r\n ElseIf( nDimensionCount = 10 );\r\n If( CellIsUpdateable( pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10 ) = 1 );\r\n sElType = DType( sDim10, sV10 );\r\n If( sElType @<> 'S' );\r\n nObal = CellGetN( pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10 );\r\n nCbal = nObal + StringToNumberEx( sV11, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n CellPutN( nCbal, pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10 );\r\n Else;\r\n CellPutS( sV11, pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10 );\r\n EndIf;\r\n EndIf;\r\n ElseIf( nDimensionCount = 11 );\r\n If( CellIsUpdateable( pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11 ) = 1 );\r\n sElType = DType( sDim11, sV11 );\r\n If( sElType @<> 'S' );\r\n nObal = CellGetN( pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11 );\r\n nCbal = nObal + StringToNumberEx( sV12, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n CellPutN( nCbal, pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11 );\r\n Else;\r\n CellPutS( sV12, pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11 );\r\n EndIf;\r\n EndIf;\r\n ElseIf( nDimensionCount = 12 );\r\n If( CellIsUpdateable( pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12 ) = 1 );\r\n sElType = DType( sDim12, sV12 );\r\n If( sElType @<> 'S' );\r\n nObal = CellGetN( pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12 );\r\n nCbal = nObal + StringToNumberEx( sV13, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n CellPutN( nCbal, pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12 );\r\n Else;\r\n CellPutS( sV13, pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12 );\r\n EndIf;\r\n EndIf;\r\n ElseIf( nDimensionCount = 13 );\r\n If( CellIsUpdateable( pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12, sV13 ) = 1 );\r\n sElType = DType( sDim13, sV13 );\r\n If( sElType @<> 'S' );\r\n nObal = CellGetN( pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12, sV13 );\r\n nCbal = nObal + StringToNumberEx( sV14, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n CellPutN( nCbal, pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12, sV13 );\r\n Else;\r\n CellPutS( sV14, pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12, sV13 );\r\n EndIf;\r\n EndIf;\r\n ElseIf( nDimensionCount = 14 );\r\n If( CellIsUpdateable( pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12, sV13, sV14 ) = 1 );\r\n sElType = DType( sDim14, sV14 );\r\n If( sElType @<> 'S' );\r\n nObal = CellGetN( pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12, sV13, sV14 );\r\n nCbal = nObal + StringToNumberEx( sV15, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n CellPutN( nCbal, pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12, sV13, sV14 );\r\n Else;\r\n CellPutS( sV15, pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12, sV13, sV14 );\r\n EndIf;\r\n EndIf;\r\n ElseIf( nDimensionCount = 15 );\r\n If( CellIsUpdateable( pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12, sV13, sV14, sV15 ) = 1 );\r\n sElType = DType( sDim15, sV15 );\r\n If( sElType @<> 'S' );\r\n nObal = CellGetN( pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12, sV13, sV14, sV15 );\r\n nCbal = nObal + StringToNumberEx( sV16, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n CellPutN( nCbal, pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12, sV13, sV14, sV15 );\r\n Else;\r\n CellPutS( sV16, pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12, sV13, sV14, sV15 );\r\n EndIf;\r\n EndIf;\r\n ElseIf( nDimensionCount = 16 );\r\n If( CellIsUpdateable( pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12, sV13, sV14, sV15, sV16 ) = 1 );\r\n sElType = DType( sDim16, sV16 );\r\n If( sElType @<> 'S' );\r\n nObal = CellGetN( pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12, sV13, sV14, sV15, sV16 );\r\n nCbal = nObal + StringToNumberEx( sV17, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n CellPutN( nCbal, pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12, sV13, sV14, sV15, sV16 );\r\n Else;\r\n CellPutS( sV17, pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12, sV13, sV14, sV15, sV16 );\r\n EndIf;\r\n EndIf;\r\n ElseIf( nDimensionCount = 17 );\r\n If( CellIsUpdateable( pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12, sV13, sV14, sV15, sV16, sV17 ) = 1 );\r\n sElType = DType( sDim17, sV17 );\r\n If( sElType @<> 'S' );\r\n nObal = CellGetN( pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12, sV13, sV14, sV15, sV16, sV17 );\r\n nCbal = nObal + StringToNumberEx( sV18, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n CellPutN( nCbal, pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12, sV13, sV14, sV15, sV16, sV17 );\r\n Else;\r\n CellPutS( sV18, pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12, sV13, sV14, sV15, sV16, sV17 );\r\n EndIf;\r\n EndIf;\r\n ElseIf( nDimensionCount = 18 );\r\n If( CellIsUpdateable( pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12, sV13, sV14, sV15, sV16, sV17, sV18 ) = 1 );\r\n sElType = DType( sDim18, sV18 );\r\n If( sElType @<> 'S' );\r\n nObal = CellGetN( pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12, sV13, sV14, sV15, sV16, sV17, sV18 );\r\n nCbal = nObal + StringToNumberEx( sV19, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n CellPutN( nCbal, pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12, sV13, sV14, sV15, sV16, sV17, sV18 );\r\n Else;\r\n CellPutS( sV19, pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12, sV13, sV14, sV15, sV16, sV17, sV18 );\r\n EndIf;\r\n EndIf;\r\n ElseIf( nDimensionCount = 19 );\r\n If( CellIsUpdateable( pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12, sV13, sV14, sV15, sV16, sV17, sV18, sV19 ) = 1 );\r\n sElType = DType( sDim19, sV19 );\r\n If( sElType @<> 'S' );\r\n nObal = CellGetN( pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12, sV13, sV14, sV15, sV16, sV17, sV18, sV19 );\r\n nCbal = nObal + StringToNumberEx( sV20, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n CellPutN( nCbal, pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12, sV13, sV14, sV15, sV16, sV17, sV18, sV19 );\r\n Else;\r\n CellPutS( sV20, pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12, sV13, sV14, sV15, sV16, sV17, sV18, sV19 );\r\n EndIf;\r\n EndIf;\r\n ElseIf( nDimensionCount = 20 );\r\n If( CellIsUpdateable( pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12, sV13, sV14, sV15, sV16, sV17, sV18, sV19, sV20 ) = 1 );\r\n sElType = DType( sDim20, sV20 );\r\n If( sElType @<> 'S' );\r\n nObal = CellGetN( pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12, sV13, sV14, sV15, sV16, sV17, sV18, sV19, sV20 );\r\n nCbal = nObal + StringToNumberEx( sV21, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n CellPutN( nCbal, pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12, sV13, sV14, sV15, sV16, sV17, sV18, sV19, sV20 );\r\n Else;\r\n CellPutS( sV21, pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12, sV13, sV14, sV15, sV16, sV17, sV18, sV19, sV20 );\r\n EndIf;\r\n EndIf; \r\n ElseIf( nDimensionCount = 21 );\r\n If( CellIsUpdateable( pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12, sV13, sV14, sV15, sV16, sV17, sV18, sV19, sV20, sV21 ) = 1 );\r\n sElType = DType( sDim21, sV21 );\r\n If( sElType @<> 'S' );\r\n nObal = CellGetN( pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12, sV13, sV14, sV15, sV16, sV17, sV18, sV19, sV20, sV21 );\r\n nCbal = nObal + StringToNumberEx( sV22, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n CellPutN( nCbal, pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12, sV13, sV14, sV15, sV16, sV17, sV18, sV19, sV20, sV21 );\r\n Else;\r\n CellPutS( sV22, pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12, sV13, sV14, sV15, sV16, sV17, sV18, sV19, sV20, sV21 );\r\n EndIf;\r\n EndIf; \r\n ElseIf( nDimensionCount = 22 );\r\n If( CellIsUpdateable( pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12, sV13, sV14, sV15, sV16, sV17, sV18, sV19, sV20, sV21, sV22 ) = 1 );\r\n sElType = DType( sDim22, sV22 );\r\n If( sElType @<> 'S' );\r\n nObal = CellGetN( pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12, sV13, sV14, sV15, sV16, sV17, sV18, sV19, sV20, sV21, sV22 );\r\n nCbal = nObal + StringToNumberEx( sV23, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n CellPutN( nCbal, pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12, sV13, sV14, sV15, sV16, sV17, sV18, sV19, sV20, sV21, sV22 );\r\n Else;\r\n CellPutS( sV23, pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12, sV13, sV14, sV15, sV16, sV17, sV18, sV19, sV20, sV21, sV22 );\r\n EndIf;\r\n EndIf;\r\n ElseIf( nDimensionCount = 23 );\r\n If( CellIsUpdateable( pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12, sV13, sV14, sV15, sV16, sV17, sV18, sV19, sV20, sV21, sV22, sV23 ) = 1 );\r\n sElType = DType( sDim23, sV23 );\r\n If( sElType @<> 'S' );\r\n nObal = CellGetN( pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12, sV13, sV14, sV15, sV16, sV17, sV18, sV19, sV20, sV21, sV22, sV23 );\r\n nCbal = nObal + StringToNumberEx( sV24, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n CellPutN( nCbal, pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12, sV13, sV14, sV15, sV16, sV17, sV18, sV19, sV20, sV21, sV22, sV23 );\r\n Else;\r\n CellPutS( sV24, pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12, sV13, sV14, sV15, sV16, sV17, sV18, sV19, sV20, sV21, sV22, sV23 );\r\n EndIf;\r\n EndIf; \r\n ElseIf( nDimensionCount = 24 );\r\n If( CellIsUpdateable( pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12, sV13, sV14, sV15, sV16, sV17, sV18, sV19, sV20, sV21, sV22, sV23, sV24 ) = 1 );\r\n sElType = DType( sDim24, sV24 );\r\n If( sElType @<> 'S' );\r\n nObal = CellGetN( pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12, sV13, sV14, sV15, sV16, sV17, sV18, sV19, sV20, sV21, sV22, sV23, sV24 );\r\n nCbal = nObal + StringToNumberEx( sV25, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n CellPutN( nCbal, pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12, sV13, sV14, sV15, sV16, sV17, sV18, sV19, sV20, sV21, sV22, sV23, sV24 );\r\n Else;\r\n CellPutS( sV25, pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12, sV13, sV14, sV15, sV16, sV17, sV18, sV19, sV20, sV21, sV22, sV23, sV24 );\r\n EndIf;\r\n EndIf; \r\n ElseIf( nDimensionCount = 25 );\r\n If( CellIsUpdateable( pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12, sV13, sV14, sV15, sV16, sV17, sV18, sV19, sV20, sV21, sV22, sV23, sV24, sV25 ) = 1 );\r\n sElType = DType( sDim25, sV25 );\r\n If( sElType @<> 'S' );\r\n nObal = CellGetN( pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12, sV13, sV14, sV15, sV16, sV17, sV18, sV19, sV20, sV21, sV22, sV23, sV24, sV25 );\r\n nCbal = nObal + StringToNumberEx( sV26, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n CellPutN( nCbal, pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12, sV13, sV14, sV15, sV16, sV17, sV18, sV19, sV20, sV21, sV22, sV23, sV24, sV25 );\r\n Else;\r\n CellPutS( sV26, pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12, sV13, sV14, sV15, sV16, sV17, sV18, sV19, sV20, sV21, sV22, sV23, sV24, sV25 );\r\n EndIf;\r\n EndIf; \r\n ElseIf( nDimensionCount = 26 );\r\n If( CellIsUpdateable( pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12, sV13, sV14, sV15, sV16, sV17, sV18, sV19, sV20, sV21, sV22, sV23, sV24, sV25, sV26 ) = 1 );\r\n sElType = DType( sDim26, sV26 );\r\n If( sElType @<> 'S' );\r\n nObal = CellGetN( pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12, sV13, sV14, sV15, sV16, sV17, sV18, sV19, sV20, sV21, sV22, sV23, sV24, sV25, sV26 );\r\n nCbal = nObal + StringToNumberEx( sV27, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n CellPutN( nCbal, pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12, sV13, sV14, sV15, sV16, sV17, sV18, sV19, sV20, sV21, sV22, sV23, sV24, sV25, sV26 );\r\n Else;\r\n CellPutS( sV27, pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12, sV13, sV14, sV15, sV16, sV17, sV18, sV19, sV20, sV21, sV22, sV23, sV24, sV25, sV26 );\r\n EndIf;\r\n EndIf; \r\n ElseIf( nDimensionCount = 27 );\r\n If( CellIsUpdateable( pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12, sV13, sV14, sV15, sV16, sV17, sV18, sV19, sV20, sV21, sV22, sV23, sV24, sV25, sV26, sV27 ) = 1 );\r\n sElType = DType( sDim27, sV27 );\r\n If( sElType @<> 'S' );\r\n nObal = CellGetN( pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12, sV13, sV14, sV15, sV16, sV17, sV18, sV19, sV20, sV21, sV22, sV23, sV24, sV25, sV26, sV27 );\r\n nCbal = nObal + StringToNumberEx( sV28, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n CellPutN( nCbal, pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12, sV13, sV14, sV15, sV16, sV17, sV18, sV19, sV20, sV21, sV22, sV23, sV24, sV25, sV26, sV27 );\r\n Else;\r\n CellPutS( sV28, pTgtCube, sV1, sV2, sV3, sV4, sV5, sV6, sV7, sV8, sV9, sV10, sV11, sV12, sV13, sV14, sV15, sV16, sV17, sV18, sV19, sV20, sV21, sV22, sV23, sV24, sV25, sV26, sV27 );\r\n EndIf;\r\n EndIf; \r\n \r\n EndIf;\r\n \r\n### End Data ###", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n## Zero Source\r\nIf( pZeroSource = 1 & nErrors = 0 );\r\n ViewZeroOut( pSrcCube, sView );\r\nEndIf;\r\n\r\n### Delete export file if used\r\nIf( pFile = 1 );\r\n ASCIIDelete( cFile );\r\nEndIf;\r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully copied data from %pSrcCube% cube to the %pTgtCube% cube.' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\nEndIf;\r\n\r\n### End Epilog ###", "HasSecurityAccess": true, - "UIData": "_ParameterConstraints=e30=\f", + "UIData": "", "DataSource": { "Type": "TM1CubeView", "dataSourceNameForClient": "Bedrock Source Cube", @@ -13,123 +13,111 @@ "view": "Default" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pSrcCube", - "Prompt": "REQUIRED: Cube data is being copied from", + "Prompt": "REQUIRED: Source cube name", "Value": "", "Type": "String" }, { "Name": "pFilter", - "Prompt": "OPTIONAL: Filter on source cube in format Year\u00a6 2006 + 2007 & Scenario\u00a6 Actual + Budget. Blank for whole cube", + "Prompt": "OPTIONAL: Filter on cube in format: 'dim_one\u00a6 el_one + el_two & dim_two\u00a6 el_one + el_two'", "Value": "", "Type": "String" }, { "Name": "pFilterParallel", - "Prompt": "OPTIONAL: Parallelization Filter: Month\u00a6Q1+Q2+Q3+Q4 (Blank=run single threaded). Single dimension parallel slices. Will be added to filter single element at a time. Dimension must not be part of filter", + "Prompt": "OPTIONAL: Parallelization filter in format: dim_one\u00a6 el_one + el_two. Dimension must not be part of filter", "Value": "", "Type": "String" }, { "Name": "pParallelThreads", - "Prompt": "Maximum number of threads to run when parallel processing is enabled ( if <2 will execute one thread, but parallel filter is still applied )", + "Prompt": "OPTIONAL: Maximum number of threads to run when parallel processing is enabled (Default = 0)", "Value": 0, "Type": "Numeric" }, { "Name": "pTgtCube", - "Prompt": "REQUIRED: Name of cube to copy the values to", + "Prompt": "REQUIRED: Target cube name", "Value": "", "Type": "String" }, { "Name": "pMappingToNewDims", - "Prompt": "REQUIRED IF TARGET HAS DIMS NOT IN SOURCE: DimX\u00a6InputElementForDimX & DimY\u00a6InputElementForDimY (specify an N level element for each new dim)", + "Prompt": "OPTIONAL: Required if target has dims not in source. Format: 'dim_one\u00a6 el_one & dim_two\u00a6 el_two'", "Value": "", "Type": "String" }, { "Name": "pSuppressConsol", - "Prompt": "OPTIONAL: Suppress Consolidations (Skip = 1) Only use 0 for strings", + "Prompt": "OPTIONAL: Suppress consolidated values (Boolean. Default = 1)", "Value": 1, "Type": "Numeric" }, { "Name": "pSuppressConsolStrings", - "Prompt": "OPTIONAL: Suppress Consolidated String Cells (Skip = 1)", - "Value": 0, + "Prompt": "OPTIONAL: Suppress consolidated string cells (Boolean. Default = 1)", + "Value": 1, "Type": "Numeric" }, { "Name": "pSuppressRules", - "Prompt": "OPTIONAL: Suppress Rules (Skip = 1)", + "Prompt": "OPTIONAL: Suppress rules (Boolean. Default = 1)", "Value": 1, "Type": "Numeric" }, { "Name": "pSuppressZero", - "Prompt": "OPTIONAL: Suppress Null Cells (Skip = 1)", + "Prompt": "OPTIONAL: Suppress zeroes (Boolean. Default = 1)", "Value": 1, "Type": "Numeric" }, { "Name": "pZeroTarget", - "Prompt": "OPTIONAL: Zero out Target Element PRIOR to Copy? (Boolean 1=True) Clears combination of pFilter and pMappingToNewDims", + "Prompt": "OPTIONAL: Zero out target before start of process (Boolean. Default = 1)", "Value": 1, "Type": "Numeric" }, { "Name": "pZeroSource", - "Prompt": "OPTIONAL: Zero out Source Element AFTER Copy? (Boolean 1=True). If pFilter is blank the whole source cube is cleared!", + "Prompt": "OPTIONAL: Zero out source after end of process (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { "Name": "pFactor", - "Prompt": "OPTIONAL: Multiply source value by factor (1 keeps the value as is). To modify existing values make the target element the same as the source with pZeroTarget = 0", + "Prompt": "OPTIONAL: Multiply source values by factor (Default = 1)", "Value": 1, "Type": "Numeric" }, { "Name": "pDimDelim", - "Prompt": "OPTIONAL. Delimiter for start of Dimension/Element set", + "Prompt": "OPTIONAL: Delimiter for start of dimension/element set in filter parameters (Default = '&')", "Value": "&", "Type": "String" }, { "Name": "pEleStartDelim", - "Prompt": "OPTIONAL: Delimiter for start of element list", + "Prompt": "OPTIONAL: Delimiter for start of element list in filter parameters (Default = '\u00a6')", "Value": "\u00a6", "Type": "String" }, { "Name": "pEleDelim", - "Prompt": "OPTIONAL: Delimiter between elements", + "Prompt": "OPTIONAL: Delimiter between elements in filter parameters (Default = '+')", "Value": "+", "Type": "String" }, { "Name": "pTemp", - "Prompt": "OPTIONAL: Delete temporary view and Subset ( 0 = Retain View and Subsets 1 = Delete View and Subsets 2 = Delete View only )", + "Prompt": "OPTIONAL: Delete/create temporary objects (0 = Do not delete, 1 = Delete, 2 = if view and subsets are created, keep only subsets)", "Value": 1, "Type": "Numeric" }, { "Name": "pSandbox", - "Prompt": "OPTIONAL: To use sandbox not base data enter the sandbox name (invalid name will result in process error)", + "Prompt": "OPTIONAL: Use sandbox", "Value": "", "Type": "String" }, @@ -141,37 +129,43 @@ }, { "Name": "pDelim", - "Prompt": "OPTIONAL: For pFile > 0. AsciiOutput delimiter character (Default = ',' exactly 3 digits = ASCII code)", - "Value": ",", + "Prompt": "OPTIONAL: Delimiter for list parameters (Default = '&')", + "Value": "&", "Type": "String" }, { "Name": "pQuote", - "Prompt": "OPTIONAL: For pFile > 0. AsciiOutput quote character (Default = '\"' exactly 3 digits = ASCII code)", + "Prompt": "OPTIONAL: Quote character (2 or 3 digits = ASCII code. Default = '\"')", "Value": "\"", "Type": "String" }, { "Name": "pDecimalSeparator", - "Prompt": "OPTIONAL: For pFile > 0. Decimal separator for conversion of NumberToStringEx and StringToNumberEx (default = '.' exactly 3 digits = ASCII code)", + "Prompt": "OPTIONAL: Decimal separator for string/number conversion (Exactly 3 digits = ASCII code. Default ='.')", "Value": ".", "Type": "String" }, { "Name": "pThousandSeparator", - "Prompt": "OPTIONAL: For pFile > 0. Thousand separator for conversion of NumberToStringEx and StringToNumberEx (default = ',' exactly 3 digits = ASCII code)", + "Prompt": "OPTIONAL: Thousand separator for string/number conversion (Exactly 3 digits = ASCII code. Default = ',')", "Value": ",", "Type": "String" }, { "Name": "pSubN", - "Prompt": "OPTIONAL: Create N level subset for all dims not mentioned in pFilter", + "Prompt": "OPTIONAL: Create N level subset for all dims not specified (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { - "Name": "pThreadMode", - "Prompt": "DO NOT USE: Internal parameter only, please do not use", + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, @@ -180,6 +174,18 @@ "Prompt": "OBSOLETE: This parameter does nothing and is only included for backwards compatability", "Value": 0, "Type": "Numeric" + }, + { + "Name": "pThreadMode", + "Prompt": "DO NOT USE: Internal parameter only, please do not use", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [ @@ -387,35 +393,5 @@ "EndByte": 0 } ], - "VariablesUIData": [ - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f" - ] + "VariablesUIData": [] } \ No newline at end of file diff --git a/bedrock_processes_json/}bedrock.cube.data.copy.json b/bedrock_processes_json/}bedrock.cube.data.copy.json index 3b0f482..c5ae8cb 100644 --- a/bedrock_processes_json/}bedrock.cube.data.copy.json +++ b/bedrock_processes_json/}bedrock.cube.data.copy.json @@ -1,11 +1,11 @@ { "Name": "}bedrock.cube.data.copy", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.cube.data.copy', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pCube', '', 'pSrcView', '', 'pTgtView', '', 'pFilter', '',\r\n \t'pFilterParallel', '', 'pParallelThreads', 0,\r\n \t'pEleMapping', '', 'pMappingDelim', '->',\r\n \t'pDimDelim', '&', 'pEleStartDelim', '\u00a6', 'pEleDelim', '+',\r\n \t'pFactor', 1, 'pSuppressConsol', 1, 'pSuppressConsolStrings', 0, 'pSuppressRules', 1, 'pSuppressZero', 1, 'pIncludeDescendants',0, 'pCumulate', 0,\r\n \t'pZeroTarget', 1, 'pZeroSource', 0,\r\n \t'pTemp', 1, 'pCubeLogging', 0, 'pSandbox', '', \r\n \t'pFile', 0, 'pDelim', ',', 'pQuote', '\"', 'pDecimalSeparator', '.', 'pThousandSeparator', ',', 'pSubN', 0\r\n );\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n#################################################################################################\r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n#################################################################################################\r\n\r\n#Region @DOC\r\n# Description:\r\n# This TI is intended to copy data from one element of a dimension to another in the same cube.\r\n\r\n# Use case: Mainly used in production environments.\r\n# 1/ Typically, this would be used to archive a Budget or Forecast element of a version dimension.\r\n# 2/ Could also be used to prepopulate a version from a prior year.\r\n\r\n# Note:\r\n# Naturally, a valid cube name (pCube) is required. otherwise the process will abort.\r\n# Element mapping (pEleMapping) is also required, otherwise the process will abort.\r\n# A filter parameter (pFilter) can also be used to filter dimensions that have not been mapped.\r\n# Source (pSrcView) & target (pTgtView) views will be assigned temporary names if left blank.\r\n# All other parameters may be left as is but be sure to use them appropriately when specifying pEleMapping & pFilter parameters.\r\n# - Since this TI has a view as a data source, it requires the implicit variables NValue, SValue and Value_is_String.\r\n# - To edit this TI in Architect a tmp cube with minimum 24 dims is needed as the preview data source or set the data\r\n# source to ASCII and manually edit the TI in notepad after saving to add back the required implicit view variables.\r\n# - If using the pFilterParallel parameter the **single dimension** used as the \"parallelization slicer\" cannot appear in\r\n# the pFilter and pEleMapping parameters.\r\n# - When using parallelization via the *RunProcess* function the elements listed in pFilterParallel will be split one_at_a_time\r\n# and passed to a recursive call of the process being added to pFilter.\r\n#EndRegion @DOC\r\n\r\nIf( pThreadControlFile @<> '' );\r\n LogOutput( 'INFO', 'Executed as subTI with Thread Control File: ' | pThreadControlFile );\r\nEndIf;\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode = 0;\r\n# Target Filter Variable for shell processes\r\nStringGlobalVariable('sTargetFilter');\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent= 'Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pCube:%pCube%, pSrcView:%pSrcView%, pTgtView:%pTgtView%, pFilter:%pFilter%, pFilterParallel:%pFilterParallel%, pParallelThreads:%pParallelThreads%, pEleMapping:%pEleMapping%, pMappingDelim:%pMappingDelim%, pDimDelim:%pDimDelim%, pEleStartDelim:%pEleStartDelim%, pEleDelim:%pEleDelim%, pFactor:%pFactor%, pSuppressConsol:%pSuppressConsol%, pSuppressConsolStrings:%pSuppressConsolStrings%, pSuppressRules:%pSuppressRules%, pSuppressZero:%pSuppressZero% pIncludeDescendants %pIncludeDescendants% pCumulate:%pCumulate% pZeroTarget:%pZeroTarget%, pZeroSource:%pZeroSource%, pTemp:%pTemp%, pCubeLogging:%pCubeLogging%, pSandbox:%pSandbox%, pFile:%pFile%.';\r\ncDefaultView = Expand( '%cThisProcName%_%cTimeStamp%_%cRandomInt%' );\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) );\r\nENDIF;\r\n\r\n# Variables\r\nnDataCount = 0;\r\nnExistingSourceFlag = 0;\r\nnAttrCubeFlag = 0;\r\ncSuffixSource = 'S';\r\ncSuffixTarget = 'T';\r\ncPrefixElementAttributes = '}ElementAttributes_';\r\ncDimCountMax = 27;\r\nsDimCountMax = NumberToString( cDimCountMax );\r\nnFactor = If( pFactor = 0, 1, pFactor );\r\ncLenASCIICode = 3;\r\n\r\n## check operating system\r\nIf( SubSt( GetProcessErrorFileDirectory, 2, 1 ) @= ':' );\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nElseIf( Scan( '/', GetProcessErrorFileDirectory ) > 0 );\r\n sOS = 'Linux';\r\n sOSDelim = '/';\r\nElse;\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nEndIf;\r\n\r\n# Validate file delimiter & quote character\r\nIf( pDelim @= '' );\r\n pDelim = ',';\r\nElse;\r\n # If length of pDelim is exactly 3 chars and each of them is decimal digit, then the pDelim is entered as ASCII code\r\n nValid = 0;\r\n If ( LONG(pDelim) = cLenASCIICode );\r\n nChar = 1;\r\n While ( nChar <= cLenASCIICode );\r\n If( CODE( pDelim, nChar ) >= CODE( '0', 1 ) & CODE( pDelim, nChar ) <= CODE( '9', 1 ) );\r\n nValid = 1;\r\n Else;\r\n nValid = 0;\r\n Break;\r\n EndIf;\r\n nChar = nChar + 1;\r\n End;\r\n EndIf;\r\n If ( nValid<>0 );\r\n pDelim=CHAR(StringToNumber( pDelim ));\r\n Else;\r\n pDelim = SubSt( Trim( pDelim ), 1, 1 );\r\n EndIf;\r\nEndIf;\r\n\r\nIf( pQuote @= '' );\r\n ## Use no quote character\r\nElse;\r\n # If length of pQuote is exactly 3 chars and each of them is decimal digit, then the pQuote is entered as ASCII code\r\n nValid = 0;\r\n If ( LONG(pQuote) = cLenASCIICode );\r\n nChar = 1;\r\n While ( nChar <= cLenASCIICode );\r\n If( CODE( pQuote, nChar ) >= CODE( '0', 1 ) & CODE( pQuote, nChar ) <= CODE( '9', 1 ) );\r\n nValid = 1;\r\n Else;\r\n nValid = 0;\r\n Break;\r\n EndIf;\r\n nChar = nChar + 1;\r\n End;\r\n EndIf;\r\n If ( nValid<>0 );\r\n pQuote=CHAR(StringToNumber( pQuote ));\r\n Else;\r\n pQuote = SubSt( Trim( pQuote ), 1, 1 );\r\n EndIf;\r\nEndIf;\r\n\r\n## File location for indirect data copy\r\ncDir = GetProcessErrorFileDirectory;\r\ncFileName = LOWER(pCube) | cTimeStamp | cRandomInt | '.csv';\r\ncFile = cDir | cFileName;\r\ncTitleRows = 1;\r\ncDelimiter = pDelim;\r\ncQuote = pQuote;\r\n\r\n# nMappedDimX is a binary switch used to keep track of which dimensions have been mapped from the source to the target\r\nnMappedDim1 = 0;\r\nnMappedDim2 = 0;\r\nnMappedDim3 = 0;\r\nnMappedDim4 = 0;\r\nnMappedDim5 = 0;\r\nnMappedDim6 = 0;\r\nnMappedDim7 = 0;\r\nnMappedDim8 = 0;\r\nnMappedDim9 = 0;\r\nnMappedDim10 = 0;\r\nnMappedDim11 = 0;\r\nnMappedDim12 = 0;\r\nnMappedDim13 = 0;\r\nnMappedDim14 = 0;\r\nnMappedDim15 = 0;\r\nnMappedDim16 = 0;\r\nnMappedDim17 = 0;\r\nnMappedDim18 = 0;\r\nnMappedDim19 = 0;\r\nnMappedDim20 = 0;\r\nnMappedDim21 = 0;\r\nnMappedDim22 = 0;\r\nnMappedDim23 = 0;\r\nnMappedDim24 = 0;\r\nnMappedDim25 = 0;\r\nnMappedDim26 = 0;\r\nnMappedDim27 = 0;\r\n\r\n### Determine dimensions in target cube - we need to know this to test the cell type before loading ###\r\nsDim1 = TabDim( pCube, 1 );\r\nsDim2 = TabDim( pCube, 2 );\r\nsDim3 = TabDim( pCube, 3 );\r\nsDim4 = TabDim( pCube, 4 );\r\nsDim5 = TabDim( pCube, 5 );\r\nsDim6 = TabDim( pCube, 6 );\r\nsDim7 = TabDim( pCube, 7 );\r\nsDim8 = TabDim( pCube, 8 );\r\nsDim9 = TabDim( pCube, 9 );\r\nsDim10 = TabDim( pCube, 10 );\r\nsDim11 = TabDim( pCube, 11 );\r\nsDim12 = TabDim( pCube, 12 );\r\nsDim13 = TabDim( pCube, 13 );\r\nsDim14 = TabDim( pCube, 14 );\r\nsDim15 = TabDim( pCube, 15 );\r\nsDim16 = TabDim( pCube, 16 );\r\nsDim17 = TabDim( pCube, 17 );\r\nsDim18 = TabDim( pCube, 18 );\r\nsDim19 = TabDim( pCube, 19 );\r\nsDim20 = TabDim( pCube, 20 );\r\nsDim21 = TabDim( pCube, 21 );\r\nsDim22 = TabDim( pCube, 22 );\r\nsDim23 = TabDim( pCube, 23 );\r\nsDim24 = TabDim( pCube, 24 );\r\nsDim25 = TabDim( pCube, 25 );\r\nsDim26 = TabDim( pCube, 26 );\r\nsDim27 = TabDim( pCube, 27 );\r\n\r\n###########################\r\n### Validate Parameters ###\r\n###########################\r\nnErrors = 0;\r\n\r\n## Default filter delimiters\r\nIf( pDimDelim @= '' );\r\n pDimDelim = '&';\r\nEndIf;\r\n\r\nIf( pEleStartDelim@= '' );\r\n pEleStartDelim= '\u00a6';\r\nEndIf;\r\n\r\nIf( pEleDelim @= '' );\r\n pEleDelim = '+';\r\nEndIf;\r\n\r\nIf( pMappingDelim @= '' );\r\n pMappingDelim = '->';\r\nEndIf;\r\n\r\nIf( pDecimalSeparator @= '' );\r\n \tpDecimalSeparator = '.';\r\nEndIf;\r\nIf ( LONG(pDecimalSeparator) = cLenASCIICode );\r\n nValid = 0;\r\n nChar = 1;\r\n While ( nChar <= cLenASCIICode );\r\n If( CODE( pDecimalSeparator, nChar ) >= CODE( '0', 1 ) & CODE( pDecimalSeparator, nChar ) <= CODE( '9', 1 ) );\r\n nValid = 1;\r\n Else;\r\n nValid = 0;\r\n Break;\r\n EndIf;\r\n nChar = nChar + 1;\r\n End;\r\n If ( nValid<>0 );\r\n pDecimalSeparator = CHAR(StringToNumber( pDecimalSeparator ));\r\n Else;\r\n pDecimalSeparator = SubSt( Trim( pDecimalSeparator ), 1, 1 );\r\n EndIf;\r\nEndIf;\r\nsDecimalSeparator = pDecimalSeparator;\r\n\r\nIf( pThousandSeparator @= '' );\r\n \tpThousandSeparator = ',';\r\nEndIf;\r\nIf ( LONG(pThousandSeparator) = cLenASCIICode );\r\n nValid = 0;\r\n nChar = 1;\r\n While ( nChar <= cLenASCIICode );\r\n If( CODE( pThousandSeparator, nChar ) >= CODE( '0', 1 ) & CODE( pThousandSeparator, nChar ) <= CODE( '9', 1 ) );\r\n nValid = 1;\r\n Else;\r\n nValid = 0;\r\n Break;\r\n EndIf;\r\n nChar = nChar + 1;\r\n End;\r\n If ( nValid<>0 );\r\n pThousandSeparator = CHAR(StringToNumber( pThousandSeparator ));\r\n Else;\r\n pThousandSeparator = SubSt( Trim( pThousandSeparator ), 1, 1 );\r\n EndIf;\r\nEndIf;\r\nsThousandSeparator = pThousandSeparator;\r\n\r\n# Validate cube\r\nIf( Trim( pCube ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No cube specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( CubeExists( pCube ) = 0 );\r\n nErrors = nErrors + 1;\r\n sMessage = Expand( 'Invalid source cube specified: %pCube%.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### Determine number of dims in target cube ###\r\nnCount = 1;\r\nWhile( TabDim( pCube, nCount ) @<> '' );\r\n sDimension = TabDim( pCube, nCount );\r\n nCount = nCount + 1;\r\nEnd;\r\nnDimensionCount = nCount - 1;\r\n\r\n## If dimension count exceeds the current maximum then terminate process\r\nIf( nDimensionCount > cDimCountMax );\r\n nErrors = nErrors + 1;\r\n sMessage = 'Cube has too many dimensions: %pCube%. Max %sDimCountMax% dims catered for, TI must be altered to accommodate.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n## Validate the View parameter\r\nIf( TRIM(pSrcView) @<> '' & TRIM(pSrcView) @= TRIM(pTgtView) );\r\n nErrors = nErrors + 1;\r\n sMessage = Expand( 'Source and Target Views can not be the same: %pSrcView%.' ) ;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n## Validate the View parameter\r\nIf( TRIM( pSrcView) @= '' );\r\n cViewSource = Expand( '%cDefaultView%_%cSuffixSource%' ) ;\r\nElse ;\r\n cViewSource = pSrcView ;\r\n nExistingSourceFlag = 1;\r\nEndIf;\r\n\r\n## Validate the View parameter\r\nIf( TRIM( pTgtView ) @= '' );\r\n cViewTarget = Expand( '%cDefaultView%_%cSuffixTarget%' ) ;\r\nElse ;\r\n cViewTarget = pTgtView ;\r\nEndIf;\r\n\r\n# Validate parallelization filter\r\nIf( Scan( pEleStartDelim, pFilterParallel ) > 0 );\r\n sDimParallel = SubSt( pFilterParallel, 1, Scan( pEleStartDelim, pFilterParallel ) - 1 );\r\n If( Scan( Lower(sDimParallel) | pEleStartDelim, Lower(pFilter) ) > 0 );\r\n sMessage = 'Parallelization dimension %sDimParallel% cannot exist in filter.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n EndIf;\r\n If( Scan( Lower(sDimParallel) | pEleStartDelim, Lower(pEleMapping) ) > 0 );\r\n sMessage = 'Parallelization dimension %sDimParallel% cannot exist in element mapping.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n EndIf;\r\nEndIf;\r\n\r\n# Validate Max Threads\r\nIf( pParallelThreads > 0 );\r\n nMaxThreads = pParallelThreads;\r\nElse;\r\n nMaxThreads = 1;\r\nEndIf;\r\n\r\n# Validate Mapping parameter\r\nIf( pDimDelim @= pEleStartDelim % pDimDelim @= pEleDelim % pEleStartDelim @= pEleDelim );\r\n sMessage = 'The delimiters cannot me the same.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate Mapping parameter\r\nIf( TRIM( pEleMapping ) @<> '' & TRIM( pMappingDelim) @= '');\r\n nErrors = nErrors + 1;\r\n sMessage = 'Mapping Delimiter & Element Mapping can not both be empty.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndif;\r\n\r\n# Validate Sandbox\r\nIf( TRIM( pSandbox ) @<> '' );\r\n If( ServerSandboxExists( pSandbox ) = 0 );\r\n SetUseActiveSandboxProperty( 0 );\r\n nErrors = nErrors + 1;\r\n sMessage = Expand('Sandbox %pSandbox% is invalid for the current user.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n Else;\r\n ServerActiveSandboxSet( pSandbox );\r\n SetUseActiveSandboxProperty( 1 );\r\n EndIf;\r\nElse;\r\n SetUseActiveSandboxProperty( 0 );\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 );\r\n ProcessQuit;\r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n########## pEleMapping ######################################################\r\n### Split ElementMapping parameter and create variables to be substituted ###\r\n################################################################################################# #############\r\nsElementMapping = TRIM( pEleMapping );\r\nsMappingDelimiter = TRIM( pMappingDelim );\r\nsElementStartDelim = TRIM( pEleStartDelim );\r\nsDelimDim = TRIM( pDimDelim );\r\nsDecimalSeparator = TRIM(pDecimalSeparator);\r\nsThousandSeparator = TRIM(pThousandSeparator);\r\nsFilter = TRIM( pFilter);\r\nsTargetFilter = '';\r\nnSuppressConsol = pSuppressConsol;\r\nnChar = 1;\r\nnCharCount = LONG( sElementMapping );\r\n\r\n# If there's no element mapping then the process can be used to multiply existing value by a factor\r\nIf( nCharCount > 0 );\r\n\r\n sWord = '';\r\n sLastDelim = '';\r\n\r\n # Add a trailing element delimiter so that the last element is picked up\r\n If( nCharCount > 0 );\r\n sElementMapping = sElementMapping | sMappingDelimiter ;\r\n nCharCount = nCharCount + LONG(sMappingDelimiter );\r\n EndIf;\r\n\r\n WHILE (nChar <= nCharCount);\r\n sChar = SUBST( sElementMapping, nChar, 1);\r\n\r\n # Used for delimiters, required for multiple character delimiters\r\n sDelim = '';\r\n nAddExtra = 0;\r\n\r\n # Ignore spaces\r\n IF (TRIM(sChar) @<> '' );\r\n\r\n ### Dimension Name ###\r\n\r\n # If the delimiter is more than 1 character peek ahead the same amount\r\n # Ignore the first character\r\n sDelim = sChar;\r\n nCount = LONG(sElementStartDelim) - 1;\r\n If( nCount > 0 & nChar + nCount <= nCharCount );\r\n # Add the extra characters\r\n sDelim = sDelim | SUBST( sElementMapping, nChar + 1, nCount);\r\n # Move to the end of the delimter\r\n nAddExtra = nCount;\r\n EndIf;\r\n\r\n If( sDelim @= sElementStartDelim );\r\n\r\n sChar = sDelim;\r\n\r\n If( sLastDelim @<> '' & sLastDelim @<> sDelimDim );\r\n sMessage = Expand ( 'The name of a dimension must follow a dimension delimiter %sDelimDim%' );\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n #ProcessError();\r\n EndIf;\r\n\r\n sDimension = sWord;\r\n\r\n If( DimensionExists( sDimension ) = 0 );\r\n # The dimension does not exist in the model. Cancel process\r\n sMessage = Expand( 'Dimension: %sDimension% does not exist');\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n #ProcessError();\r\n EndIf;\r\n\r\n # Check that the dimension is in the cube\r\n i = 1;\r\n iMax = 30;\r\n sDimInCube = 'No';\r\n While( i <= iMax );\r\n sDimensionOfCube = TabDim( pCube, i );\r\n If(sDimension @= sDimensionOfCube);\r\n sDimInCube = 'Yes';\r\n # record where the loop stops\r\n nIndex = i;\r\n i = 100;\r\n Else;\r\n i = i + 1;\r\n EndIf;\r\n End;\r\n\r\n If( sDimInCube @<> 'Yes' );\r\n # The dimension does not exist in the cube. Cancel process\r\n sMessage = Expand( 'Dimension %sDimension% does not exist in this cube');\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n #ProcessError();\r\n EndIf;\r\n\r\n ### Dimension exists so add it to the filters\r\n IF(LONG(sFilter) > 0 & sLastDelim @= '');\r\n sTargetFilter = sFilter | sDelimDim | sDimension | sElementStartDelim;\r\n sFilter = sFilter | sDelimDim | sDimension | sElementStartDelim;\r\n ElseiF(LONG(sFilter) > 0 & sLastDelim@<>'');\r\n sFilter = sFilter | sDelimDim | sDimension | sElementStartDelim;\r\n sTargetFilter = sTargetFilter | sDelimDim | sDimension | sElementStartDelim;\r\n Else;\r\n sFilter = sDimension | sElementStartDelim;\r\n sTargetFilter = sDimension | sElementStartDelim;\r\n EndIf;\r\n\r\n #Reset the source and target elements\r\n sSource = '';\r\n sTarget = '';\r\n\r\n # The variable nElementCount is used to keep track of how many elements there are per dimension\r\n # the first element is the source\r\n # the second element is the target\r\n # There shouldn't be any more than 2 elements per dimension\r\n\r\n # A new dimension has been found so reset the element count so\r\n # the code can tell how many elements have been specified for each dimension\r\n # There should just be 2\r\n\r\n nElementCount = 1;\r\n sLastDelim = sChar;\r\n\r\n # Clear the word\r\n sWord = '';\r\n\r\n Else;\r\n\r\n # Reset extra chars\r\n nAddExtra = 0;\r\n\r\n ### Check both dim delimiter and element delimiter ###\r\n nIsDelimiter = 0;\r\n\r\n # Check dim delim\r\n # If the delimiter is more than 1 character peek ahead the same amount\r\n # Ignore the first character\r\n sDelim = sChar;\r\n nCount = LONG(sDelimDim) - 1;\r\n If( nCount > 0 & nChar + nCount <= nCharCount );\r\n # Add the extra characters\r\n sDelim = sDelim | SUBST( sElementMapping, nChar + 1, nCount);\r\n # Move to the end of the delimter\r\n nAddExtra = nCount;\r\n EndIf;\r\n\r\n If( sDelim @= sDelimDim );\r\n nIsDelimiter = 1;\r\n sChar = sDelim;\r\n Else;\r\n # Reset extra chars\r\n nAddExtra = 0;\r\n\r\n ## Check element delimiter\r\n\r\n # If the delimiter is more than 1 character peek ahead the same amount\r\n # Ignore the first character\r\n sDelim = sChar;\r\n nCount = LONG(sMappingDelimiter) - 1;\r\n If( nCount > 0 & nChar + nCount <= nCharCount );\r\n # Add the extra characters\r\n sDelim = sDelim | SUBST( sElementMapping, nChar + 1, nCount);\r\n # Move to the end of the delimter\r\n nAddExtra = nCount;\r\n EndIf;\r\n\r\n If( sDelim @= sMappingDelimiter );\r\n nIsDelimiter = 1;\r\n sChar = sDelim;\r\n Else;\r\n # Reset extra chars\r\n nAddExtra = 0;\r\n EndIf;\r\n\r\n EndIf;\r\n\r\n If ( nIsDelimiter = 1 );\r\n\r\n If( sLastDelim @= '' % sLastDelim @= sDelimDim );\r\n sMessage = 'An element start delimiter must follow a dimension name: ' | sChar | ' (' | NumberToString(nChar) | ')';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n #ProcessError();\r\n EndIf;\r\n\r\n # an element has been found!\r\n sElement = sWord;\r\n\r\n If( DIMIX( sDimension, sElement ) = 0 );\r\n # The element does not exist in the dimension. Cancel process\r\n sMessage = Expand( 'Element: %sElement% does not exist in dimension %sDimension%' );\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n EndIf;\r\n\r\n # Allow consolidations only if pSuppressConsol is not set to 1\r\n # Consolidations may be made allowable\r\n # so that you can copy strings between c levels\r\n # or copy from a consolidated source element to an n level target element\r\n\r\n ### Check for errors before continuing\r\n If( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 );\r\n ProcessQuit;\r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n EndIf;\r\n\r\n If ( DTYPE( sDimension, sElement) @= 'C' );\r\n IF( nElementCount = 1 );\r\n If( pSuppressConsol <> 1 );\r\n nSuppressConsol = 0;\r\n EndIf;\r\n pSubN = 1;\r\n Else;\r\n sMessage = Expand( 'Target element: %sElement% for dimension %sDimension% is consolidated' );\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n #ProcessBreak;\r\n Endif;\r\n Endif;\r\n\r\n # Add the element to the source or target depending on whether it's the first or the second element\r\n # Get principal name\r\n # in case source element and this element are using different aliases\r\n\r\n sElement = DimensionElementPrincipalName(sDimension,sElement);\r\n\r\n # first element\r\n IF(nElementCount = 1);\r\n\r\n sSource = sElement;\r\n sFilter = sFilter | sElement;\r\n\r\n # second element\r\n ElseIf(nElementCount = 2);\r\n\r\n sTarget = sElement;\r\n sTargetFilter = sTargetFilter | sElement;\r\n\r\n Else;\r\n\r\n sMessage = Expand( 'There should only be 2 elements per dimension: %sDimension% , a source and a target');\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n #ProcessError();\r\n\r\n EndIf;\r\n\r\n If(nIndex = 1);\r\n nMappedDim1 = 1;\r\n sSourceDim1 = sSource;\r\n sTargetDim1 = sTarget;\r\n ElseIf(nIndex = 2);\r\n nMappedDim2 = 1;\r\n sSourceDim2 = sSource;\r\n sTargetDim2 = sTarget;\r\n ElseIf(nIndex = 3);\r\n nMappedDim3 = 1;\r\n sSourceDim3 = sSource;\r\n sTargetDim3 = sTarget;\r\n ElseIf(nIndex = 4);\r\n nMappedDim4 = 1;\r\n sSourceDim4 = sSource;\r\n sTargetDim4 = sTarget;\r\n ElseIf(nIndex = 5);\r\n nMappedDim5 = 1;\r\n sSourceDim5 = sSource;\r\n sTargetDim5 = sTarget;\r\n ElseIf(nIndex = 6);\r\n nMappedDim6 = 1;\r\n sSourceDim6 = sSource;\r\n sTargetDim6 = sTarget;\r\n ElseIf(nIndex = 7);\r\n nMappedDim7 = 1;\r\n sSourceDim7 = sSource;\r\n sTargetDim7 = sTarget;\r\n ElseIf(nIndex = 8);\r\n nMappedDim8 = 1;\r\n sSourceDim8 = sSource;\r\n sTargetDim8 = sTarget;\r\n ElseIf(nIndex = 9);\r\n nMappedDim9 = 1;\r\n sSourceDim9 = sSource;\r\n sTargetDim9 = sTarget;\r\n ElseIf(nIndex = 10);\r\n nMappedDim10 = 1;\r\n sSourceDim10 = sSource;\r\n sTargetDim10 = sTarget;\r\n ElseIf(nIndex = 11);\r\n nMappedDim11 = 1;\r\n sSourceDim11 = sSource;\r\n sTargetDim11 = sTarget;\r\n ElseIf(nIndex = 12);\r\n nMappedDim12 = 1;\r\n sSourceDim12 = sSource;\r\n sTargetDim12 = sTarget;\r\n ElseIf(nIndex = 13);\r\n nMappedDim13 = 1;\r\n sSourceDim13 = sSource;\r\n sTargetDim13 = sTarget;\r\n ElseIf(nIndex = 14);\r\n nMappedDim14 = 1;\r\n sSourceDim14 = sSource;\r\n sTargetDim14 = sTarget;\r\n ElseIf(nIndex = 15);\r\n nMappedDim15 = 1;\r\n sSourceDim15 = sSource;\r\n sTargetDim15 = sTarget;\r\n ElseIf(nIndex = 16);\r\n nMappedDim16 = 1;\r\n sSourceDim16 = sSource;\r\n sTargetDim16 = sTarget;\r\n ElseIf(nIndex = 17);\r\n nMappedDim17 = 1;\r\n sSourceDim17 = sSource;\r\n sTargetDim17 = sTarget;\r\n ElseIf(nIndex = 18);\r\n nMappedDim18 = 1;\r\n sSourceDim18 = sSource;\r\n sTargetDim18 = sTarget;\r\n ElseIf(nIndex = 19);\r\n nMappedDim19 = 1;\r\n sSourceDim19 = sSource;\r\n sTargetDim19 = sTarget;\r\n ElseIf(nIndex = 20);\r\n nMappedDim20 = 1;\r\n sSourceDim20 = sSource;\r\n sTargetDim20 = sTarget;\r\n ElseIf(nIndex = 21);\r\n nMappedDim21 = 1;\r\n sSourceDim21 = sSource;\r\n sTargetDim21 = sTarget;\r\n ElseIf(nIndex = 22);\r\n nMappedDim22 = 1;\r\n sSourceDim22 = sSource;\r\n sTargetDim22 = sTarget;\r\n ElseIf(nIndex = 23);\r\n nMappedDim23 = 1;\r\n sSourceDim23 = sSource;\r\n sTargetDim23 = sTarget;\r\n ElseIf(nIndex = 24);\r\n nMappedDim24 = 1;\r\n sSourceDim24 = sSource;\r\n sTargetDim24 = sTarget;\r\n ElseIf(nIndex = 25);\r\n nMappedDim25 = 1;\r\n sSourceDim25 = sSource;\r\n sTargetDim25 = sTarget;\r\n ElseIf(nIndex = 26);\r\n nMappedDim26 = 1;\r\n sSourceDim26 = sSource;\r\n sTargetDim26 = sTarget;\r\n ElseIf(nIndex = 27);\r\n nMappedDim27 = 1;\r\n sSourceDim27 = sSource;\r\n sTargetDim27 = sTarget;\r\n EndIf;\r\n\r\n sLastDelim = sChar;\r\n\r\n # Clear the word\r\n sWord = '';\r\n\r\n nElementCount = nElementCount + 1;\r\n\r\n Else;\r\n sWord = sWord | sChar;\r\n EndIf;\r\n\r\n EndIf;\r\n\r\n EndIf;\r\n\r\n nChar = nChar + nAddExtra + 1;\r\n\r\n END;\r\nENDIF;\r\n\r\n\r\n### Check that there if a dimension is used, there is a source element and a target element\r\ncSourceVariableStem = 'sSourceDim';\r\ncTargetVariableStem = 'sTargetDim';\r\ncMappedDimVariableStem = 'nMappedDim';\r\n\r\nnCounter = 1;\r\nWHILE(nCounter <= nDimensionCount);\r\n\r\n sMappedDimVariable = 'nMappedDim ' | NumberToString(nCounter);\r\n sDimensionUsedPadded = Expand('%' | sMappedDimVariable | '%');\r\n\r\n nMappedDim = StringToNumber(Trim(sDimensionUsedPadded));\r\n If(nMappedDim = 1);\r\n sDim = TabDim( pCube, nCounter );\r\n sSourceVariable = cSourceVariableStem | NumberToString(nCounter);\r\n sSourcePadded = Expand('%' | sSourceVariable | '%');\r\n sSource = Trim(sSourcePadded);\r\n\r\n sTargetVariable = cTargetVariableStem | NumberToString(nCounter);\r\n sTargetPadded = Expand('%' | sTargetVariable | '%');\r\n sTarget = Trim(sTargetPadded);\r\n\r\n If(sSource @='' % sTarget @='');\r\n sMessage = 'Source and/or target element is blank for dimension ' | sDim;\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n #ProcessError();\r\n EndIf;\r\n\r\n EndIf;\r\n\r\nnCounter = nCounter + 1;\r\n\r\nEND;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n DataSourceType = 'NULL';\r\n If( pStrictErrorHandling = 1 );\r\n ProcessQuit;\r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n# Branch depending on whether to do recursive calls to self on independent threads or run all in this thread\r\nIf( Scan( pEleStartDelim, pFilterParallel ) > 0 );\r\n sDimParallel = SubSt( pFilterParallel, 1, Scan( pEleStartDelim, pFilterParallel ) - 1 );\r\n sElementList = SubSt( pFilterParallel, Scan( pEleStartDelim, pFilterParallel ) + Long( pEleStartDelim ), Long( pFilterParallel ) );\r\n If( SubSt( sElementList, Long( sElementList ), 1 ) @<> pEleDelim );\r\n sElementList = sElementList | pEleDelim;\r\n EndIf;\r\n ## Counting elements in element list\r\n sElementListCount = sElementList;\r\n nElements = 0;\r\n While( Scan( pEleDelim, sElementListCount ) > 0 );\r\n nElements = nElements + 1;\r\n sElementListCount = SubSt( sElementListCount, Scan( pEleDelim, sElementListCount ) + Long( pEleDelim ), Long( sElementListCount ) );\r\n End;\r\n IF( Mod( nElements, nMaxThreads ) = 0 );\r\n nElemsPerThread = INT( nElements / nMaxThreads );\r\n ELSE;\r\n nElemsPerThread = INT( nElements / nMaxThreads ) + 1;\r\n ENDIF;\r\n nThreadElCounter = 0;\r\n nThreads = 0;\r\n While( Scan( pEleDelim, sElementList ) > 0 );\r\n sSlicerEle = SubSt( sElementList, 1, Scan( pEleDelim, sElementList ) - 1 );\r\n sElementList = SubSt( sElementList, Scan( pEleDelim, sElementList ) + Long( pEleDelim ), Long( sElementList ) );\r\n # Do recursive process call with new RunProcess function\r\n nThreadElCounter = nThreadElCounter + 1;\r\n sDimDelim = If(pFilter @= '', '', pDimDelim );\r\n IF( nThreadElCounter = 1 );\r\n sFilter = Expand('%pFilter%%sDimDelim%%sDimParallel%%pEleStartDelim%%sSlicerEle%');\r\n ELSE;\r\n sFilter = Expand('%sFilter%%pEleDelim%%sSlicerEle%');\r\n ENDIF;\r\n IF( nThreadElCounter >= nElemsPerThread );\r\n nThreadID = INT( RAND( ) * 10000 + 1) + Numbr(cTimeStamp);\r\n sThreadControlFile = LOWER( GetProcessName() | '_ThreadControlFile_' | cRandomInt | '_' | NumberToString(nThreadID) | '_' | cTimeStamp );\r\n AsciiOutput( cDir | sThreadControlFile | '.txt', '' );\r\n LogOutput( 'INFO', 'Executing subTI with Thread ID: ' | NumberToString(nThreadID) );\r\n RunProcess( cThisProcName, 'pLogoutput', pLogoutput,\r\n \t'pCube', pCube, 'pSrcView', pSrcView, 'pTgtView', pTgtView,\r\n \t'pFilter', sFilter, 'pFilterParallel', '', 'pEleMapping', pEleMapping, 'pMappingDelim', pMappingDelim,\r\n \t'pDimDelim', pDimDelim, 'pEleStartDelim', pEleStartDelim, 'pEleDelim', pEleDelim,\r\n \t'pFactor', pFactor, 'pSuppressConsol', pSuppressConsol, 'pSuppressConsolStrings', pSuppressConsolStrings, 'pSuppressRules', pSuppressRules, 'pSuppressZero', pSuppressZero, 'pCumulate', pCumulate,\r\n \t'pZeroTarget', pZeroTarget, 'pZeroSource', pZeroSource, 'pTemp', pTemp, 'pCubeLogging', pCubeLogging, 'pSandbox', pSandbox, 'pFile', pFile, 'pDecimalSeparator', pDecimalSeparator, 'pThousandSeparator', pThousandSeparator,\r\n 'pThreadMode', 1, 'pThreadControlFile', sThreadControlFile\r\n );\r\n \t nThreadElCounter = 0;\r\n \t sFilter = '';\r\n \t nThreads = nThreads + 1;\r\n \tENDIF;\r\n End;\r\n ## Process last elements - only when filter is not empty (there are still elements)\r\n IF( sFilter @<> '' );\r\n RunProcess( cThisProcName, 'pLogoutput', pLogoutput,\r\n \t'pCube', pCube, 'pSrcView', pSrcView, 'pTgtView', pTgtView,\r\n \t'pFilter', sFilter, 'pFilterParallel', '', 'pEleMapping', pEleMapping, 'pMappingDelim', pMappingDelim,\r\n \t'pDimDelim', pDimDelim, 'pEleStartDelim', pEleStartDelim, 'pEleDelim', pEleDelim,\r\n \t'pFactor', pFactor, 'pSuppressConsol', pSuppressConsol, 'pSuppressConsolStrings', pSuppressConsolStrings, 'pSuppressRules', pSuppressRules, 'pSuppressZero', pSuppressZero, 'pCumulate', pCumulate,\r\n \t'pZeroTarget', pZeroTarget, 'pZeroSource', pZeroSource, 'pTemp', pTemp, 'pCubeLogging', pCubeLogging, 'pSandbox', pSandbox, 'pFile', pFile, 'pDecimalSeparator', pDecimalSeparator, 'pThousandSeparator', pThousandSeparator,\r\n 'pThreadMode', 1, 'pThreadControlFile', sThreadControlFile\r\n );\r\n ENDIF;\r\n DataSourceType = 'NULL';\r\n Sleep( 1000 );\r\nElse;\r\n ### Create View of target to zero out\r\n ### Check that there's something in sTargetFilter so the cube doesn't accidentally get wiped out\r\n IF( pThreadControlFile @<> '' );\r\n LogOutput( 'info', 'creating thread file ' | cDir | pThreadControlFile | '.txt' );\r\n AsciiOutput( cDir | pThreadControlFile | '.txt', '' );\r\n ENDIF;\r\n If(pZeroTarget = 1 & LONG(sTargetFilter)> 0);\r\n\r\n sProc = '}bedrock.cube.data.clear';\r\n nRet = ExecuteProcess( sProc,\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pCube', pCube,\r\n 'pView', cViewTarget,\r\n 'pFilter', sTargetFilter,\r\n 'pDimDelim', pDimDelim,\r\n 'pEleStartDelim', pEleStartDelim,\r\n 'pEleDelim', pEleDelim,\r\n 'pCubeLogging', pCubeLogging,\r\n 'pTemp', pTemp,\r\n 'pSandbox', pSandbox\r\n );\r\n\r\n IF(nRet <> 0);\r\n sMessage = 'Error clearing the target view.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 );\r\n ProcessQuit;\r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n ENDIF;\r\n\r\n Endif;\r\n\r\n If( pFile = 0 );\r\n\r\n ### Create View of Source ###\r\n\r\n nRet = ExecuteProcess('}bedrock.cube.view.create',\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pCube', pCube,\r\n 'pView', cViewSource,\r\n 'pFilter', sFilter,\r\n 'pSuppressZero', pSuppressZero,\r\n 'pSuppressConsol', nSuppressConsol,\r\n 'pSuppressRules', pSuppressRules,\r\n 'pSuppressConsolStrings', pSuppressConsolStrings,\r\n 'pIncludeDescendants',pIncludeDescendants,\r\n 'pDimDelim', pDimDelim,\r\n 'pEleStartDelim', pEleStartDelim,\r\n 'pEleDelim', pEleDelim ,\r\n 'pTemp', pTemp,\r\n 'pSubN', pSubN\r\n );\r\n\r\n IF(nRet <> 0);\r\n sMessage = 'Error creating the view from the filter.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 );\r\n ProcessQuit;\r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n ENDIF;\r\n\r\n\r\n ### Assign Datasource ###\r\n DataSourceType = 'VIEW';\r\n DatasourceNameForServer = pCube;\r\n DatasourceNameForClient = pCube;\r\n DatasourceCubeView = cViewSource;\r\n nThreadMode = 1;\r\n Else;\r\n ### Export Data to file ###\r\n\r\n nRet = ExecuteProcess('}bedrock.cube.data.export',\r\n 'pLogoutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pCube', pCube,\r\n 'pView', cViewSource,\r\n 'pFilter', sFilter,\r\n 'pFilterParallel', '',\r\n 'pParallelThreads', 0,\r\n 'pDimDelim', pDimDelim,\r\n 'pEleStartDelim', pEleStartDelim,\r\n 'pEleDelim', pEleDelim,\r\n 'pSuppressZero', pSuppressZero,\r\n 'pSuppressConsol', nSuppressConsol,\r\n 'pSuppressRules', pSuppressRules,\r\n 'pSuppressConsolStrings', pSuppressConsolStrings,\r\n 'pIncludeDescendants',pIncludeDescendants,\r\n 'pZeroSource', 0,\r\n 'pCubeLogging', pCubeLogging,\r\n 'pTemp', pTemp,\r\n 'pFilePath', cDir,\r\n 'pFileName', cFileName,\r\n 'pDelim', cDelimiter,\r\n 'pDecimalSeparator', sDecimalSeparator,\r\n 'pThousandSeparator', sThousandSeparator,\r\n 'pQuote', cQuote,\r\n 'pTitleRecord', cTitleRows,\r\n 'pSandbox', pSandbox\r\n );\r\n\r\n IF(nRet <> 0);\r\n sMessage = 'Error exporting data to file.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 );\r\n ProcessQuit;\r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n ENDIF;\r\n\r\n If(FileExists(cFile) = 0);\r\n # If the file does not exist, it means that nothing got exported, so there is nothing to import\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( 'Process:%cThisProcName% is skipping import as export file %cFile% was not found.' ) );\r\n EndIf;\r\n DataSourceType = 'NULL';\r\n Else;\r\n ### Assign Datasource ###\r\n DataSourceType = 'CHARACTERDELIMITED';\r\n DatasourceNameForServer = cFile;\r\n DatasourceNameForClient = cFile;\r\n DatasourceASCIIHeaderRecords = cTitleRows;\r\n DatasourceASCIIDelimiter = cDelimiter;\r\n DatasourceASCIIQuoteCharacter = cQuote;\r\n EndIf;\r\n\r\n nThreadMode = 1;\r\n\r\n EndIf;\r\n\r\nEndIf;\r\n\r\n### End Prolog ###\r\n", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.cube.data.copy', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pCube', '', 'pSrcView', '', 'pTgtView', '', 'pFilter', '',\r\n \t'pFilterParallel', '', 'pParallelThreads', 0,\r\n \t'pEleMapping', '', 'pMappingDelim', '->',\r\n \t'pDimDelim', '&', 'pEleStartDelim', '\u00a6', 'pEleDelim', '+',\r\n \t'pFactor', 1, 'pSuppressConsol', 1, 'pSuppressConsolStrings', 0, 'pSuppressRules', 1, 'pSuppressZero', 1, 'pIncludeDescendants',0, 'pCumulate', 0,\r\n \t'pZeroTarget', 1, 'pZeroSource', 0,\r\n \t'pTemp', 1, 'pCubeLogging', 0, 'pSandbox', '', \r\n \t'pFile', 0, 'pDelim', ',', 'pQuote', '\"', 'pDecimalSeparator', '.', 'pThousandSeparator', ',', 'pSubN', 0\r\n );\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n#################################################################################################\r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n#################################################################################################\r\n\r\n#Region @DOC\r\n# Description:\r\n# This TI is intended to copy data from one element of a dimension to another in the same cube.\r\n\r\n# Use case: Mainly used in production environments.\r\n# 1/ Typically, this would be used to archive a Budget or Forecast element of a version dimension.\r\n# 2/ Could also be used to prepopulate a version from a prior year.\r\n\r\n# Note:\r\n# Naturally, a valid cube name (pCube) is required. otherwise the process will abort.\r\n# Element mapping (pEleMapping) is also required, otherwise the process will abort.\r\n# A filter parameter (pFilter) can also be used to filter dimensions that have not been mapped.\r\n# Source (pSrcView) & target (pTgtView) views will be assigned temporary names if left blank.\r\n# All other parameters may be left as is but be sure to use them appropriately when specifying pEleMapping & pFilter parameters.\r\n# - Since this TI has a view as a data source, it requires the implicit variables NValue, SValue and Value_is_String.\r\n# - To edit this TI in Architect a tmp cube with minimum 24 dims is needed as the preview data source or set the data\r\n# source to ASCII and manually edit the TI in notepad after saving to add back the required implicit view variables.\r\n# - If using the pFilterParallel parameter the **single dimension** used as the \"parallelization slicer\" cannot appear in\r\n# the pFilter and pEleMapping parameters.\r\n# - When using parallelization via the *RunProcess* function the elements listed in pFilterParallel will be split one_at_a_time\r\n# and passed to a recursive call of the process being added to pFilter.\r\n#EndRegion @DOC\r\n\r\nIf( pThreadControlFile @<> '' );\r\n LogOutput( 'INFO', 'Executed as subTI with Thread Control File: ' | pThreadControlFile );\r\nEndIf;\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode = 0;\r\n# Target Filter Variable for shell processes\r\nStringGlobalVariable('sTargetFilter');\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent= 'Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pCube:%pCube%, pSrcView:%pSrcView%, pTgtView:%pTgtView%, pFilter:%pFilter%, pFilterParallel:%pFilterParallel%, pParallelThreads:%pParallelThreads%, pEleMapping:%pEleMapping%, pMappingDelim:%pMappingDelim%, pDimDelim:%pDimDelim%, pEleStartDelim:%pEleStartDelim%, pEleDelim:%pEleDelim%, pFactor:%pFactor%, pSuppressConsol:%pSuppressConsol%, pSuppressConsolStrings:%pSuppressConsolStrings%, pSuppressRules:%pSuppressRules%, pSuppressZero:%pSuppressZero% pIncludeDescendants %pIncludeDescendants% pCumulate:%pCumulate% pZeroTarget:%pZeroTarget%, pZeroSource:%pZeroSource%, pTemp:%pTemp%, pCubeLogging:%pCubeLogging%, pSandbox:%pSandbox%, pFile:%pFile%.';\r\ncDefaultView = Expand( '%cThisProcName%_%cTimeStamp%_%cRandomInt%' );\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pCube\": null,\r\n \"pDecimalSeparator\": \".\",\r\n \"pDelim\": \"&\",\r\n \"pDimDelim\": \"&\",\r\n \"pEleDelim\": \"+\",\r\n \"pEleMapping\": null,\r\n \"pEleStartDelim\": \"\u00a6\",\r\n \"pFilter\": \"\",\r\n \"pFilterParallel\": \"\",\r\n \"pMappingDelim\": \"->\",\r\n \"pQuote\": \"\"\",\r\n \"pSandbox\": \"\",\r\n \"pSrcView\": \"\",\r\n \"pTgtView\": \"\",\r\n \"pThousandSeparator\": \",\",\r\n \"pThreadControlFile\": \"\",\r\n \"pCumulate\": 0,\r\n \"pFactor\": 1,\r\n \"pFile\": 0,\r\n \"pIncludeDescendants\": 0,\r\n \"pLogOutput\": 0,\r\n \"pMaxWaitSeconds\": 1800,\r\n \"pParallelThreads\": 0,\r\n \"pStrictErrorHandling\": 0,\r\n \"pSubN\": 0,\r\n \"pSuppressConsol\": 1,\r\n \"pSuppressConsolStrings\": 1,\r\n \"pSuppressRules\": 1,\r\n \"pSuppressZero\": 1,\r\n \"pTemp\": 1,\r\n \"pThreadMode\": 0,\r\n \"pZeroSource\": 0,\r\n \"pZeroTarget\": 1\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pCube\": '|StringToJson ( pCube )|',\r\n \"pDecimalSeparator\": '|StringToJson ( pDecimalSeparator )|',\r\n \"pDelim\": '|StringToJson ( pDelim )|',\r\n \"pDimDelim\": '|StringToJson ( pDimDelim )|',\r\n \"pEleDelim\": '|StringToJson ( pEleDelim )|',\r\n \"pEleMapping\": '|StringToJson ( pEleMapping )|',\r\n \"pEleStartDelim\": '|StringToJson ( pEleStartDelim )|',\r\n \"pFilter\": '|StringToJson ( pFilter )|',\r\n \"pFilterParallel\": '|StringToJson ( pFilterParallel )|',\r\n \"pMappingDelim\": '|StringToJson ( pMappingDelim )|',\r\n \"pQuote\": '|StringToJson ( pQuote )|',\r\n \"pSandbox\": '|StringToJson ( pSandbox )|',\r\n \"pSrcView\": '|StringToJson ( pSrcView )|',\r\n \"pTgtView\": '|StringToJson ( pTgtView )|',\r\n \"pThousandSeparator\": '|StringToJson ( pThousandSeparator )|',\r\n \"pThreadControlFile\": '|StringToJson ( pThreadControlFile )|',\r\n \"pCumulate\": '|NumberToString( pCumulate )|',\r\n \"pFactor\": '|NumberToString( pFactor )|',\r\n \"pFile\": '|NumberToString( pFile )|',\r\n \"pIncludeDescendants\": '|NumberToString( pIncludeDescendants )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pMaxWaitSeconds\": '|NumberToString( pMaxWaitSeconds )|',\r\n \"pParallelThreads\": '|NumberToString( pParallelThreads )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|',\r\n \"pSubN\": '|NumberToString( pSubN )|',\r\n \"pSuppressConsol\": '|NumberToString( pSuppressConsol )|',\r\n \"pSuppressConsolStrings\": '|NumberToString( pSuppressConsolStrings )|',\r\n \"pSuppressRules\": '|NumberToString( pSuppressRules )|',\r\n \"pSuppressZero\": '|NumberToString( pSuppressZero )|',\r\n \"pTemp\": '|NumberToString( pTemp )|',\r\n \"pThreadMode\": '|NumberToString( pThreadMode )|',\r\n \"pZeroSource\": '|NumberToString( pZeroSource )|',\r\n \"pZeroTarget\": '|NumberToString( pZeroTarget )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npCube = JsonToString( JsonGet( pJson, 'pCube' ) );\r\npDecimalSeparator = JsonToString( JsonGet( pJson, 'pDecimalSeparator' ) );\r\npDelim = JsonToString( JsonGet( pJson, 'pDelim' ) );\r\npDimDelim = JsonToString( JsonGet( pJson, 'pDimDelim' ) );\r\npEleDelim = JsonToString( JsonGet( pJson, 'pEleDelim' ) );\r\npEleMapping = JsonToString( JsonGet( pJson, 'pEleMapping' ) );\r\npEleStartDelim = JsonToString( JsonGet( pJson, 'pEleStartDelim' ) );\r\npFilter = JsonToString( JsonGet( pJson, 'pFilter' ) );\r\npFilterParallel = JsonToString( JsonGet( pJson, 'pFilterParallel' ) );\r\npMappingDelim = JsonToString( JsonGet( pJson, 'pMappingDelim' ) );\r\npQuote = JsonToString( JsonGet( pJson, 'pQuote' ) );\r\npSandbox = JsonToString( JsonGet( pJson, 'pSandbox' ) );\r\npSrcView = JsonToString( JsonGet( pJson, 'pSrcView' ) );\r\npTgtView = JsonToString( JsonGet( pJson, 'pTgtView' ) );\r\npThousandSeparator = JsonToString( JsonGet( pJson, 'pThousandSeparator' ) );\r\npThreadControlFile = JsonToString( JsonGet( pJson, 'pThreadControlFile' ) );\r\n# Numeric Parameters\r\npCumulate = StringToNumber( JsonToString( JsonGet( pJson, 'pCumulate' ) ) );\r\npFactor = StringToNumber( JsonToString( JsonGet( pJson, 'pFactor' ) ) );\r\npFile = StringToNumber( JsonToString( JsonGet( pJson, 'pFile' ) ) );\r\npIncludeDescendants = StringToNumber( JsonToString( JsonGet( pJson, 'pIncludeDescendants' ) ) );\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npMaxWaitSeconds = StringToNumber( JsonToString( JsonGet( pJson, 'pMaxWaitSeconds' ) ) );\r\npParallelThreads = StringToNumber( JsonToString( JsonGet( pJson, 'pParallelThreads' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\npSubN = StringToNumber( JsonToString( JsonGet( pJson, 'pSubN' ) ) );\r\npSuppressConsol = StringToNumber( JsonToString( JsonGet( pJson, 'pSuppressConsol' ) ) );\r\npSuppressConsolStrings = StringToNumber( JsonToString( JsonGet( pJson, 'pSuppressConsolStrings' ) ) );\r\npSuppressRules = StringToNumber( JsonToString( JsonGet( pJson, 'pSuppressRules' ) ) );\r\npSuppressZero = StringToNumber( JsonToString( JsonGet( pJson, 'pSuppressZero' ) ) );\r\npTemp = StringToNumber( JsonToString( JsonGet( pJson, 'pTemp' ) ) );\r\npThreadMode = StringToNumber( JsonToString( JsonGet( pJson, 'pThreadMode' ) ) );\r\npZeroSource = StringToNumber( JsonToString( JsonGet( pJson, 'pZeroSource' ) ) );\r\npZeroTarget = StringToNumber( JsonToString( JsonGet( pJson, 'pZeroTarget' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) );\r\nENDIF;\r\n\r\n# Variables\r\nnDataCount = 0;\r\nnExistingSourceFlag = 0;\r\nnAttrCubeFlag = 0;\r\ncSuffixSource = 'S';\r\ncSuffixTarget = 'T';\r\ncPrefixElementAttributes = '}ElementAttributes_';\r\ncDimCountMax = 27;\r\nsDimCountMax = NumberToString( cDimCountMax );\r\nnFactor = If( pFactor = 0, 1, pFactor );\r\ncLenASCIICode = 3;\r\n\r\n## check operating system\r\nIf( SubSt( GetProcessErrorFileDirectory, 2, 1 ) @= ':' );\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nElseIf( Scan( '/', GetProcessErrorFileDirectory ) > 0 );\r\n sOS = 'Linux';\r\n sOSDelim = '/';\r\nElse;\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nEndIf;\r\n\r\n# Validate file delimiter & quote character\r\nIf( pDelim @= '' );\r\n pDelim = ',';\r\nElse;\r\n # If length of pDelim is exactly 3 chars and each of them is decimal digit, then the pDelim is entered as ASCII code\r\n nValid = 0;\r\n If ( LONG(pDelim) = cLenASCIICode );\r\n nChar = 1;\r\n While ( nChar <= cLenASCIICode );\r\n If( CODE( pDelim, nChar ) >= CODE( '0', 1 ) & CODE( pDelim, nChar ) <= CODE( '9', 1 ) );\r\n nValid = 1;\r\n Else;\r\n nValid = 0;\r\n Break;\r\n EndIf;\r\n nChar = nChar + 1;\r\n End;\r\n EndIf;\r\n If ( nValid<>0 );\r\n pDelim=CHAR(StringToNumber( pDelim ));\r\n Else;\r\n pDelim = SubSt( Trim( pDelim ), 1, 1 );\r\n EndIf;\r\nEndIf;\r\n\r\nIf( pQuote @= '' );\r\n ## Use no quote character\r\nElse;\r\n # If length of pQuote is exactly 3 chars and each of them is decimal digit, then the pQuote is entered as ASCII code\r\n nValid = 0;\r\n If ( LONG(pQuote) = cLenASCIICode );\r\n nChar = 1;\r\n While ( nChar <= cLenASCIICode );\r\n If( CODE( pQuote, nChar ) >= CODE( '0', 1 ) & CODE( pQuote, nChar ) <= CODE( '9', 1 ) );\r\n nValid = 1;\r\n Else;\r\n nValid = 0;\r\n Break;\r\n EndIf;\r\n nChar = nChar + 1;\r\n End;\r\n EndIf;\r\n If ( nValid<>0 );\r\n pQuote=CHAR(StringToNumber( pQuote ));\r\n Else;\r\n pQuote = SubSt( Trim( pQuote ), 1, 1 );\r\n EndIf;\r\nEndIf;\r\n\r\n## File location for indirect data copy\r\ncDir = GetProcessErrorFileDirectory;\r\ncFileName = LOWER(pCube) | cTimeStamp | cRandomInt | '.csv';\r\ncFile = cDir | cFileName;\r\ncTitleRows = 1;\r\ncDelimiter = pDelim;\r\ncQuote = pQuote;\r\n\r\n# nMappedDimX is a binary switch used to keep track of which dimensions have been mapped from the source to the target\r\nnMappedDim1 = 0;\r\nnMappedDim2 = 0;\r\nnMappedDim3 = 0;\r\nnMappedDim4 = 0;\r\nnMappedDim5 = 0;\r\nnMappedDim6 = 0;\r\nnMappedDim7 = 0;\r\nnMappedDim8 = 0;\r\nnMappedDim9 = 0;\r\nnMappedDim10 = 0;\r\nnMappedDim11 = 0;\r\nnMappedDim12 = 0;\r\nnMappedDim13 = 0;\r\nnMappedDim14 = 0;\r\nnMappedDim15 = 0;\r\nnMappedDim16 = 0;\r\nnMappedDim17 = 0;\r\nnMappedDim18 = 0;\r\nnMappedDim19 = 0;\r\nnMappedDim20 = 0;\r\nnMappedDim21 = 0;\r\nnMappedDim22 = 0;\r\nnMappedDim23 = 0;\r\nnMappedDim24 = 0;\r\nnMappedDim25 = 0;\r\nnMappedDim26 = 0;\r\nnMappedDim27 = 0;\r\n\r\n### Determine dimensions in target cube - we need to know this to test the cell type before loading ###\r\nsDim1 = TabDim( pCube, 1 );\r\nsDim2 = TabDim( pCube, 2 );\r\nsDim3 = TabDim( pCube, 3 );\r\nsDim4 = TabDim( pCube, 4 );\r\nsDim5 = TabDim( pCube, 5 );\r\nsDim6 = TabDim( pCube, 6 );\r\nsDim7 = TabDim( pCube, 7 );\r\nsDim8 = TabDim( pCube, 8 );\r\nsDim9 = TabDim( pCube, 9 );\r\nsDim10 = TabDim( pCube, 10 );\r\nsDim11 = TabDim( pCube, 11 );\r\nsDim12 = TabDim( pCube, 12 );\r\nsDim13 = TabDim( pCube, 13 );\r\nsDim14 = TabDim( pCube, 14 );\r\nsDim15 = TabDim( pCube, 15 );\r\nsDim16 = TabDim( pCube, 16 );\r\nsDim17 = TabDim( pCube, 17 );\r\nsDim18 = TabDim( pCube, 18 );\r\nsDim19 = TabDim( pCube, 19 );\r\nsDim20 = TabDim( pCube, 20 );\r\nsDim21 = TabDim( pCube, 21 );\r\nsDim22 = TabDim( pCube, 22 );\r\nsDim23 = TabDim( pCube, 23 );\r\nsDim24 = TabDim( pCube, 24 );\r\nsDim25 = TabDim( pCube, 25 );\r\nsDim26 = TabDim( pCube, 26 );\r\nsDim27 = TabDim( pCube, 27 );\r\n\r\n###########################\r\n### Validate Parameters ###\r\n###########################\r\nnErrors = 0;\r\n\r\n## Default filter delimiters\r\nIf( pDimDelim @= '' );\r\n pDimDelim = '&';\r\nEndIf;\r\n\r\nIf( pEleStartDelim@= '' );\r\n pEleStartDelim= '\u00a6';\r\nEndIf;\r\n\r\nIf( pEleDelim @= '' );\r\n pEleDelim = '+';\r\nEndIf;\r\n\r\nIf( pMappingDelim @= '' );\r\n pMappingDelim = '->';\r\nEndIf;\r\n\r\nIf( pDecimalSeparator @= '' );\r\n \tpDecimalSeparator = '.';\r\nEndIf;\r\nIf ( LONG(pDecimalSeparator) = cLenASCIICode );\r\n nValid = 0;\r\n nChar = 1;\r\n While ( nChar <= cLenASCIICode );\r\n If( CODE( pDecimalSeparator, nChar ) >= CODE( '0', 1 ) & CODE( pDecimalSeparator, nChar ) <= CODE( '9', 1 ) );\r\n nValid = 1;\r\n Else;\r\n nValid = 0;\r\n Break;\r\n EndIf;\r\n nChar = nChar + 1;\r\n End;\r\n If ( nValid<>0 );\r\n pDecimalSeparator = CHAR(StringToNumber( pDecimalSeparator ));\r\n Else;\r\n pDecimalSeparator = SubSt( Trim( pDecimalSeparator ), 1, 1 );\r\n EndIf;\r\nEndIf;\r\nsDecimalSeparator = pDecimalSeparator;\r\n\r\nIf( pThousandSeparator @= '' );\r\n \tpThousandSeparator = ',';\r\nEndIf;\r\nIf ( LONG(pThousandSeparator) = cLenASCIICode );\r\n nValid = 0;\r\n nChar = 1;\r\n While ( nChar <= cLenASCIICode );\r\n If( CODE( pThousandSeparator, nChar ) >= CODE( '0', 1 ) & CODE( pThousandSeparator, nChar ) <= CODE( '9', 1 ) );\r\n nValid = 1;\r\n Else;\r\n nValid = 0;\r\n Break;\r\n EndIf;\r\n nChar = nChar + 1;\r\n End;\r\n If ( nValid<>0 );\r\n pThousandSeparator = CHAR(StringToNumber( pThousandSeparator ));\r\n Else;\r\n pThousandSeparator = SubSt( Trim( pThousandSeparator ), 1, 1 );\r\n EndIf;\r\nEndIf;\r\nsThousandSeparator = pThousandSeparator;\r\n\r\n# Validate cube\r\nIf( Trim( pCube ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No cube specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( CubeExists( pCube ) = 0 );\r\n nErrors = nErrors + 1;\r\n sMessage = Expand( 'Invalid source cube specified: %pCube%.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### Determine number of dims in target cube ###\r\nnCount = 1;\r\nWhile( TabDim( pCube, nCount ) @<> '' );\r\n sDimension = TabDim( pCube, nCount );\r\n nCount = nCount + 1;\r\nEnd;\r\nnDimensionCount = nCount - 1;\r\n\r\n## If dimension count exceeds the current maximum then terminate process\r\nIf( nDimensionCount > cDimCountMax );\r\n nErrors = nErrors + 1;\r\n sMessage = 'Cube has too many dimensions: %pCube%. Max %sDimCountMax% dims catered for, TI must be altered to accommodate.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n## Validate the View parameter\r\nIf( TRIM(pSrcView) @<> '' & TRIM(pSrcView) @= TRIM(pTgtView) );\r\n nErrors = nErrors + 1;\r\n sMessage = Expand( 'Source and Target Views can not be the same: %pSrcView%.' ) ;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n## Validate the View parameter\r\nIf( TRIM( pSrcView) @= '' );\r\n cViewSource = Expand( '%cDefaultView%_%cSuffixSource%' ) ;\r\nElse ;\r\n cViewSource = pSrcView ;\r\n nExistingSourceFlag = 1;\r\nEndIf;\r\n\r\n## Validate the View parameter\r\nIf( TRIM( pTgtView ) @= '' );\r\n cViewTarget = Expand( '%cDefaultView%_%cSuffixTarget%' ) ;\r\nElse ;\r\n cViewTarget = pTgtView ;\r\nEndIf;\r\n\r\n# Validate parallelization filter\r\nIf( Scan( pEleStartDelim, pFilterParallel ) > 0 );\r\n sDimParallel = SubSt( pFilterParallel, 1, Scan( pEleStartDelim, pFilterParallel ) - 1 );\r\n If( Scan( Lower(sDimParallel) | pEleStartDelim, Lower(pFilter) ) > 0 );\r\n sMessage = 'Parallelization dimension %sDimParallel% cannot exist in filter.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n EndIf;\r\n If( Scan( Lower(sDimParallel) | pEleStartDelim, Lower(pEleMapping) ) > 0 );\r\n sMessage = 'Parallelization dimension %sDimParallel% cannot exist in element mapping.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n EndIf;\r\nEndIf;\r\n\r\n# Validate Max Threads\r\nIf( pParallelThreads > 0 );\r\n nMaxThreads = pParallelThreads;\r\nElse;\r\n nMaxThreads = 1;\r\nEndIf;\r\n\r\n# Validate Mapping parameter\r\nIf( pDimDelim @= pEleStartDelim % pDimDelim @= pEleDelim % pEleStartDelim @= pEleDelim );\r\n sMessage = 'The delimiters cannot me the same.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate Mapping parameter\r\nIf( TRIM( pEleMapping ) @<> '' & TRIM( pMappingDelim) @= '');\r\n nErrors = nErrors + 1;\r\n sMessage = 'Mapping Delimiter & Element Mapping can not both be empty.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndif;\r\n\r\n# Validate Sandbox\r\nIf( TRIM( pSandbox ) @<> '' );\r\n If( ServerSandboxExists( pSandbox ) = 0 );\r\n SetUseActiveSandboxProperty( 0 );\r\n nErrors = nErrors + 1;\r\n sMessage = Expand('Sandbox %pSandbox% is invalid for the current user.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n Else;\r\n ServerActiveSandboxSet( pSandbox );\r\n SetUseActiveSandboxProperty( 1 );\r\n EndIf;\r\nElse;\r\n SetUseActiveSandboxProperty( 0 );\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 );\r\n ProcessQuit;\r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n########## pEleMapping ######################################################\r\n### Split ElementMapping parameter and create variables to be substituted ###\r\n################################################################################################# #############\r\nsElementMapping = TRIM( pEleMapping );\r\nsMappingDelimiter = TRIM( pMappingDelim );\r\nsElementStartDelim = TRIM( pEleStartDelim );\r\nsDelimDim = TRIM( pDimDelim );\r\nsDecimalSeparator = TRIM(pDecimalSeparator);\r\nsThousandSeparator = TRIM(pThousandSeparator);\r\nsFilter = TRIM( pFilter);\r\nsTargetFilter = '';\r\nnSuppressConsol = pSuppressConsol;\r\nnChar = 1;\r\nnCharCount = LONG( sElementMapping );\r\n\r\n# If there's no element mapping then the process can be used to multiply existing value by a factor\r\nIf( nCharCount > 0 );\r\n\r\n sWord = '';\r\n sLastDelim = '';\r\n\r\n # Add a trailing element delimiter so that the last element is picked up\r\n If( nCharCount > 0 );\r\n sElementMapping = sElementMapping | sMappingDelimiter ;\r\n nCharCount = nCharCount + LONG(sMappingDelimiter );\r\n EndIf;\r\n\r\n WHILE (nChar <= nCharCount);\r\n sChar = SUBST( sElementMapping, nChar, 1);\r\n\r\n # Used for delimiters, required for multiple character delimiters\r\n sDelim = '';\r\n nAddExtra = 0;\r\n\r\n # Ignore spaces\r\n IF (TRIM(sChar) @<> '' );\r\n\r\n ### Dimension Name ###\r\n\r\n # If the delimiter is more than 1 character peek ahead the same amount\r\n # Ignore the first character\r\n sDelim = sChar;\r\n nCount = LONG(sElementStartDelim) - 1;\r\n If( nCount > 0 & nChar + nCount <= nCharCount );\r\n # Add the extra characters\r\n sDelim = sDelim | SUBST( sElementMapping, nChar + 1, nCount);\r\n # Move to the end of the delimter\r\n nAddExtra = nCount;\r\n EndIf;\r\n\r\n If( sDelim @= sElementStartDelim );\r\n\r\n sChar = sDelim;\r\n\r\n If( sLastDelim @<> '' & sLastDelim @<> sDelimDim );\r\n sMessage = Expand ( 'The name of a dimension must follow a dimension delimiter %sDelimDim%' );\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n #ProcessError();\r\n EndIf;\r\n\r\n sDimension = sWord;\r\n\r\n If( DimensionExists( sDimension ) = 0 );\r\n # The dimension does not exist in the model. Cancel process\r\n sMessage = Expand( 'Dimension: %sDimension% does not exist');\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n #ProcessError();\r\n EndIf;\r\n\r\n # Check that the dimension is in the cube\r\n i = 1;\r\n iMax = 30;\r\n sDimInCube = 'No';\r\n While( i <= iMax );\r\n sDimensionOfCube = TabDim( pCube, i );\r\n If(sDimension @= sDimensionOfCube);\r\n sDimInCube = 'Yes';\r\n # record where the loop stops\r\n nIndex = i;\r\n i = 100;\r\n Else;\r\n i = i + 1;\r\n EndIf;\r\n End;\r\n\r\n If( sDimInCube @<> 'Yes' );\r\n # The dimension does not exist in the cube. Cancel process\r\n sMessage = Expand( 'Dimension %sDimension% does not exist in this cube');\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n #ProcessError();\r\n EndIf;\r\n\r\n ### Dimension exists so add it to the filters\r\n IF(LONG(sFilter) > 0 & sLastDelim @= '');\r\n sTargetFilter = sFilter | sDelimDim | sDimension | sElementStartDelim;\r\n sFilter = sFilter | sDelimDim | sDimension | sElementStartDelim;\r\n ElseiF(LONG(sFilter) > 0 & sLastDelim@<>'');\r\n sFilter = sFilter | sDelimDim | sDimension | sElementStartDelim;\r\n sTargetFilter = sTargetFilter | sDelimDim | sDimension | sElementStartDelim;\r\n Else;\r\n sFilter = sDimension | sElementStartDelim;\r\n sTargetFilter = sDimension | sElementStartDelim;\r\n EndIf;\r\n\r\n #Reset the source and target elements\r\n sSource = '';\r\n sTarget = '';\r\n\r\n # The variable nElementCount is used to keep track of how many elements there are per dimension\r\n # the first element is the source\r\n # the second element is the target\r\n # There shouldn't be any more than 2 elements per dimension\r\n\r\n # A new dimension has been found so reset the element count so\r\n # the code can tell how many elements have been specified for each dimension\r\n # There should just be 2\r\n\r\n nElementCount = 1;\r\n sLastDelim = sChar;\r\n\r\n # Clear the word\r\n sWord = '';\r\n\r\n Else;\r\n\r\n # Reset extra chars\r\n nAddExtra = 0;\r\n\r\n ### Check both dim delimiter and element delimiter ###\r\n nIsDelimiter = 0;\r\n\r\n # Check dim delim\r\n # If the delimiter is more than 1 character peek ahead the same amount\r\n # Ignore the first character\r\n sDelim = sChar;\r\n nCount = LONG(sDelimDim) - 1;\r\n If( nCount > 0 & nChar + nCount <= nCharCount );\r\n # Add the extra characters\r\n sDelim = sDelim | SUBST( sElementMapping, nChar + 1, nCount);\r\n # Move to the end of the delimter\r\n nAddExtra = nCount;\r\n EndIf;\r\n\r\n If( sDelim @= sDelimDim );\r\n nIsDelimiter = 1;\r\n sChar = sDelim;\r\n Else;\r\n # Reset extra chars\r\n nAddExtra = 0;\r\n\r\n ## Check element delimiter\r\n\r\n # If the delimiter is more than 1 character peek ahead the same amount\r\n # Ignore the first character\r\n sDelim = sChar;\r\n nCount = LONG(sMappingDelimiter) - 1;\r\n If( nCount > 0 & nChar + nCount <= nCharCount );\r\n # Add the extra characters\r\n sDelim = sDelim | SUBST( sElementMapping, nChar + 1, nCount);\r\n # Move to the end of the delimter\r\n nAddExtra = nCount;\r\n EndIf;\r\n\r\n If( sDelim @= sMappingDelimiter );\r\n nIsDelimiter = 1;\r\n sChar = sDelim;\r\n Else;\r\n # Reset extra chars\r\n nAddExtra = 0;\r\n EndIf;\r\n\r\n EndIf;\r\n\r\n If ( nIsDelimiter = 1 );\r\n\r\n If( sLastDelim @= '' % sLastDelim @= sDelimDim );\r\n sMessage = 'An element start delimiter must follow a dimension name: ' | sChar | ' (' | NumberToString(nChar) | ')';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n #ProcessError();\r\n EndIf;\r\n\r\n # an element has been found!\r\n sElement = sWord;\r\n\r\n If( DIMIX( sDimension, sElement ) = 0 );\r\n # The element does not exist in the dimension. Cancel process\r\n sMessage = Expand( 'Element: %sElement% does not exist in dimension %sDimension%' );\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n EndIf;\r\n\r\n # Allow consolidations only if pSuppressConsol is not set to 1\r\n # Consolidations may be made allowable\r\n # so that you can copy strings between c levels\r\n # or copy from a consolidated source element to an n level target element\r\n\r\n ### Check for errors before continuing\r\n If( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 );\r\n ProcessQuit;\r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n EndIf;\r\n\r\n If ( DTYPE( sDimension, sElement) @= 'C' );\r\n IF( nElementCount = 1 );\r\n If( pSuppressConsol <> 1 );\r\n nSuppressConsol = 0;\r\n EndIf;\r\n pSubN = 1;\r\n Else;\r\n sMessage = Expand( 'Target element: %sElement% for dimension %sDimension% is consolidated' );\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n #ProcessBreak;\r\n Endif;\r\n Endif;\r\n\r\n # Add the element to the source or target depending on whether it's the first or the second element\r\n # Get principal name\r\n # in case source element and this element are using different aliases\r\n\r\n sElement = DimensionElementPrincipalName(sDimension,sElement);\r\n\r\n # first element\r\n IF(nElementCount = 1);\r\n\r\n sSource = sElement;\r\n sFilter = sFilter | sElement;\r\n\r\n # second element\r\n ElseIf(nElementCount = 2);\r\n\r\n sTarget = sElement;\r\n sTargetFilter = sTargetFilter | sElement;\r\n\r\n Else;\r\n\r\n sMessage = Expand( 'There should only be 2 elements per dimension: %sDimension% , a source and a target');\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n #ProcessError();\r\n\r\n EndIf;\r\n\r\n If(nIndex = 1);\r\n nMappedDim1 = 1;\r\n sSourceDim1 = sSource;\r\n sTargetDim1 = sTarget;\r\n ElseIf(nIndex = 2);\r\n nMappedDim2 = 1;\r\n sSourceDim2 = sSource;\r\n sTargetDim2 = sTarget;\r\n ElseIf(nIndex = 3);\r\n nMappedDim3 = 1;\r\n sSourceDim3 = sSource;\r\n sTargetDim3 = sTarget;\r\n ElseIf(nIndex = 4);\r\n nMappedDim4 = 1;\r\n sSourceDim4 = sSource;\r\n sTargetDim4 = sTarget;\r\n ElseIf(nIndex = 5);\r\n nMappedDim5 = 1;\r\n sSourceDim5 = sSource;\r\n sTargetDim5 = sTarget;\r\n ElseIf(nIndex = 6);\r\n nMappedDim6 = 1;\r\n sSourceDim6 = sSource;\r\n sTargetDim6 = sTarget;\r\n ElseIf(nIndex = 7);\r\n nMappedDim7 = 1;\r\n sSourceDim7 = sSource;\r\n sTargetDim7 = sTarget;\r\n ElseIf(nIndex = 8);\r\n nMappedDim8 = 1;\r\n sSourceDim8 = sSource;\r\n sTargetDim8 = sTarget;\r\n ElseIf(nIndex = 9);\r\n nMappedDim9 = 1;\r\n sSourceDim9 = sSource;\r\n sTargetDim9 = sTarget;\r\n ElseIf(nIndex = 10);\r\n nMappedDim10 = 1;\r\n sSourceDim10 = sSource;\r\n sTargetDim10 = sTarget;\r\n ElseIf(nIndex = 11);\r\n nMappedDim11 = 1;\r\n sSourceDim11 = sSource;\r\n sTargetDim11 = sTarget;\r\n ElseIf(nIndex = 12);\r\n nMappedDim12 = 1;\r\n sSourceDim12 = sSource;\r\n sTargetDim12 = sTarget;\r\n ElseIf(nIndex = 13);\r\n nMappedDim13 = 1;\r\n sSourceDim13 = sSource;\r\n sTargetDim13 = sTarget;\r\n ElseIf(nIndex = 14);\r\n nMappedDim14 = 1;\r\n sSourceDim14 = sSource;\r\n sTargetDim14 = sTarget;\r\n ElseIf(nIndex = 15);\r\n nMappedDim15 = 1;\r\n sSourceDim15 = sSource;\r\n sTargetDim15 = sTarget;\r\n ElseIf(nIndex = 16);\r\n nMappedDim16 = 1;\r\n sSourceDim16 = sSource;\r\n sTargetDim16 = sTarget;\r\n ElseIf(nIndex = 17);\r\n nMappedDim17 = 1;\r\n sSourceDim17 = sSource;\r\n sTargetDim17 = sTarget;\r\n ElseIf(nIndex = 18);\r\n nMappedDim18 = 1;\r\n sSourceDim18 = sSource;\r\n sTargetDim18 = sTarget;\r\n ElseIf(nIndex = 19);\r\n nMappedDim19 = 1;\r\n sSourceDim19 = sSource;\r\n sTargetDim19 = sTarget;\r\n ElseIf(nIndex = 20);\r\n nMappedDim20 = 1;\r\n sSourceDim20 = sSource;\r\n sTargetDim20 = sTarget;\r\n ElseIf(nIndex = 21);\r\n nMappedDim21 = 1;\r\n sSourceDim21 = sSource;\r\n sTargetDim21 = sTarget;\r\n ElseIf(nIndex = 22);\r\n nMappedDim22 = 1;\r\n sSourceDim22 = sSource;\r\n sTargetDim22 = sTarget;\r\n ElseIf(nIndex = 23);\r\n nMappedDim23 = 1;\r\n sSourceDim23 = sSource;\r\n sTargetDim23 = sTarget;\r\n ElseIf(nIndex = 24);\r\n nMappedDim24 = 1;\r\n sSourceDim24 = sSource;\r\n sTargetDim24 = sTarget;\r\n ElseIf(nIndex = 25);\r\n nMappedDim25 = 1;\r\n sSourceDim25 = sSource;\r\n sTargetDim25 = sTarget;\r\n ElseIf(nIndex = 26);\r\n nMappedDim26 = 1;\r\n sSourceDim26 = sSource;\r\n sTargetDim26 = sTarget;\r\n ElseIf(nIndex = 27);\r\n nMappedDim27 = 1;\r\n sSourceDim27 = sSource;\r\n sTargetDim27 = sTarget;\r\n EndIf;\r\n\r\n sLastDelim = sChar;\r\n\r\n # Clear the word\r\n sWord = '';\r\n\r\n nElementCount = nElementCount + 1;\r\n\r\n Else;\r\n sWord = sWord | sChar;\r\n EndIf;\r\n\r\n EndIf;\r\n\r\n EndIf;\r\n\r\n nChar = nChar + nAddExtra + 1;\r\n\r\n END;\r\nENDIF;\r\n\r\n\r\n### Check that there if a dimension is used, there is a source element and a target element\r\ncSourceVariableStem = 'sSourceDim';\r\ncTargetVariableStem = 'sTargetDim';\r\ncMappedDimVariableStem = 'nMappedDim';\r\n\r\nnCounter = 1;\r\nWHILE(nCounter <= nDimensionCount);\r\n\r\n sMappedDimVariable = 'nMappedDim ' | NumberToString(nCounter);\r\n sDimensionUsedPadded = Expand('%' | sMappedDimVariable | '%');\r\n\r\n nMappedDim = StringToNumber(Trim(sDimensionUsedPadded));\r\n If(nMappedDim = 1);\r\n sDim = TabDim( pCube, nCounter );\r\n sSourceVariable = cSourceVariableStem | NumberToString(nCounter);\r\n sSourcePadded = Expand('%' | sSourceVariable | '%');\r\n sSource = Trim(sSourcePadded);\r\n\r\n sTargetVariable = cTargetVariableStem | NumberToString(nCounter);\r\n sTargetPadded = Expand('%' | sTargetVariable | '%');\r\n sTarget = Trim(sTargetPadded);\r\n\r\n If(sSource @='' % sTarget @='');\r\n sMessage = 'Source and/or target element is blank for dimension ' | sDim;\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n #ProcessError();\r\n EndIf;\r\n\r\n EndIf;\r\n\r\nnCounter = nCounter + 1;\r\n\r\nEND;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n DataSourceType = 'NULL';\r\n If( pStrictErrorHandling = 1 );\r\n ProcessQuit;\r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n# Branch depending on whether to do recursive calls to self on independent threads or run all in this thread\r\nIf( Scan( pEleStartDelim, pFilterParallel ) > 0 );\r\n sDimParallel = SubSt( pFilterParallel, 1, Scan( pEleStartDelim, pFilterParallel ) - 1 );\r\n sElementList = SubSt( pFilterParallel, Scan( pEleStartDelim, pFilterParallel ) + Long( pEleStartDelim ), Long( pFilterParallel ) );\r\n If( SubSt( sElementList, Long( sElementList ), 1 ) @<> pEleDelim );\r\n sElementList = sElementList | pEleDelim;\r\n EndIf;\r\n ## Counting elements in element list\r\n sElementListCount = sElementList;\r\n nElements = 0;\r\n While( Scan( pEleDelim, sElementListCount ) > 0 );\r\n nElements = nElements + 1;\r\n sElementListCount = SubSt( sElementListCount, Scan( pEleDelim, sElementListCount ) + Long( pEleDelim ), Long( sElementListCount ) );\r\n End;\r\n IF( Mod( nElements, nMaxThreads ) = 0 );\r\n nElemsPerThread = INT( nElements / nMaxThreads );\r\n ELSE;\r\n nElemsPerThread = INT( nElements / nMaxThreads ) + 1;\r\n ENDIF;\r\n nThreadElCounter = 0;\r\n nThreads = 0;\r\n While( Scan( pEleDelim, sElementList ) > 0 );\r\n sSlicerEle = SubSt( sElementList, 1, Scan( pEleDelim, sElementList ) - 1 );\r\n sElementList = SubSt( sElementList, Scan( pEleDelim, sElementList ) + Long( pEleDelim ), Long( sElementList ) );\r\n # Do recursive process call with new RunProcess function\r\n nThreadElCounter = nThreadElCounter + 1;\r\n sDimDelim = If(pFilter @= '', '', pDimDelim );\r\n IF( nThreadElCounter = 1 );\r\n sFilter = Expand('%pFilter%%sDimDelim%%sDimParallel%%pEleStartDelim%%sSlicerEle%');\r\n ELSE;\r\n sFilter = Expand('%sFilter%%pEleDelim%%sSlicerEle%');\r\n ENDIF;\r\n IF( nThreadElCounter >= nElemsPerThread );\r\n nThreadID = INT( RAND( ) * 10000 + 1) + Numbr(cTimeStamp);\r\n sThreadControlFile = LOWER( GetProcessName() | '_ThreadControlFile_' | cRandomInt | '_' | NumberToString(nThreadID) | '_' | cTimeStamp );\r\n AsciiOutput( cDir | sThreadControlFile | '.txt', '' );\r\n LogOutput( 'INFO', 'Executing subTI with Thread ID: ' | NumberToString(nThreadID) );\r\n RunProcess( cThisProcName, 'pLogoutput', pLogoutput,\r\n \t'pCube', pCube, 'pSrcView', pSrcView, 'pTgtView', pTgtView,\r\n \t'pFilter', sFilter, 'pFilterParallel', '', 'pEleMapping', pEleMapping, 'pMappingDelim', pMappingDelim,\r\n \t'pDimDelim', pDimDelim, 'pEleStartDelim', pEleStartDelim, 'pEleDelim', pEleDelim,\r\n \t'pFactor', pFactor, 'pSuppressConsol', pSuppressConsol, 'pSuppressConsolStrings', pSuppressConsolStrings, 'pSuppressRules', pSuppressRules, 'pSuppressZero', pSuppressZero, 'pCumulate', pCumulate,\r\n \t'pZeroTarget', pZeroTarget, 'pZeroSource', pZeroSource, 'pTemp', pTemp, 'pCubeLogging', pCubeLogging, 'pSandbox', pSandbox, 'pFile', pFile, 'pDecimalSeparator', pDecimalSeparator, 'pThousandSeparator', pThousandSeparator,\r\n 'pThreadMode', 1, 'pThreadControlFile', sThreadControlFile\r\n );\r\n \t nThreadElCounter = 0;\r\n \t sFilter = '';\r\n \t nThreads = nThreads + 1;\r\n \tENDIF;\r\n End;\r\n ## Process last elements - only when filter is not empty (there are still elements)\r\n IF( sFilter @<> '' );\r\n RunProcess( cThisProcName, 'pLogoutput', pLogoutput,\r\n \t'pCube', pCube, 'pSrcView', pSrcView, 'pTgtView', pTgtView,\r\n \t'pFilter', sFilter, 'pFilterParallel', '', 'pEleMapping', pEleMapping, 'pMappingDelim', pMappingDelim,\r\n \t'pDimDelim', pDimDelim, 'pEleStartDelim', pEleStartDelim, 'pEleDelim', pEleDelim,\r\n \t'pFactor', pFactor, 'pSuppressConsol', pSuppressConsol, 'pSuppressConsolStrings', pSuppressConsolStrings, 'pSuppressRules', pSuppressRules, 'pSuppressZero', pSuppressZero, 'pCumulate', pCumulate,\r\n \t'pZeroTarget', pZeroTarget, 'pZeroSource', pZeroSource, 'pTemp', pTemp, 'pCubeLogging', pCubeLogging, 'pSandbox', pSandbox, 'pFile', pFile, 'pDecimalSeparator', pDecimalSeparator, 'pThousandSeparator', pThousandSeparator,\r\n 'pThreadMode', 1, 'pThreadControlFile', sThreadControlFile\r\n );\r\n ENDIF;\r\n DataSourceType = 'NULL';\r\n Sleep( 1000 );\r\nElse;\r\n ### Create View of target to zero out\r\n ### Check that there's something in sTargetFilter so the cube doesn't accidentally get wiped out\r\n IF( pThreadControlFile @<> '' );\r\n LogOutput( 'info', 'creating thread file ' | cDir | pThreadControlFile | '.txt' );\r\n AsciiOutput( cDir | pThreadControlFile | '.txt', '' );\r\n ENDIF;\r\n If(pZeroTarget = 1 & LONG(sTargetFilter)> 0);\r\n\r\n sProc = '}bedrock.cube.data.clear';\r\n nRet = ExecuteProcess( sProc,\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pCube', pCube,\r\n 'pView', cViewTarget,\r\n 'pFilter', sTargetFilter,\r\n 'pDimDelim', pDimDelim,\r\n 'pEleStartDelim', pEleStartDelim,\r\n 'pEleDelim', pEleDelim,\r\n 'pCubeLogging', pCubeLogging,\r\n 'pTemp', pTemp,\r\n 'pSandbox', pSandbox\r\n );\r\n\r\n IF(nRet <> 0);\r\n sMessage = 'Error clearing the target view.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 );\r\n ProcessQuit;\r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n ENDIF;\r\n\r\n Endif;\r\n\r\n If( pFile = 0 );\r\n\r\n ### Create View of Source ###\r\n\r\n nRet = ExecuteProcess('}bedrock.cube.view.create',\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pCube', pCube,\r\n 'pView', cViewSource,\r\n 'pFilter', sFilter,\r\n 'pSuppressZero', pSuppressZero,\r\n 'pSuppressConsol', nSuppressConsol,\r\n 'pSuppressRules', pSuppressRules,\r\n 'pSuppressConsolStrings', pSuppressConsolStrings,\r\n 'pIncludeDescendants',pIncludeDescendants,\r\n 'pDimDelim', pDimDelim,\r\n 'pEleStartDelim', pEleStartDelim,\r\n 'pEleDelim', pEleDelim ,\r\n 'pTemp', pTemp,\r\n 'pSubN', pSubN\r\n );\r\n\r\n IF(nRet <> 0);\r\n sMessage = 'Error creating the view from the filter.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 );\r\n ProcessQuit;\r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n ENDIF;\r\n\r\n\r\n ### Assign Datasource ###\r\n DataSourceType = 'VIEW';\r\n DatasourceNameForServer = pCube;\r\n DatasourceNameForClient = pCube;\r\n DatasourceCubeView = cViewSource;\r\n nThreadMode = 1;\r\n Else;\r\n ### Export Data to file ###\r\n\r\n nRet = ExecuteProcess('}bedrock.cube.data.export',\r\n 'pLogoutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pCube', pCube,\r\n 'pView', cViewSource,\r\n 'pFilter', sFilter,\r\n 'pFilterParallel', '',\r\n 'pParallelThreads', 0,\r\n 'pDimDelim', pDimDelim,\r\n 'pEleStartDelim', pEleStartDelim,\r\n 'pEleDelim', pEleDelim,\r\n 'pSuppressZero', pSuppressZero,\r\n 'pSuppressConsol', nSuppressConsol,\r\n 'pSuppressRules', pSuppressRules,\r\n 'pSuppressConsolStrings', pSuppressConsolStrings,\r\n 'pIncludeDescendants',pIncludeDescendants,\r\n 'pZeroSource', 0,\r\n 'pCubeLogging', pCubeLogging,\r\n 'pTemp', pTemp,\r\n 'pFilePath', cDir,\r\n 'pFileName', cFileName,\r\n 'pDelim', cDelimiter,\r\n 'pDecimalSeparator', sDecimalSeparator,\r\n 'pThousandSeparator', sThousandSeparator,\r\n 'pQuote', cQuote,\r\n 'pTitleRecord', cTitleRows,\r\n 'pSandbox', pSandbox\r\n );\r\n\r\n IF(nRet <> 0);\r\n sMessage = 'Error exporting data to file.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 );\r\n ProcessQuit;\r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n ENDIF;\r\n\r\n If(FileExists(cFile) = 0);\r\n # If the file does not exist, it means that nothing got exported, so there is nothing to import\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( 'Process:%cThisProcName% is skipping import as export file %cFile% was not found.' ) );\r\n EndIf;\r\n DataSourceType = 'NULL';\r\n Else;\r\n ### Assign Datasource ###\r\n DataSourceType = 'CHARACTERDELIMITED';\r\n DatasourceNameForServer = cFile;\r\n DatasourceNameForClient = cFile;\r\n DatasourceASCIIHeaderRecords = cTitleRows;\r\n DatasourceASCIIDelimiter = cDelimiter;\r\n DatasourceASCIIQuoteCharacter = cQuote;\r\n EndIf;\r\n\r\n nThreadMode = 1;\r\n\r\n EndIf;\r\n\r\nEndIf;\r\n\r\n### End Prolog ###\r\n", "MetadataProcedure": "#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "DataProcedure": "#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n\r\n#################################################################################################\r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n#################################################################################################\r\n\r\nIf( pFile > 0 );\r\n v0 = v1; v1 = v2; v2 = v3; v3 = v4; v4 = v5; v5 = v6; v6 = v7; v7 = v8; v8 = v9; v9 = v10; v10 = v11; v11 = v12; v12 = v13; v13 = v14; v14 = v15;\r\n v15 = v16; v16 = v17; v17 = v18; v18 = v19; v19 = v20; v20 = v21; v21 = v22; v22 = v23; v23 = v24; v24 = v25; v25 = v26; v26 = v27; v27 = v28; v28 = v29;\r\nEndIf;\r\n\r\nv1 = IF(nMappedDim1 = 1, IF(v1 @= sSourceDim1 % elisanc(sDim1,sSourceDim1,v1)=1, sTargetDim1, v1), v1);\r\nv2 = IF(nMappedDim2 = 1, IF(v2 @= sSourceDim2 % elisanc(sDim2,sSourceDim2,v2)=1, sTargetDim2, v2), v2);\r\nv3 = IF(nMappedDim3 = 1, IF(v3 @= sSourceDim3 % elisanc(sDim3,sSourceDim3,v3)=1, sTargetDim3, v3), v3);\r\nv4 = IF(nMappedDim4 = 1, IF(v4 @= sSourceDim4 % elisanc(sDim4,sSourceDim4,v4)=1, sTargetDim4, v4), v4);\r\nv5 = IF(nMappedDim5 = 1, IF(v5 @= sSourceDim5 % elisanc(sDim5,sSourceDim5,v5)=1, sTargetDim5, v5), v5);\r\nv6 = IF(nMappedDim6 = 1, IF(v6 @= sSourceDim6 % elisanc(sDim6,sSourceDim6,v6)=1, sTargetDim6, v6), v6);\r\nv7 = IF(nMappedDim7 = 1, IF(v7 @= sSourceDim7 % elisanc(sDim7,sSourceDim7,v7)=1, sTargetDim7, v7), v7);\r\nv8 = IF(nMappedDim8 = 1, IF(v8 @= sSourceDim8 % elisanc(sDim8,sSourceDim8,v8)=1, sTargetDim8, v8), v8);\r\nv9 = IF(nMappedDim9 = 1, IF(v9 @= sSourceDim9 % elisanc(sDim9,sSourceDim9,v9)=1, sTargetDim9, v9), v9);\r\nv10 = IF(nMappedDim10 = 1, IF(v10 @= sSourceDim10 % elisanc(sDim10,sSourceDim10,v10)=1, sTargetDim10, v10), v10);\r\nv11 = IF(nMappedDim11 = 1, IF(v11 @= sSourceDim11 % elisanc(sDim11,sSourceDim11,v11)=1, sTargetDim11, v11), v11);\r\nv12 = IF(nMappedDim12 = 1, IF(v12 @= sSourceDim12 % elisanc(sDim12,sSourceDim12,v12)=1, sTargetDim12, v12), v12);\r\nv13 = IF(nMappedDim13 = 1, IF(v13 @= sSourceDim13 % elisanc(sDim13,sSourceDim13,v13)=1, sTargetDim13, v13), v13);\r\nv14 = IF(nMappedDim14 = 1, IF(v14 @= sSourceDim14 % elisanc(sDim14,sSourceDim14,v14)=1, sTargetDim14, v14), v14);\r\nv15 = IF(nMappedDim15 = 1, IF(v15 @= sSourceDim15 % elisanc(sDim15,sSourceDim15,v15)=1, sTargetDim15, v15), v15);\r\nv16 = IF(nMappedDim16 = 1, IF(v16 @= sSourceDim16 % elisanc(sDim16,sSourceDim16,v16)=1, sTargetDim16, v16), v16);\r\nv17 = IF(nMappedDim17 = 1, IF(v17 @= sSourceDim17 % elisanc(sDim17,sSourceDim17,v17)=1, sTargetDim17, v17), v17);\r\nv18 = IF(nMappedDim18 = 1, IF(v18 @= sSourceDim18 % elisanc(sDim18,sSourceDim18,v18)=1, sTargetDim18, v18), v18);\r\nv19 = IF(nMappedDim19 = 1, IF(v19 @= sSourceDim19 % elisanc(sDim19,sSourceDim19,v19)=1, sTargetDim19, v19), v19);\r\nv20 = IF(nMappedDim20 = 1, IF(v20 @= sSourceDim20 % elisanc(sDim20,sSourceDim20,v20)=1, sTargetDim20, v20), v20);\r\nv21 = IF(nMappedDim21 = 1, IF(v21 @= sSourceDim21 % elisanc(sDim21,sSourceDim21,v21)=1, sTargetDim21, v21), v21);\r\nv22 = IF(nMappedDim22 = 1, IF(v22 @= sSourceDim22 % elisanc(sDim22,sSourceDim22,v22)=1, sTargetDim22, v22), v22);\r\nv23 = IF(nMappedDim23 = 1, IF(v23 @= sSourceDim23 % elisanc(sDim23,sSourceDim23,v23)=1, sTargetDim23, v23), v23);\r\nv24 = IF(nMappedDim24 = 1, IF(v24 @= sSourceDim24 % elisanc(sDim23,sSourceDim24,v24)=1, sTargetDim24, v24), v24);\r\nv25 = IF(nMappedDim25 = 1, IF(v25 @= sSourceDim25 % elisanc(sDim25,sSourceDim25,v25)=1, sTargetDim25, v25), v25);\r\nv26 = IF(nMappedDim26 = 1, IF(v26 @= sSourceDim26 % elisanc(sDim26,sSourceDim26,v26)=1, sTargetDim26, v26), v26);\r\nv27 = IF(nMappedDim27 = 1, IF(v27 @= sSourceDim27 % elisanc(sDim27,sSourceDim27,v27)=1, sTargetDim27, v27), v27);\r\n\r\n\r\n### Write data from source version to target version ###\r\n\r\n# Selects the correct CellPut formula depending upon the number of dimensions in the cube\r\n# and whether the value is numeric or string ( max 27 dims catered for in this code )\r\n# value type determined by element type of last dimension in cube\r\n# could have used Value_is_String = 1 and NValue/SValue but this works just as well\r\n\r\n\r\nIf( nDimensionCount = 2 );\r\n If( CellIsUpdateable( pCube, v1, v2 ) = 1 );\r\n sElType = DType( sDim2, v2 );\r\n IF( SubSt( pCube, 1, 17 ) @= '}ElementSecurity_');\r\n v3 = IF( v3 @= '', 'NONE', v3 );\r\n ElementSecurityPut( v3, sDim1, v1, v2 );\r\n ELSEIF( sElType @= 'AA' );\r\n AttrPutS( v3, sDim1, v1, v2, 1 );\r\n ELSEIF( sElType @= 'AS' );\r\n AttrPutS( v3, sDim1, v1, v2 );\r\n ELSEIF( sElType @= 'AN' );\r\n AttrPutN( StringToNumberEx( v3, sDecimalSeparator, sThousandSeparator ) * nFactor, sDim1, v1, v2 );\r\n ElseIf( sElType @= 'S' );\r\n CellPutS( v3, pCube, v1, v2 );\r\n Else;\r\n IF( pCumulate = 1);\r\n nObal = CellGetN( pCube, v1, v2 );\r\n nCbal = nObal + StringToNumberEx( v3, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n ELSE;\r\n nCbal = StringToNumberEx( v3, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n Endif;\r\n CellPutN( nCbal, pCube, v1, v2 );\r\n EndIf;\r\n EndIf;\r\nElseIf( nDimensionCount = 3 );\r\n If( CellIsUpdateable( pCube, v1, v2, v3 ) = 1 );\r\n sElType = DType( sDim3, v3 );\r\n If( sElType @<> 'S' );\r\n IF( pCumulate = 1);\r\n nObal = CellGetN( pCube, v1, v2, v3 );\r\n nCbal = nObal + StringToNumberEx( v4, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n ELSE;\r\n nCbal = StringToNumberEx( v4, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n Endif;\r\n CellPutN( nCbal, pCube, v1, v2, v3 );\r\n Else;\r\n CellPutS( v4, pCube, v1, v2, v3 );\r\n EndIf;\r\n EndIf;\r\nElseIf( nDimensionCount = 4 );\r\n If( CellIsUpdateable( pCube, v1, v2, v3, v4 ) = 1 );\r\n sElType = DType( sDim4, v4 );\r\n If( sElType @<> 'S' );\r\n IF( pCumulate = 1);\r\n nObal = CellGetN( pCube, v1, v2, v3, v4);\r\n nCbal = nObal + StringToNumberEx( v5, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n ELSE;\r\n nCbal = StringToNumberEx( v5, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n Endif;\r\n CellPutN( nCbal, pCube, v1, v2, v3, v4);\r\n Else;\r\n CellPutS( v5, pCube, v1, v2, v3, v4);\r\n EndIf;\r\n EndIf;\r\nElseIf( nDimensionCount = 5 );\r\n If( CellIsUpdateable( pCube, v1, v2, v3, v4, v5 ) = 1 );\r\n sElType = DType( sDim5, v5 );\r\n If( sElType @<> 'S' );\r\n IF(pCumulate = 1);\r\n nObal = CellGetN( pCube, v1, v2, v3, v4, v5 );\r\n nCbal = nObal + StringToNumberEx( v6, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n ELSE;\r\n nCbal = StringToNumberEx( v6, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n Endif;\r\n CellPutN( nCbal, pCube, v1, v2, v3, v4, v5 );\r\n Else;\r\n CellPutS( v6, pCube, v1, v2, v3, v4, v5 );\r\n EndIf;\r\n EndIf;\r\n ElseIf( nDimensionCount = 6 );\r\n If( CellIsUpdateable( pCube, v1, v2, v3, v4, v5, v6 ) = 1 );\r\n sElType = DType( sDim6, v6 );\r\n If( sElType @<> 'S' );\r\n IF( pCumulate = 1);\r\n nObal = CellGetN( pCube, v1, v2, v3, v4, v5, v6 );\r\n nCbal = nObal + StringToNumberEx( v7, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n ELSE;\r\n nCbal = StringToNumberEx( v7, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n Endif;\r\n CellPutN( nCbal, pCube, v1, v2, v3, v4, v5, v6 );\r\n Else;\r\n CellPutS( v7, pCube, v1, v2, v3, v4, v5, v6 );\r\n EndIf;\r\n EndIf;\r\n ElseIf( nDimensionCount = 7 );\r\n If( CellIsUpdateable( pCube, v1, v2, v3, v4, v5, v6, v7 ) = 1 );\r\n sElType = DType( sDim7, v7 );\r\n If( sElType @<> 'S' );\r\n IF( pCumulate = 1);\r\n nObal = CellGetN( pCube, v1, v2, v3, v4, v5, v6, v7 );\r\n nCbal = nObal + StringToNumberEx( v8, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n ELSE;\r\n nCbal = StringToNumberEx( v8, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n Endif;\r\n CellPutN( nCbal, pCube, v1, v2, v3, v4, v5, v6, v7 );\r\n Else;\r\n CellPutS( v8, pCube, v1, v2, v3, v4, v5, v6, v7 );\r\n EndIf;\r\n EndIf;\r\n ElseIf( nDimensionCount = 8 );\r\n If( CellIsUpdateable( pCube, v1, v2, v3, v4, v5, v6, v7, v8 ) = 1 );\r\n sElType = DType( sDim8, v8 );\r\n If( sElType @<> 'S' );\r\n IF( pCumulate = 1);\r\n nObal = CellGetN( pCube, v1, v2, v3, v4, v5, v6, v7, v8 );\r\n nCbal = nObal + StringToNumberEx( v9, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n ELSE;\r\n nCbal = StringToNumberEx( v9, sDecimalSeparator, sThousandSeparator )* nFactor;\r\n Endif;\r\n CellPutN( nCbal, pCube, v1, v2, v3, v4, v5, v6, v7, v8 );\r\n Else;\r\n CellPutS( v9, pCube, v1, v2, v3, v4, v5, v6, v7, v8 );\r\n EndIf;\r\n EndIf;\r\n ElseIf( nDimensionCount = 9 );\r\n If( CellIsUpdateable( pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9 ) = 1 );\r\n sElType = DType( sDim9, v9 );\r\n If( sElType @<> 'S' );\r\n IF( pCumulate = 1);\r\n nObal = CellGetN( pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9 );\r\n nCbal = nObal + StringToNumberEx( v10, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n ELSE;\r\n nCbal = StringToNumberEx( v10, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n Endif;\r\n CellPutN( nCbal, pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9 );\r\n Else;\r\n CellPutS( v10, pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9 );\r\n EndIf;\r\n EndIf;\r\n ElseIf( nDimensionCount = 10 );\r\n If( CellIsUpdateable( pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10 ) = 1 );\r\n sElType = DType( sDim10, v10 );\r\n If( sElType @<> 'S' );\r\n IF( pCumulate = 1);\r\n nObal = CellGetN( pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10 );\r\n nCbal = nObal + StringToNumberEx( v11, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n ELSE;\r\n nCbal = StringToNumberEx( v11, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n Endif;\r\n CellPutN( nCbal, pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10 );\r\n Else;\r\n CellPutS( v11, pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10 );\r\n EndIf;\r\n EndIf;\r\n ElseIf( nDimensionCount = 11 );\r\n If( CellIsUpdateable( pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11 ) = 1 );\r\n sElType = DType( sDim11, v11 );\r\n If( sElType @<> 'S' );\r\n IF( pCumulate = 1);\r\n nObal = CellGetN( pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11 );\r\n nCbal = nObal + StringToNumberEx( v12, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n ELSE;\r\n nCbal = StringToNumberEx( v12, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n Endif;\r\n CellPutN( nCbal, pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11 );\r\n Else;\r\n CellPutS( v12, pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11 );\r\n EndIf;\r\n EndIf;\r\n ElseIf( nDimensionCount = 12 );\r\n If( CellIsUpdateable( pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12 ) = 1 );\r\n sElType = DType( sDim12, v12 );\r\n If( sElType @<> 'S' );\r\n IF( pCumulate = 1);\r\n nObal = CellGetN( pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12 );\r\n nCbal = nObal + StringToNumberEx( v13, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n ELSE;\r\n nCbal = StringToNumberEx( v13, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n Endif;\r\n CellPutN( nCbal, pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12 );\r\n Else;\r\n CellPutS( v13, pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12 );\r\n EndIf;\r\n EndIf;\r\n ElseIf( nDimensionCount = 13 );\r\n If( CellIsUpdateable( pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13 ) = 1 );\r\n sElType = DType( sDim13, v13 );\r\n If( sElType @<> 'S' );\r\n IF( pCumulate = 1);\r\n nObal = CellGetN( pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13 );\r\n nCbal = nObal + StringToNumberEx( v14, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n ELSE;\r\n nCbal = StringToNumberEx( v14, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n Endif;\r\n CellPutN( nCbal, pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13 );\r\n Else;\r\n CellPutS( v14, pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13 );\r\n EndIf;\r\n EndIf;\r\n ElseIf( nDimensionCount = 14 );\r\n If( CellIsUpdateable( pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14 ) = 1 );\r\n sElType = DType( sDim14, v14 );\r\n If( sElType @<> 'S' );\r\n IF( pCumulate = 1);\r\n nObal = CellGetN( pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14 );\r\n nCbal = nObal + StringToNumberEx( v15, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n ELSE;\r\n nCbal = StringToNumberEx( v15, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n Endif;\r\n CellPutN( nCbal, pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14 );\r\n Else;\r\n CellPutS( v15, pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14 );\r\n EndIf;\r\n EndIf;\r\n ElseIf( nDimensionCount = 15 );\r\n If( CellIsUpdateable( pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15 ) = 1 );\r\n sElType = DType( sDim15, v15 );\r\n If( sElType @<> 'S' );\r\n IF( pCumulate = 1);\r\n nObal = CellGetN( pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15 );\r\n nCbal = nObal + StringToNumberEx( v16, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n ELSE;\r\n nCbal = StringToNumberEx( v16, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n Endif;\r\n CellPutN( nCbal, pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15 );\r\n Else;\r\n CellPutS( v16, pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15 );\r\n EndIf;\r\n EndIf;\r\n ElseIf( nDimensionCount = 16 );\r\n If( CellIsUpdateable( pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16 ) = 1 );\r\n sElType = DType( sDim16, v16 );\r\n If( sElType @<> 'S' );\r\n IF( pCumulate = 1);\r\n nObal = CellGetN( pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16 );\r\n nCbal = nObal + StringToNumberEx( v17, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n ELSE;\r\n nCbal = StringToNumberEx( v17, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n Endif;\r\n CellPutN( nCbal, pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16 );\r\n Else;\r\n CellPutS( v17, pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16 );\r\n EndIf;\r\n EndIf;\r\n ElseIf( nDimensionCount = 17 );\r\n If( CellIsUpdateable( pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17 ) = 1 );\r\n sElType = DType( sDim17, v17 );\r\n If( sElType @<> 'S' );\r\n IF( pCumulate = 1);\r\n nObal = CellGetN( pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17 );\r\n nCbal = nObal + StringToNumberEx( v18, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n ELSE;\r\n nCbal = StringToNumberEx( v18, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n Endif;\r\n CellPutN( nCbal, pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17 );\r\n Else;\r\n CellPutS( v18, pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17 );\r\n EndIf;\r\n EndIf;\r\n ElseIf( nDimensionCount = 18 );\r\n If( CellIsUpdateable( pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18 ) = 1 );\r\n sElType = DType( sDim18, v18 );\r\n If( sElType @<> 'S' );\r\n IF( pCumulate = 1);\r\n nObal = CellGetN( pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18 );\r\n nCbal = nObal + StringToNumberEx( v19, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n ELSE;\r\n nCbal = StringToNumberEx( v19, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n Endif;\r\n CellPutN( nCbal, pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18 );\r\n Else;\r\n CellPutS( v19, pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18 );\r\n EndIf;\r\n EndIf;\r\n ElseIf( nDimensionCount = 19 );\r\n If( CellIsUpdateable( pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19 ) = 1 );\r\n sElType = DType( sDim19, v19 );\r\n If( sElType @<> 'S' );\r\n IF( pCumulate = 1);\r\n nObal = CellGetN( pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19 );\r\n nCbal = nObal + StringToNumberEx( v20, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n ELSE;\r\n nCbal = StringToNumberEx( v20, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n Endif;\r\n CellPutN( nCbal, pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19 );\r\n Else;\r\n CellPutS( v20, pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19 );\r\n EndIf;\r\n EndIf;\r\n ElseIf( nDimensionCount = 20 );\r\n If( CellIsUpdateable( pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20 ) = 1 );\r\n sElType = DType( sDim20, v20 );\r\n If( sElType @<> 'S' );\r\n IF( pCumulate = 1);\r\n nObal = CellGetN( pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20 );\r\n nCbal = nObal + StringToNumberEx( v21, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n ELSE;\r\n nCbal = StringToNumberEx( v21, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n Endif;\r\n CellPutN( nCbal, pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20 );\r\n Else;\r\n CellPutS( v21, pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20 );\r\n EndIf;\r\n EndIf;\r\n ElseIf( nDimensionCount = 21 );\r\n If( CellIsUpdateable( pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21 ) = 1 );\r\n sElType = DType( sDim21, v21 );\r\n If( sElType @<> 'S' );\r\n IF( pCumulate = 1);\r\n nObal = CellGetN( pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21 );\r\n nCbal = nObal + StringToNumberEx( v22, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n ELSE;\r\n nCbal = StringToNumberEx( v22, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n Endif;\r\n CellPutN( nCbal, pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21 );\r\n Else;\r\n CellPutS( v22, pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21 );\r\n EndIf;\r\n EndIf;\r\n ElseIf( nDimensionCount = 22 );\r\n If( CellIsUpdateable( pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22 ) = 1 );\r\n sElType = DType( sDim22, v22 );\r\n If( sElType @<> 'S' );\r\n IF( pCumulate = 1);\r\n nObal = CellGetN( pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22 );\r\n nCbal = nObal + StringToNumberEx( v23, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n ELSE;\r\n nCbal = StringToNumberEx( v23, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n Endif;\r\n CellPutN( nCbal, pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22 );\r\n Else;\r\n CellPutS( v23, pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22 );\r\n EndIf;\r\n EndIf;\r\n ElseIf( nDimensionCount = 23 );\r\n If( CellIsUpdateable( pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21,\r\n v22, v23 ) = 1 );\r\n sElType = DType( sDim23, v23 );\r\n If( sElType @<> 'S' );\r\n IF( pCumulate >= 1);\r\n nObal = CellGetN( pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23 );\r\n nCbal = nObal + StringToNumberEx( v24, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n ELSE;\r\n nCbal = StringToNumberEx( v24, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n Endif;\r\n CellPutN( nCbal, pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23 );\r\n Else;\r\n CellPutS( v24, pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23 );\r\n EndIf;\r\n EndIf;\r\n ElseIf( nDimensionCount = 24 );\r\n If( CellIsUpdateable( pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24 ) = 1 );\r\n sElType = DType( sDim24, v24 );\r\n If( sElType @<> 'S' );\r\n IF( pCumulate = 1);\r\n nObal = CellGetN( pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24 );\r\n nCbal = nObal + StringToNumberEx( v25, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n ELSE;\r\n nCbal = StringToNumberEx( v25, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n Endif;\r\n CellPutN( nCbal, pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24 );\r\n Else;\r\n CellPutS( v25, pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24 );\r\n EndIf;\r\n EndIf;\r\n ElseIf( nDimensionCount = 25 );\r\n If( CellIsUpdateable( pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25 ) = 1 );\r\n sElType = DType( sDim25, v25 );\r\n If( sElType @<> 'S' );\r\n IF( pCumulate = 1);\r\n nObal = CellGetN( pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25 );\r\n nCbal = nObal + StringToNumberEx( v26, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n ELSE;\r\n nCbal = StringToNumberEx( v26, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n Endif;\r\n CellPutN( nCbal, pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25 );\r\n Else;\r\n CellPutS( v26, pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25 );\r\n EndIf;\r\n EndIf;\r\nElseIf( nDimensionCount = 26 );\r\n If( CellIsUpdateable( pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21,\r\n v22, v23, v24, v25, v26 ) = 1 );\r\n sElType = DType( sDim26, v26 );\r\n If( sElType @<> 'S' );\r\n IF( pCumulate = 1);\r\n nObal = CellGetN( pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26 );\r\n nCbal = nObal + StringToNumberEx( v27, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n ELSE;\r\n nCbal = StringToNumberEx( v27, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n Endif;\r\n CellPutN( nCbal, pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26 );\r\n Else;\r\n CellPutS( v27, pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26 );\r\n EndIf;\r\n EndIf;\r\nElseIf( nDimensionCount = 27 );\r\n If( CellIsUpdateable( pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27 ) = 1 );\r\n sElType = DType( sDim27, v27 );\r\n If( sElType @<> 'S' );\r\n IF( pCumulate >= 1);\r\n nObal = CellGetN( pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27 );\r\n nCbal = nObal + StringToNumberEx( v28, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n ELSE;\r\n nCbal = StringToNumberEx( v28, sDecimalSeparator, sThousandSeparator ) * nFactor;\r\n Endif;\r\n CellPutN( nCbal, pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27 );\r\n Else;\r\n CellPutS( v28, pCube, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27 );\r\n EndIf;\r\n EndIf;\r\n\r\n EndIf;\r\n\r\n\r\n### End Data ###", "EpilogProcedure": "#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n\r\n#################################################################################################\r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n#################################################################################################\r\n\r\n# Zero out source cube #\r\nIF( pZeroSource = 1 & nErrors = 0 );\r\n sProc = '}bedrock.cube.data.clear';\r\n nRet = ExecuteProcess( sProc,\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pCube', pCube,\r\n 'pView', cViewSource,\r\n 'pFilter', sFilter,\r\n 'pDimDelim', pDimDelim,\r\n 'pEleStartDelim', pEleStartDelim,\r\n 'pEleDelim', pEleDelim,\r\n 'pTemp', pTemp,\r\n 'pCubeLogging', pCubeLogging,\r\n 'pSandbox', pSandbox\r\n );\r\n If(nRet <> 0);\r\n sMessage = 'Error clearing the source view.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n ProcessError();\r\n EndIf;\r\nEndIf;\r\n\r\n### Delete export file if used\r\nIf( pFile = 1 );\r\n# ASCIIDelete( cFile );\r\nEndIf;\r\n\r\n### Delete thread control file if used\r\nIF( pThreadControlFile @<> '' );\r\n LogOutput( 'INFO', 'Removing thread control file: ' | cDir | pThreadControlFile | '.txt' );\r\n ASCIIDelete( cDir | pThreadControlFile | '.txt' );\r\nENDIF;\r\n\r\n### Wait for all parallel threads to finish if using pFilterParallel\r\nIf( pFilterParallel @<> '' );\r\n sThreadFilePattern = LOWER( GetProcessName() | '_ThreadControlFile_' | cRandomInt | '_' | '*.txt' );\r\n LogOutput( 'INFO', 'Checking for: ' | sThreadFilePattern );\r\n i = 1;\r\n While( i < pMaxWaitSeconds );\r\n sThreadCheck = WildcardFileSearch( cDir | sThreadFilePattern, '' );\r\n If( sThreadCheck @<> '' );\r\n Sleep( 1000 );\r\n Else;\r\n Break;\r\n EndIf;\r\n\r\n i = i + 1;\r\n End;\r\nEndIf;\r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully copied data from %pSrcView% view to the %pTgtView% view in the %pCube% cube.' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n### End Epilog ###", "HasSecurityAccess": true, - "UIData": "_ParameterConstraints=e30=\f", + "UIData": "", "DataSource": { "Type": "TM1CubeView", "dataSourceNameForClient": "zzSYS 50 Dim Cube", @@ -13,21 +13,9 @@ "view": "Temp" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pCube", - "Prompt": "REQUIRED: Cube", + "Prompt": "REQUIRED: Cube name", "Value": "", "Type": "String" }, @@ -45,115 +33,115 @@ }, { "Name": "pFilter", - "Prompt": "OPTIONAL: Filter Unmapped Dimensions using format: Year\u00a6 2006 + 2007 & Scenario\u00a6 Actual + Budget etc", + "Prompt": "OPTIONAL: Filter on cube in format: 'dim_one\u00a6 el_one + el_two & dim_two\u00a6 el_one + el_two'", "Value": "", "Type": "String" }, { "Name": "pFilterParallel", - "Prompt": "OPTIONAL: Parallelization Filter: Month:Q1+Q2+Q3+Q4 (Blank=run single threaded). Single dimension parallel slices. Will be added to filter single element at a time. Dimension must not be part of filter", + "Prompt": "OPTIONAL: Parallelization filter in format: dim_one\u00a6 el_one + el_two. Dimension must not be part of filter", "Value": "", "Type": "String" }, { "Name": "pParallelThreads", - "Prompt": "Maximum number of threads to run when parallel processing is enabled ( if <2 will execute one thread, but parallel filter is still applied )", + "Prompt": "OPTIONAL: Maximum number of threads to run when parallel processing is enabled (Default = 0)", "Value": 0, "Type": "Numeric" }, { "Name": "pEleMapping", - "Prompt": "REQUIRED: Map source elements to target elements using format Dim1ToCopy\u00a6SourceElement->TargetElement & Dim2ToCopy\u00a6Source Element->TargetElement etc", + "Prompt": "REQUIRED: Map source elements to target elements using format: dim_one\u00a6 el_one -> el_two & dim_two\u00a6 el_one -> el_two'", "Value": "", "Type": "String" }, { "Name": "pMappingDelim", - "Prompt": "OPTIONAL: Delimiter between source element and target element in pEleMapping (default value if blank = '->')", + "Prompt": "OPTIONAL: Delimiter between source element and target element in pEleMapping (Default = '->')", "Value": "->", "Type": "String" }, { "Name": "pDimDelim", - "Prompt": "OPTIONAL: Delimiter for start of Dimension/Element set (default value if blank = '&')", + "Prompt": "OPTIONAL: Delimiter for start of dimension/element set in filter parameters (Default = '&')", "Value": "&", "Type": "String" }, { "Name": "pEleStartDelim", - "Prompt": "OPTIONAL: Delimiter for start of element list (default value if blank = '\u00a6')", + "Prompt": "OPTIONAL: Delimiter for start of element list in filter parameters (Default = '\u00a6')", "Value": "\u00a6", "Type": "String" }, { "Name": "pEleDelim", - "Prompt": "OPTIONAL: Delimiter between elements (default value if blank = '+')", + "Prompt": "OPTIONAL: Delimiter between elements in filter parameters (Default = '+')", "Value": "+", "Type": "String" }, { "Name": "pFactor", - "Prompt": "OPTIONAL: Multiply source value by factor (1 keeps the value as is). To modify existing values make the target element the same as the source with pZeroTarget = 0", + "Prompt": "OPTIONAL: Multiply source values by factor (Default = 1)", "Value": 1, "Type": "Numeric" }, { "Name": "pSuppressConsol", - "Prompt": "OPTIONAL: Suppress Consolidated Cells (Skip = 1)", + "Prompt": "OPTIONAL: Suppress consolidated values (Boolean. Default = 1)", "Value": 1, "Type": "Numeric" }, { "Name": "pSuppressConsolStrings", - "Prompt": "OPTIONAL: Suppress Consolidated String Cells (Skip = 1)", - "Value": 0, + "Prompt": "OPTIONAL: Suppress consolidated string cells (Boolean. Default = 1)", + "Value": 1, "Type": "Numeric" }, { "Name": "pSuppressRules", - "Prompt": "OPTIONAL: Suppress Rules (Skip = 1)", + "Prompt": "OPTIONAL: Suppress rules (Boolean. Default = 1)", "Value": 1, "Type": "Numeric" }, { "Name": "pSuppressZero", - "Prompt": "OPTIONAL: Suppress Null Cells (Skip = 1)", + "Prompt": "OPTIONAL: Suppress zeroes (Boolean. Default = 1)", "Value": 1, "Type": "Numeric" }, { "Name": "pIncludeDescendants", - "Prompt": "OPTIONAL: Include all descendants when copying consolidated values", + "Prompt": "OPTIONAL: Include all descendants when source has consolidations (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { "Name": "pCumulate", - "Prompt": "OPTIONAL: 1 = Add source to existing value in target (if zero out target = 0 False). 0 = Replace target with source.", + "Prompt": "OPTIONAL: Accumulate amounts (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { "Name": "pZeroTarget", - "Prompt": "OPTIONAL: Zero out Target Element PRIOR to Copy? (Boolean 1=True)", + "Prompt": "OPTIONAL: Zero out target before start of process (Boolean. Default = 1)", "Value": 1, "Type": "Numeric" }, { "Name": "pZeroSource", - "Prompt": "OPTIONAL: Zero out Source Element AFTER Copy? (Boolean 1=True)", + "Prompt": "OPTIONAL: Zero out source after end of process (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { "Name": "pTemp", - "Prompt": "OPTIONAL: Delete temporary view and Subset ( 0 = Retain View and Subsets 1 = Delete View and Subsets 2 = Delete View only )", + "Prompt": "OPTIONAL: Delete/create temporary objects (0 = Do not delete, 1 = Delete, 2 = if view and subsets are created, keep only subsets)", "Value": 1, "Type": "Numeric" }, { "Name": "pSandbox", - "Prompt": "OPTIONAL: To use sandbox not base data enter the sandbox name (invalid name will result in process error)", + "Prompt": "OPTIONAL: Use sandbox", "Value": "", "Type": "String" }, @@ -165,50 +153,50 @@ }, { "Name": "pDelim", - "Prompt": "OPTIONAL: For pFile > 0. AsciiOutput delimiter character (Default = ',' exactly 3 digits = ASCII code)", - "Value": ",", + "Prompt": "OPTIONAL: Delimiter for list parameters (Default = '&')", + "Value": "&", "Type": "String" }, { "Name": "pQuote", - "Prompt": "OPTIONAL: For pFile > 0. AsciiOutput quote character (Default = '\"' exactly 3 digits = ASCII code)", + "Prompt": "OPTIONAL: Quote character (2 or 3 digits = ASCII code. Default = '\"')", "Value": "\"", "Type": "String" }, { "Name": "pDecimalSeparator", - "Prompt": "OPTIONAL: For pFile > 0. Decimal separator for conversion of NumberToStringEx and StringToNumberEx (default = '.' exactly 3 digits = ASCII code)", + "Prompt": "OPTIONAL: Decimal separator for string/number conversion (Exactly 3 digits = ASCII code. Default ='.')", "Value": ".", "Type": "String" }, { "Name": "pThousandSeparator", - "Prompt": "OPTIONAL: For pFile > 0. Thousand separator for conversion of NumberToStringEx and StringToNumberEx (default = ',' exactly 3 digits = ASCII code)", + "Prompt": "OPTIONAL: Thousand separator for string/number conversion (Exactly 3 digits = ASCII code. Default = ',')", "Value": ",", "Type": "String" }, { "Name": "pSubN", - "Prompt": "OPTIONAL: Create N level subset for all dims not mentioned in pFilter", + "Prompt": "OPTIONAL: Create N level subset for all dims not specified (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { - "Name": "pThreadMode", - "Prompt": "DO NOT USE: Internal parameter only, please do not use", - "Value": 0, + "Name": "pMaxWaitSeconds", + "Prompt": "OPTIONAL: Max wait time for threads before timing out (Default = 1800)", + "Value": 1800, "Type": "Numeric" }, { - "Name": "pThreadControlFile", - "Prompt": "DO NOT USE: Internal parameter only, please do not use", - "Value": "", - "Type": "String" + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" }, { - "Name": "pMaxWaitSeconds", - "Prompt": "OPTIONAL: Used with parallel to define wait time", - "Value": 1800, + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, "Type": "Numeric" }, { @@ -216,6 +204,24 @@ "Prompt": "OBSOLETE: This parameter does nothing and is only included for backwards compatability", "Value": 0, "Type": "Numeric" + }, + { + "Name": "pThreadMode", + "Prompt": "DO NOT USE: Internal parameter only, please do not use", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pThreadControlFile", + "Prompt": "DO NOT USE: Internal parameter only, please do not use", + "Value": "", + "Type": "String" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [ @@ -577,57 +583,5 @@ "EndByte": 0 } ], - "VariablesUIData": [ - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=33\fColType=827\f" - ] + "VariablesUIData": [] } \ No newline at end of file diff --git a/bedrock_processes_json/}bedrock.cube.data.export.json b/bedrock_processes_json/}bedrock.cube.data.export.json index 6fb3daf..54052b8 100644 --- a/bedrock_processes_json/}bedrock.cube.data.export.json +++ b/bedrock_processes_json/}bedrock.cube.data.export.json @@ -1,11 +1,11 @@ { "Name": "}bedrock.cube.data.export", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.cube.data.export', 'pLogoutput', pLogoutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pCube', '', 'pView', '', 'pFilter', '',\r\n \t'pFilterParallel', '', 'pParallelThreads', 0,\r\n \t'pDimDelim', '&', 'pEleStartDelim', '\u00a6', 'pEleDelim', '+',\r\n \t'pSuppressZero', 1, 'pSuppressConsol', 1, 'pSuppressRules', 1, 'pSuppressConsolStrings', 1, 'pIncludeDescendants',0,\r\n \t'pZeroSource', 0, 'pCubeLogging', 0, 'pTemp', 1,\r\n \t'pFilePath', '', 'pFileName', '',\r\n \t'pDelim', ',','pDecimalSeparator','.','pThousandSeparator',',',\r\n 'pQuote', '\"', 'pTitleRecord', 1, 'pSandbox', pSandbox, 'pSubN', pSubN, 'pCubeNameExport', pCubeNameExport\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n#################################################################################################\r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n#################################################################################################\r\n\r\n#Region @DOC\r\n# Description:\r\n# This TI is designed to export data in a given cube to a flat file for a given \"slice\" (any dimension/element combination).\r\n#\r\n# Use case: Intended for development/prototyping or in Production environment.\r\n# 1. Export data for import into another TM1 model to eliminate possibility of locking.\r\n# 2. Export data for import into ERP system.\r\n#\r\n# Note:\r\n# * Naturally, a valid cube name (pCube) is mandatory otherwise the process will abort.\r\n# * All other parameters are optional, however, the filter (pFilter) should be specified to limit the size of the file.\r\n# * The default output path is the same as the error file path.\r\n# * As this TI has a view as a data source it requires the implicit variables NValue, SValue and Value_is_String\r\n# * To edit this TI in Architect a tmp cube with minimum 24 dims is needed as the preview data source or set the data\r\n# source to ASCII and manually edit the TI in notepad after saving to add back the required implicit view variables\r\n# * If using the pFilterParallel parameter the **single dimension** used as the \"parallelization slicer\" cannot appear in\r\n# the pFilter parameter\r\n# * When using parallelization via the *RunProcess* function the elements listed in pFilterParallel will be split one_at_a_time\r\n# and passed to a recursive call of the process being added to pFilter. Each element name will also be appended to the filename\r\n#\r\n# Warning:\r\n# As the *RunProcess* function currently has no mechanism to check for the state of the called process if more processes are\r\n# released than available CPU cores on the server then this could lead to TM1 consuming all available server resources and a\r\n# associated performance issue. Be careful that the number of slicer elements listed in pFilterParallel should not exceed the\r\n# number of available cores.\r\n#EndRegion @DOC\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nStringGlobalVariable('sBedrockViewCreateParsedFilter');\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pCube:%pCube%, pView:%pView%, pFilter:%pFilter%, pFilterParallel:%pFilterParallel%, pParallelThreads:%pParallelThreads%, pDimDelim:%pDimDelim%, pEleStartDelim:%pEleStartDelim%, pEleDelim:%pEleDelim%, pSuppressZero:%pSuppressZero%, pSuppressConsol:%pSuppressConsol%, pSuppressRules:%pSuppressRules%, pZeroSource:%pZeroSource%, pCubeLogging:%pCubeLogging%, pTemp:%pTemp%, pFilePath:%pFilePath%, pFileName:%pFileName%, pDelim:%pDelim%, pQuote:%pQuote%, pTitleRecord:%pTitleRecord%, pSandbox:%pSandbox%, pSuppressConsolStrings:%pSuppressConsolStrings% pIncludeDescendants %pIncludeDescendants%.';\r\ncDefaultView = Expand( '%cThisProcName%_%cTimeStamp%_%cRandomInt%' );\r\ncLenASCIICode = 3;\r\n\r\npFieldDelim = TRIM(pDelim);\r\npDimDelim = TRIM(pDimDelim);\r\npEleStartDelim = TRIM(pEleStartDelim);\r\npEleDelim = TRIM(pEleDelim);\r\npDecimalSeparator = TRIM(pDecimalSeparator);\r\npThousandSeparator= TRIM(pThousandSeparator);\r\nnDataCount = 0;\r\nnErrors = 0;\r\n\r\n## Default filter delimiters\r\nIf( pDimDelim @= '' );\r\n pDimDelim = '&';\r\nEndIf;\r\nIf( pEleStartDelim@= '' );\r\n pEleStartDelim= '\u00a6';\r\nEndIf;\r\nIf( pEleDelim @= '' );\r\n pEleDelim = '+';\r\nEndIf;\r\nIf( pDecimalSeparator @= '' );\r\n \tpDecimalSeparator = '.';\r\nEndIf;\r\nIf( pThousandSeparator @= '' );\r\n \tpThousandSeparator = ',';\r\nEndIf;\r\nsDelimDim = pDimDelim;\r\nsElementStartDelim = pEleStartDelim;\r\nsDelimelem = pEleDelim;\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) );\r\nENDIF;\r\n\r\n### Validate Parameters ###\r\n\r\n# If no cube has been specified then terminate process\r\nIf( Trim( pCube ) @= '' );\r\n sMessage = 'No cube specified.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( CubeExists( pCube ) = 0 );\r\n sMessage = Expand( 'Cube: %pCube% does not exist.' );\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n## Validate the View parameter\r\nIf( TRIM(pView) @= '' );\r\n cView = cDefaultView ;\r\nElse ;\r\n cView = pView ;\r\nEndIf;\r\ncSubset = cView;\r\n\r\n## check operating system\r\nIf( SubSt( GetProcessErrorFileDirectory, 2, 1 ) @= ':' );\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nElseIf( Scan( '/', GetProcessErrorFileDirectory ) > 0 );\r\n sOS = 'Linux';\r\n sOSDelim = '/';\r\nElse;\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nEndIf;\r\n\r\n# Validate file path\r\nIf(Trim( pFilePath ) @= '' );\r\n pFilePath = GetProcessErrorFileDirectory;\r\nEndIf;\r\nIf( SubSt( pFilePath, Long( pFilePath ), 1 ) @= sOSDelim );\r\n pFilePath = SubSt( pFilePath, 1, Long( pFilePath ) -1 );\r\nEndIf;\r\nIf( FileExists( pFilePath ) = 0 );\r\n sMessage = Expand('Invalid export directory: %pFilePath%');\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\npFilePath = pFilePath | sOSDelim;\r\n\r\n# Validate file name\r\nIf( pFileName @= '' );\r\n sBaseFileName = Expand('%pCube%_Export');\r\n sExt = '.csv';\r\n pFileName = sBaseFileName | '.csv';\r\nElse;\r\n # determine file extension. If no file extension entered then use .csv as default\r\n If( Scan( '.', pFileName ) = 0 );\r\n sExt = '.csv';\r\n sBaseFileName = pFileName;\r\n Else;\r\n sExt = SubSt( pFileName, Scan( '.', pFileName ), Long( pFileName ) );\r\n sBaseFileName = SubSt( pFileName, 1, Scan( '.', pFileName ) - 1 );\r\n EndIf;\r\n pFileName = sBaseFileName | sExt;\r\nEndIf;\r\ncExportFile = pFilePath | pFileName;\r\n\r\n# Validate parallelization filter\r\nIf( Scan( pEleStartDelim, pFilterParallel ) > 0 );\r\n sDimParallel = SubSt( pFilterParallel, 1, Scan( pEleStartDelim, pFilterParallel ) - 1 );\r\n If( Scan( Lower(sDimParallel) | pEleStartDelim, Lower(pFilter) ) > 0 );\r\n sMessage = 'Parallelization dimension %sDimParallel% cannot exist in filter.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n EndIf;\r\nEndIf;\r\n\r\n# Validate Max Threads\r\nIf( pParallelThreads > 0 );\r\n nMaxThreads = pParallelThreads;\r\nElse;\r\n nMaxThreads = 1;\r\nEndIf;\r\n\r\n# Validate file delimiter & quote character\r\nIf( pFieldDelim @= '' );\r\n pFieldDelim = ',';\r\nElse;\r\n # If length of pFieldDelim is exactly 3 chars and each of them is decimal digit, then the pFieldDelim is entered as ASCII code\r\n nValid = 0;\r\n If ( LONG(pFieldDelim) = cLenASCIICode );\r\n nChar = 1;\r\n While ( nChar <= cLenASCIICode );\r\n If( CODE( pFieldDelim, nChar ) >= CODE( '0', 1 ) & CODE( pFieldDelim, nChar ) <= CODE( '9', 1 ) );\r\n nValid = 1;\r\n Else;\r\n nValid = 0;\r\n Break;\r\n EndIf;\r\n nChar = nChar + 1;\r\n End;\r\n EndIf;\r\n If ( nValid<>0 );\r\n pFieldDelim=CHAR(StringToNumber( pFieldDelim ));\r\n Else;\r\n pFieldDelim = SubSt( Trim( pFieldDelim ), 1, 1 );\r\n EndIf;\r\nEndIf;\r\n\r\nIf( pQuote @= '' );\r\n ## Use no quote character\r\nElse;\r\n # If length of pQuote is exactly 3 chars and each of them is decimal digit, then the pQuote is entered as ASCII code\r\n nValid = 0;\r\n If ( LONG(pQuote) = cLenASCIICode );\r\n nChar = 1;\r\n While ( nChar <= cLenASCIICode );\r\n If( CODE( pQuote, nChar ) >= CODE( '0', 1 ) & CODE( pQuote, nChar ) <= CODE( '9', 1 ) );\r\n nValid = 1;\r\n Else;\r\n nValid = 0;\r\n Break;\r\n EndIf;\r\n nChar = nChar + 1;\r\n End;\r\n EndIf;\r\n If ( nValid<>0 );\r\n pQuote=CHAR(StringToNumber( pQuote ));\r\n Else;\r\n pQuote = SubSt( Trim( pQuote ), 1, 1 );\r\n EndIf;\r\nEndIf;\r\n\r\nIf ( LONG(pDecimalSeparator) = cLenASCIICode );\r\n nValid = 0;\r\n nChar = 1;\r\n While ( nChar <= cLenASCIICode );\r\n If( CODE( pDecimalSeparator, nChar ) >= CODE( '0', 1 ) & CODE( pDecimalSeparator, nChar ) <= CODE( '9', 1 ) );\r\n nValid = 1;\r\n Else;\r\n nValid = 0;\r\n Break;\r\n EndIf;\r\n nChar = nChar + 1;\r\n End;\r\n If ( nValid<>0 );\r\n pDecimalSeparator = CHAR(StringToNumber( pDecimalSeparator ));\r\n Else;\r\n pDecimalSeparator = SubSt( Trim( pDecimalSeparator ), 1, 1 );\r\n EndIf;\r\nEndIf;\r\nsDecimalSeparator = pDecimalSeparator;\r\n\r\nIf ( LONG(pThousandSeparator) = cLenASCIICode );\r\n nValid = 0;\r\n nChar = 1;\r\n While ( nChar <= cLenASCIICode );\r\n If( CODE( pThousandSeparator, nChar ) >= CODE( '0', 1 ) & CODE( pThousandSeparator, nChar ) <= CODE( '9', 1 ) );\r\n nValid = 1;\r\n Else;\r\n nValid = 0;\r\n Break;\r\n EndIf;\r\n nChar = nChar + 1;\r\n End;\r\n If ( nValid<>0 );\r\n pThousandSeparator = CHAR(StringToNumber( pThousandSeparator ));\r\n Else;\r\n pThousandSeparator = SubSt( Trim( pThousandSeparator ), 1, 1 );\r\n EndIf;\r\nEndIf;\r\nsThousandSeparator = pThousandSeparator;\r\n\r\n# Validate Sandbox\r\nIf( TRIM( pSandbox ) @<> '' );\r\n If( ServerSandboxExists( pSandbox ) = 0 );\r\n SetUseActiveSandboxProperty( 0 );\r\n nErrors = nErrors + 1;\r\n sMessage = Expand('Sandbox %pSandbox% is invalid for the current user.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n Else;\r\n ServerActiveSandboxSet( pSandbox );\r\n SetUseActiveSandboxProperty( 1 );\r\n EndIf;\r\nElse;\r\n SetUseActiveSandboxProperty( 0 );\r\nEndIf;\r\n\r\n# Validate Character Set\r\nIf(Trim( pCharacterSet ) @= '' );\r\n pCharacterSet = 'TM1CS_UTF8';\r\nEndIf;\r\n\r\n# Jump to Epilog if any errors so far\r\nIF ( nErrors > 0 );\r\n DataSourceType = 'NULL';\r\n If( pStrictErrorHandling = 1 );\r\n ProcessQuit;\r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nENDIF;\r\n\r\n# Branch depending on whether to do recursive calls to self on independent threads or run all in this thread\r\nIf( Scan( pEleStartDelim, pFilterParallel ) > 0 );\r\n sDimParallel = SubSt( pFilterParallel, 1, Scan( pEleStartDelim, pFilterParallel ) - 1 );\r\n sElementList = SubSt( pFilterParallel, Scan( pEleStartDelim, pFilterParallel ) + 1, Long( pFilterParallel ) );\r\n If( SubSt( sElementList, Long( sElementList ), 1 ) @<> pEleDelim );\r\n sElementList = sElementList | pEleDelim;\r\n EndIf;\r\n ## Counting elements in element list\r\n sElementListCount = sElementList;\r\n nElements = 0;\r\n While( Scan( pEleDelim, sElementListCount ) > 0 );\r\n nElements = nElements + 1;\r\n sElementListCount = SubSt( sElementListCount, Scan( pEleDelim, sElementListCount ) + 1, Long( sElementListCount ) );\r\n End;\r\n IF( Mod( nElements, nMaxThreads ) = 0 );\r\n nElemsPerThread = INT( nElements \\ nMaxThreads );\r\n ELSE;\r\n nElemsPerThread = INT( nElements \\ nMaxThreads ) + 1;\r\n ENDIF;\r\n nThreadElCounter = 0;\r\n While( Scan( pEleDelim, sElementList ) > 0 );\r\n sSlicerEle = SubSt( sElementList, 1, Scan( pEleDelim, sElementList ) - 1 );\r\n sElementList = SubSt( sElementList, Scan( pEleDelim, sElementList ) + 1, Long( sElementList ) );\r\n # Do recursive process call with new RunProcess function\r\n nThreadElCounter = nThreadElCounter + 1;\r\n sDimDelim = If(pFilter @= '', '', pDimDelim );\r\n IF( nThreadElCounter = 1 );\r\n sFilter = Expand('%pFilter%%sDimDelim%%sDimParallel%%pEleStartDelim%%sSlicerEle%');\r\n sFileName = Expand('%sBaseFileName%_%sDimParallel%_%sSlicerEle%');\r\n ELSE;\r\n sFilter = Expand('%sFilter%%pEleDelim%%sSlicerEle%');\r\n sFileName = Expand('%sFileName%+%sSlicerEle%');\r\n ENDIF;\r\n IF( nThreadElCounter >= nElemsPerThread );\r\n sFileName = Expand('%sFileName%%sExt%');\r\n RunProcess( cThisProcName, 'pLogoutput', pLogoutput,\r\n \t'pCube', pCube, 'pView', '',\r\n \t'pFilter', sFilter, 'pFilterParallel', '',\r\n \t'pDimDelim', pDimDelim, 'pEleStartDelim', pEleStartDelim, 'pEleDelim', pEleDelim,\r\n \t'pSuppressZero', pSuppressZero, 'pSuppressConsol', pSuppressConsol, 'pSuppressRules', pSuppressRules,\r\n \t'pZeroSource', pZeroSource, 'pCubeLogging', pCubeLogging,\r\n \t'pTemp', pTemp, 'pFilePath', pFilePath, 'pFileName', sFileName,\r\n \t'pDelim', pFieldDelim, 'pDecimalSeparator', pDecimalSeparator, 'pThousandSeparator', pThousandSeparator,\r\n 'pQuote', pQuote, 'pTitleRecord', pTitleRecord, 'pSandbox', pSandbox, 'pSuppressConsolStrings', pSuppressConsolStrings, 'pCubeNameExport', pCubeNameExport\r\n );\r\n \t nThreadElCounter = 0;\r\n \t sFilter = '';\r\n \t sFileName = '';\r\n \t ENDIF;\r\n End;\r\n ## Process last elements - only when filter is not empty (there are still elements)\r\n IF( sFilter @<> '' );\r\n sFileName = Expand('%sFileName%%sExt%');\r\n RunProcess( cThisProcName, 'pLogoutput', pLogoutput,\r\n \t'pCube', pCube, 'pView', '',\r\n \t'pFilter', sFilter, 'pFilterParallel', '',\r\n \t'pDimDelim', pDimDelim, 'pEleStartDelim', pEleStartDelim, 'pEleDelim', pEleDelim,\r\n \t'pSuppressZero', pSuppressZero, 'pSuppressConsol', pSuppressConsol, 'pSuppressRules', pSuppressRules,\r\n \t'pZeroSource', pZeroSource, 'pCubeLogging', pCubeLogging,\r\n \t'pTemp', pTemp, 'pFilePath', pFilePath, 'pFileName', sFileName,\r\n \t'pDelim', pFieldDelim, 'pDecimalSeparator', pDecimalSeparator, 'pThousandSeparator', pThousandSeparator,\r\n 'pQuote', pQuote, 'pTitleRecord', pTitleRecord, 'pSandbox', pSandbox, 'pSuppressConsolStrings', pSuppressConsolStrings, 'pCubeNameExport', pCubeNameExport\r\n );\r\n ENDIF;\r\n DataSourceType = 'NULL';\r\n nParallelRun = 1;\r\nElse;\r\n # No parallelization is being used. Proceed as normal and do everything internally\r\n\r\n # Determine number of dims in source cube & create strings to expand on title and rows\r\n nCount = 1;\r\n nDimensionIndex = 0;\r\n\r\n ## Skip cube name from export\r\n IF (pCubeNameExport = 0);\r\n sTitle = '';\r\n sRow = '';\r\n\r\n While( TabDim( pCube, nCount ) @<> '' );\r\n sDimension = TabDim( pCube, nCount );\r\n\r\n ## Determine title string for the source cube\r\n sTitle = sTitle|'%pQuote%'|sDimension|'%pQuote%%pFieldDelim%';\r\n # Determine row string for the source cube\r\n sRow = sRow|'%pQuote%%V'| numbertostring(nCount) |'%%pQuote%%pFieldDelim%';\r\n\r\n nCount = nCount + 1;\r\n End;\r\n nDimensionCount = nCount - 1;\r\n\r\n # Finish off the strings\r\n sTitle = sTitle|'%pQuote%Value%pQuote%';\r\n sRow = sRow|'%pQuote%%sValue%%pQuote%';\r\n\r\n ELSE;\r\n sTitle = '%pQuote%Cube%pQuote%';\r\n sRow = '%pQuote%%pCube%%pQuote%';\r\n\r\n While( TabDim( pCube, nCount ) @<> '' );\r\n sDimension = TabDim( pCube, nCount );\r\n\r\n ## Determine title string for the source cube\r\n sTitle = sTitle|'%pFieldDelim%%pQuote%'|sDimension|'%pQuote%';\r\n # Determine row string for the source cube\r\n sRow = sRow|'%pFieldDelim%%pQuote%%V'| numbertostring(nCount) |'%%pQuote%';\r\n\r\n nCount = nCount + 1;\r\n End;\r\n nDimensionCount = nCount - 1;\r\n\r\n # Finish off the strings\r\n sTitle = sTitle|'%pFieldDelim%%pQuote%Value%pQuote%';\r\n sRow = sRow|'%pFieldDelim%%pQuote%%sValue%%pQuote%';\r\n ENDIF;\r\n\r\n # Create Processing View for source version\r\n nRet = ExecuteProcess('}bedrock.cube.view.create',\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pCube', pCube,\r\n 'pView', cView,\r\n 'pFilter', pFilter,\r\n 'pSuppressZero', pSuppressZero,\r\n 'pSuppressConsol', pSuppressConsol,\r\n 'pSuppressRules', pSuppressRules,\r\n 'pSuppressConsolStrings', pSuppressConsolStrings,\r\n 'pIncludeDescendants',pIncludeDescendants,\r\n 'pDimDelim', pDimDelim,\r\n 'pEleStartDelim', pEleStartDelim,\r\n 'pEleDelim', pEleDelim,\r\n 'pTemp', pTemp,\r\n 'pSubN', pSubN\r\n );\r\n\r\n # Validate Sandbox\r\n If( TRIM( pSandbox ) @<> '' );\r\n If( ServerSandboxExists( pSandbox ) = 0 );\r\n SetUseActiveSandboxProperty( 0 );\r\n nErrors = nErrors + 1;\r\n sMessage = Expand('Sandbox %pSandbox% is invalid for the current user.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n Else;\r\n ServerActiveSandboxSet( pSandbox );\r\n SetUseActiveSandboxProperty( 1 );\r\n EndIf;\r\n Else;\r\n SetUseActiveSandboxProperty( 0 );\r\n EndIf;\r\n\r\n\r\n IF( nRet <> ProcessExitNormal() );\r\n sMessage = 'Error creating the view from the filter.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 );\r\n ProcessQuit;\r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n ENDIF;\r\n\r\n sParsedFilter = sBedrockViewCreateParsedFilter;\r\n sFilterRow = '%pQuote%%pCube%%pQuote%%pFieldDelim%%pQuote%Filter%pQuote%%pFieldDelim%%pQuote%%sParsedFilter%%pQuote%%pFieldDelim%%pQuote%%pDimDelim%%pQuote%%pFieldDelim%%pQuote%%pEleStartDelim%%pQuote%%pFieldDelim%%pQuote%%pEleDelim%%pQuote%';\r\n\r\n # Assign Datasource\r\n DataSourceType = 'VIEW';\r\n DatasourceNameForServer = pCube;\r\n DatasourceNameForClient = pCube;\r\n DatasourceCubeView = cView;\r\n DatasourceAsciiDelimiter= pFieldDelim;\r\n DatasourceAsciiQuoteCharacter = '';\r\n nParallelRun = 0;\r\nEndIf;\r\n\r\n### End Prolog ###", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.cube.data.export', 'pLogoutput', pLogoutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pCube', '', 'pView', '', 'pFilter', '',\r\n \t'pFilterParallel', '', 'pParallelThreads', 0,\r\n \t'pDimDelim', '&', 'pEleStartDelim', '\u00a6', 'pEleDelim', '+',\r\n \t'pSuppressZero', 1, 'pSuppressConsol', 1, 'pSuppressRules', 1, 'pSuppressConsolStrings', 1, 'pIncludeDescendants',0,\r\n \t'pZeroSource', 0, 'pCubeLogging', 0, 'pTemp', 1,\r\n \t'pFilePath', '', 'pFileName', '',\r\n \t'pDelim', ',','pDecimalSeparator','.','pThousandSeparator',',',\r\n 'pQuote', '\"', 'pTitleRecord', 1, 'pSandbox', pSandbox, 'pSubN', pSubN, 'pCubeNameExport', pCubeNameExport\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n#################################################################################################\r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n#################################################################################################\r\n\r\n#Region @DOC\r\n# Description:\r\n# This TI is designed to export data in a given cube to a flat file for a given \"slice\" (any dimension/element combination).\r\n#\r\n# Use case: Intended for development/prototyping or in Production environment.\r\n# 1. Export data for import into another TM1 model to eliminate possibility of locking.\r\n# 2. Export data for import into ERP system.\r\n#\r\n# Note:\r\n# * Naturally, a valid cube name (pCube) is mandatory otherwise the process will abort.\r\n# * All other parameters are optional, however, the filter (pFilter) should be specified to limit the size of the file.\r\n# * The default output path is the same as the error file path.\r\n# * As this TI has a view as a data source it requires the implicit variables NValue, SValue and Value_is_String\r\n# * To edit this TI in Architect a tmp cube with minimum 24 dims is needed as the preview data source or set the data\r\n# source to ASCII and manually edit the TI in notepad after saving to add back the required implicit view variables\r\n# * If using the pFilterParallel parameter the **single dimension** used as the \"parallelization slicer\" cannot appear in\r\n# the pFilter parameter\r\n# * When using parallelization via the *RunProcess* function the elements listed in pFilterParallel will be split one_at_a_time\r\n# and passed to a recursive call of the process being added to pFilter. Each element name will also be appended to the filename\r\n#\r\n# Warning:\r\n# As the *RunProcess* function currently has no mechanism to check for the state of the called process if more processes are\r\n# released than available CPU cores on the server then this could lead to TM1 consuming all available server resources and a\r\n# associated performance issue. Be careful that the number of slicer elements listed in pFilterParallel should not exceed the\r\n# number of available cores.\r\n#EndRegion @DOC\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nStringGlobalVariable('sBedrockViewCreateParsedFilter');\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pCube:%pCube%, pView:%pView%, pFilter:%pFilter%, pFilterParallel:%pFilterParallel%, pParallelThreads:%pParallelThreads%, pDimDelim:%pDimDelim%, pEleStartDelim:%pEleStartDelim%, pEleDelim:%pEleDelim%, pSuppressZero:%pSuppressZero%, pSuppressConsol:%pSuppressConsol%, pSuppressRules:%pSuppressRules%, pZeroSource:%pZeroSource%, pCubeLogging:%pCubeLogging%, pTemp:%pTemp%, pFilePath:%pFilePath%, pFileName:%pFileName%, pDelim:%pDelim%, pQuote:%pQuote%, pTitleRecord:%pTitleRecord%, pSandbox:%pSandbox%, pSuppressConsolStrings:%pSuppressConsolStrings% pIncludeDescendants %pIncludeDescendants%.';\r\ncDefaultView = Expand( '%cThisProcName%_%cTimeStamp%_%cRandomInt%' );\r\ncLenASCIICode = 3;\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pCharacterSet\": \"TM1CS_UTF8\",\r\n \"pCube\": null,\r\n \"pDecimalSeparator\": \".\",\r\n \"pDelim\": \"&\",\r\n \"pDimDelim\": \"&\",\r\n \"pEleDelim\": \"+\",\r\n \"pEleStartDelim\": \"\u00a6\",\r\n \"pFileName\": \"\",\r\n \"pFilePath\": \"\",\r\n \"pFilter\": \"\",\r\n \"pFilterParallel\": \"\",\r\n \"pQuote\": \"\"\",\r\n \"pSandbox\": \"\",\r\n \"pThousandSeparator\": \",\",\r\n \"pView\": \"\",\r\n \"pCubeNameExport\": 1,\r\n \"pIncludeDescendants\": 0,\r\n \"pLogOutput\": 0,\r\n \"pParallelThreads\": 0,\r\n \"pStrictErrorHandling\": 0,\r\n \"pSubN\": 0,\r\n \"pSuppressConsol\": 1,\r\n \"pSuppressConsolStrings\": 1,\r\n \"pSuppressRules\": 1,\r\n \"pSuppressZero\": 1,\r\n \"pTemp\": 1,\r\n \"pTitleRecord\": 1,\r\n \"pZeroSource\": 0\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pCharacterSet\": '|StringToJson ( pCharacterSet )|',\r\n \"pCube\": '|StringToJson ( pCube )|',\r\n \"pDecimalSeparator\": '|StringToJson ( pDecimalSeparator )|',\r\n \"pDelim\": '|StringToJson ( pDelim )|',\r\n \"pDimDelim\": '|StringToJson ( pDimDelim )|',\r\n \"pEleDelim\": '|StringToJson ( pEleDelim )|',\r\n \"pEleStartDelim\": '|StringToJson ( pEleStartDelim )|',\r\n \"pFileName\": '|StringToJson ( pFileName )|',\r\n \"pFilePath\": '|StringToJson ( pFilePath )|',\r\n \"pFilter\": '|StringToJson ( pFilter )|',\r\n \"pFilterParallel\": '|StringToJson ( pFilterParallel )|',\r\n \"pQuote\": '|StringToJson ( pQuote )|',\r\n \"pSandbox\": '|StringToJson ( pSandbox )|',\r\n \"pThousandSeparator\": '|StringToJson ( pThousandSeparator )|',\r\n \"pView\": '|StringToJson ( pView )|',\r\n \"pCubeNameExport\": '|NumberToString( pCubeNameExport )|',\r\n \"pIncludeDescendants\": '|NumberToString( pIncludeDescendants )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pParallelThreads\": '|NumberToString( pParallelThreads )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|',\r\n \"pSubN\": '|NumberToString( pSubN )|',\r\n \"pSuppressConsol\": '|NumberToString( pSuppressConsol )|',\r\n \"pSuppressConsolStrings\": '|NumberToString( pSuppressConsolStrings )|',\r\n \"pSuppressRules\": '|NumberToString( pSuppressRules )|',\r\n \"pSuppressZero\": '|NumberToString( pSuppressZero )|',\r\n \"pTemp\": '|NumberToString( pTemp )|',\r\n \"pTitleRecord\": '|NumberToString( pTitleRecord )|',\r\n \"pZeroSource\": '|NumberToString( pZeroSource )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npCharacterSet = JsonToString( JsonGet( pJson, 'pCharacterSet' ) );\r\npCube = JsonToString( JsonGet( pJson, 'pCube' ) );\r\npDecimalSeparator = JsonToString( JsonGet( pJson, 'pDecimalSeparator' ) );\r\npDelim = JsonToString( JsonGet( pJson, 'pDelim' ) );\r\npDimDelim = JsonToString( JsonGet( pJson, 'pDimDelim' ) );\r\npEleDelim = JsonToString( JsonGet( pJson, 'pEleDelim' ) );\r\npEleStartDelim = JsonToString( JsonGet( pJson, 'pEleStartDelim' ) );\r\npFileName = JsonToString( JsonGet( pJson, 'pFileName' ) );\r\npFilePath = JsonToString( JsonGet( pJson, 'pFilePath' ) );\r\npFilter = JsonToString( JsonGet( pJson, 'pFilter' ) );\r\npFilterParallel = JsonToString( JsonGet( pJson, 'pFilterParallel' ) );\r\npQuote = JsonToString( JsonGet( pJson, 'pQuote' ) );\r\npSandbox = JsonToString( JsonGet( pJson, 'pSandbox' ) );\r\npThousandSeparator = JsonToString( JsonGet( pJson, 'pThousandSeparator' ) );\r\npView = JsonToString( JsonGet( pJson, 'pView' ) );\r\n# Numeric Parameters\r\npCubeNameExport = StringToNumber( JsonToString( JsonGet( pJson, 'pCubeNameExport' ) ) );\r\npIncludeDescendants = StringToNumber( JsonToString( JsonGet( pJson, 'pIncludeDescendants' ) ) );\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npParallelThreads = StringToNumber( JsonToString( JsonGet( pJson, 'pParallelThreads' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\npSubN = StringToNumber( JsonToString( JsonGet( pJson, 'pSubN' ) ) );\r\npSuppressConsol = StringToNumber( JsonToString( JsonGet( pJson, 'pSuppressConsol' ) ) );\r\npSuppressConsolStrings = StringToNumber( JsonToString( JsonGet( pJson, 'pSuppressConsolStrings' ) ) );\r\npSuppressRules = StringToNumber( JsonToString( JsonGet( pJson, 'pSuppressRules' ) ) );\r\npSuppressZero = StringToNumber( JsonToString( JsonGet( pJson, 'pSuppressZero' ) ) );\r\npTemp = StringToNumber( JsonToString( JsonGet( pJson, 'pTemp' ) ) );\r\npTitleRecord = StringToNumber( JsonToString( JsonGet( pJson, 'pTitleRecord' ) ) );\r\npZeroSource = StringToNumber( JsonToString( JsonGet( pJson, 'pZeroSource' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\npFieldDelim = TRIM(pDelim);\r\npDimDelim = TRIM(pDimDelim);\r\npEleStartDelim = TRIM(pEleStartDelim);\r\npEleDelim = TRIM(pEleDelim);\r\npDecimalSeparator = TRIM(pDecimalSeparator);\r\npThousandSeparator= TRIM(pThousandSeparator);\r\nnDataCount = 0;\r\nnErrors = 0;\r\n\r\n## Default filter delimiters\r\nIf( pDimDelim @= '' );\r\n pDimDelim = '&';\r\nEndIf;\r\nIf( pEleStartDelim@= '' );\r\n pEleStartDelim= '\u00a6';\r\nEndIf;\r\nIf( pEleDelim @= '' );\r\n pEleDelim = '+';\r\nEndIf;\r\nIf( pDecimalSeparator @= '' );\r\n \tpDecimalSeparator = '.';\r\nEndIf;\r\nIf( pThousandSeparator @= '' );\r\n \tpThousandSeparator = ',';\r\nEndIf;\r\nsDelimDim = pDimDelim;\r\nsElementStartDelim = pEleStartDelim;\r\nsDelimelem = pEleDelim;\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) );\r\nENDIF;\r\n\r\n### Validate Parameters ###\r\n\r\n# If no cube has been specified then terminate process\r\nIf( Trim( pCube ) @= '' );\r\n sMessage = 'No cube specified.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( CubeExists( pCube ) = 0 );\r\n sMessage = Expand( 'Cube: %pCube% does not exist.' );\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n## Validate the View parameter\r\nIf( TRIM(pView) @= '' );\r\n cView = cDefaultView ;\r\nElse ;\r\n cView = pView ;\r\nEndIf;\r\ncSubset = cView;\r\n\r\n## check operating system\r\nIf( SubSt( GetProcessErrorFileDirectory, 2, 1 ) @= ':' );\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nElseIf( Scan( '/', GetProcessErrorFileDirectory ) > 0 );\r\n sOS = 'Linux';\r\n sOSDelim = '/';\r\nElse;\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nEndIf;\r\n\r\n# Validate file path\r\nIf(Trim( pFilePath ) @= '' );\r\n pFilePath = GetProcessErrorFileDirectory;\r\nEndIf;\r\nIf( SubSt( pFilePath, Long( pFilePath ), 1 ) @= sOSDelim );\r\n pFilePath = SubSt( pFilePath, 1, Long( pFilePath ) -1 );\r\nEndIf;\r\nIf( FileExists( pFilePath ) = 0 );\r\n sMessage = Expand('Invalid export directory: %pFilePath%');\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\npFilePath = pFilePath | sOSDelim;\r\n\r\n# Validate file name\r\nIf( pFileName @= '' );\r\n sBaseFileName = Expand('%pCube%_Export');\r\n sExt = '.csv';\r\n pFileName = sBaseFileName | '.csv';\r\nElse;\r\n # determine file extension. If no file extension entered then use .csv as default\r\n If( Scan( '.', pFileName ) = 0 );\r\n sExt = '.csv';\r\n sBaseFileName = pFileName;\r\n Else;\r\n sExt = SubSt( pFileName, Scan( '.', pFileName ), Long( pFileName ) );\r\n sBaseFileName = SubSt( pFileName, 1, Scan( '.', pFileName ) - 1 );\r\n EndIf;\r\n pFileName = sBaseFileName | sExt;\r\nEndIf;\r\ncExportFile = pFilePath | pFileName;\r\n\r\n# Validate parallelization filter\r\nIf( Scan( pEleStartDelim, pFilterParallel ) > 0 );\r\n sDimParallel = SubSt( pFilterParallel, 1, Scan( pEleStartDelim, pFilterParallel ) - 1 );\r\n If( Scan( Lower(sDimParallel) | pEleStartDelim, Lower(pFilter) ) > 0 );\r\n sMessage = 'Parallelization dimension %sDimParallel% cannot exist in filter.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n EndIf;\r\nEndIf;\r\n\r\n# Validate Max Threads\r\nIf( pParallelThreads > 0 );\r\n nMaxThreads = pParallelThreads;\r\nElse;\r\n nMaxThreads = 1;\r\nEndIf;\r\n\r\n# Validate file delimiter & quote character\r\nIf( pFieldDelim @= '' );\r\n pFieldDelim = ',';\r\nElse;\r\n # If length of pFieldDelim is exactly 3 chars and each of them is decimal digit, then the pFieldDelim is entered as ASCII code\r\n nValid = 0;\r\n If ( LONG(pFieldDelim) = cLenASCIICode );\r\n nChar = 1;\r\n While ( nChar <= cLenASCIICode );\r\n If( CODE( pFieldDelim, nChar ) >= CODE( '0', 1 ) & CODE( pFieldDelim, nChar ) <= CODE( '9', 1 ) );\r\n nValid = 1;\r\n Else;\r\n nValid = 0;\r\n Break;\r\n EndIf;\r\n nChar = nChar + 1;\r\n End;\r\n EndIf;\r\n If ( nValid<>0 );\r\n pFieldDelim=CHAR(StringToNumber( pFieldDelim ));\r\n Else;\r\n pFieldDelim = SubSt( Trim( pFieldDelim ), 1, 1 );\r\n EndIf;\r\nEndIf;\r\n\r\nIf( pQuote @= '' );\r\n ## Use no quote character\r\nElse;\r\n # If length of pQuote is exactly 3 chars and each of them is decimal digit, then the pQuote is entered as ASCII code\r\n nValid = 0;\r\n If ( LONG(pQuote) = cLenASCIICode );\r\n nChar = 1;\r\n While ( nChar <= cLenASCIICode );\r\n If( CODE( pQuote, nChar ) >= CODE( '0', 1 ) & CODE( pQuote, nChar ) <= CODE( '9', 1 ) );\r\n nValid = 1;\r\n Else;\r\n nValid = 0;\r\n Break;\r\n EndIf;\r\n nChar = nChar + 1;\r\n End;\r\n EndIf;\r\n If ( nValid<>0 );\r\n pQuote=CHAR(StringToNumber( pQuote ));\r\n Else;\r\n pQuote = SubSt( Trim( pQuote ), 1, 1 );\r\n EndIf;\r\nEndIf;\r\n\r\nIf ( LONG(pDecimalSeparator) = cLenASCIICode );\r\n nValid = 0;\r\n nChar = 1;\r\n While ( nChar <= cLenASCIICode );\r\n If( CODE( pDecimalSeparator, nChar ) >= CODE( '0', 1 ) & CODE( pDecimalSeparator, nChar ) <= CODE( '9', 1 ) );\r\n nValid = 1;\r\n Else;\r\n nValid = 0;\r\n Break;\r\n EndIf;\r\n nChar = nChar + 1;\r\n End;\r\n If ( nValid<>0 );\r\n pDecimalSeparator = CHAR(StringToNumber( pDecimalSeparator ));\r\n Else;\r\n pDecimalSeparator = SubSt( Trim( pDecimalSeparator ), 1, 1 );\r\n EndIf;\r\nEndIf;\r\nsDecimalSeparator = pDecimalSeparator;\r\n\r\nIf ( LONG(pThousandSeparator) = cLenASCIICode );\r\n nValid = 0;\r\n nChar = 1;\r\n While ( nChar <= cLenASCIICode );\r\n If( CODE( pThousandSeparator, nChar ) >= CODE( '0', 1 ) & CODE( pThousandSeparator, nChar ) <= CODE( '9', 1 ) );\r\n nValid = 1;\r\n Else;\r\n nValid = 0;\r\n Break;\r\n EndIf;\r\n nChar = nChar + 1;\r\n End;\r\n If ( nValid<>0 );\r\n pThousandSeparator = CHAR(StringToNumber( pThousandSeparator ));\r\n Else;\r\n pThousandSeparator = SubSt( Trim( pThousandSeparator ), 1, 1 );\r\n EndIf;\r\nEndIf;\r\nsThousandSeparator = pThousandSeparator;\r\n\r\n# Validate Sandbox\r\nIf( TRIM( pSandbox ) @<> '' );\r\n If( ServerSandboxExists( pSandbox ) = 0 );\r\n SetUseActiveSandboxProperty( 0 );\r\n nErrors = nErrors + 1;\r\n sMessage = Expand('Sandbox %pSandbox% is invalid for the current user.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n Else;\r\n ServerActiveSandboxSet( pSandbox );\r\n SetUseActiveSandboxProperty( 1 );\r\n EndIf;\r\nElse;\r\n SetUseActiveSandboxProperty( 0 );\r\nEndIf;\r\n\r\n# Validate Character Set\r\nIf(Trim( pCharacterSet ) @= '' );\r\n pCharacterSet = 'TM1CS_UTF8';\r\nEndIf;\r\n\r\n# Jump to Epilog if any errors so far\r\nIF ( nErrors > 0 );\r\n DataSourceType = 'NULL';\r\n If( pStrictErrorHandling = 1 );\r\n ProcessQuit;\r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nENDIF;\r\n\r\n# Branch depending on whether to do recursive calls to self on independent threads or run all in this thread\r\nIf( Scan( pEleStartDelim, pFilterParallel ) > 0 );\r\n sDimParallel = SubSt( pFilterParallel, 1, Scan( pEleStartDelim, pFilterParallel ) - 1 );\r\n sElementList = SubSt( pFilterParallel, Scan( pEleStartDelim, pFilterParallel ) + 1, Long( pFilterParallel ) );\r\n If( SubSt( sElementList, Long( sElementList ), 1 ) @<> pEleDelim );\r\n sElementList = sElementList | pEleDelim;\r\n EndIf;\r\n ## Counting elements in element list\r\n sElementListCount = sElementList;\r\n nElements = 0;\r\n While( Scan( pEleDelim, sElementListCount ) > 0 );\r\n nElements = nElements + 1;\r\n sElementListCount = SubSt( sElementListCount, Scan( pEleDelim, sElementListCount ) + 1, Long( sElementListCount ) );\r\n End;\r\n IF( Mod( nElements, nMaxThreads ) = 0 );\r\n nElemsPerThread = INT( nElements \\ nMaxThreads );\r\n ELSE;\r\n nElemsPerThread = INT( nElements \\ nMaxThreads ) + 1;\r\n ENDIF;\r\n nThreadElCounter = 0;\r\n While( Scan( pEleDelim, sElementList ) > 0 );\r\n sSlicerEle = SubSt( sElementList, 1, Scan( pEleDelim, sElementList ) - 1 );\r\n sElementList = SubSt( sElementList, Scan( pEleDelim, sElementList ) + 1, Long( sElementList ) );\r\n # Do recursive process call with new RunProcess function\r\n nThreadElCounter = nThreadElCounter + 1;\r\n sDimDelim = If(pFilter @= '', '', pDimDelim );\r\n IF( nThreadElCounter = 1 );\r\n sFilter = Expand('%pFilter%%sDimDelim%%sDimParallel%%pEleStartDelim%%sSlicerEle%');\r\n sFileName = Expand('%sBaseFileName%_%sDimParallel%_%sSlicerEle%');\r\n ELSE;\r\n sFilter = Expand('%sFilter%%pEleDelim%%sSlicerEle%');\r\n sFileName = Expand('%sFileName%+%sSlicerEle%');\r\n ENDIF;\r\n IF( nThreadElCounter >= nElemsPerThread );\r\n sFileName = Expand('%sFileName%%sExt%');\r\n RunProcess( cThisProcName, 'pLogoutput', pLogoutput,\r\n \t'pCube', pCube, 'pView', '',\r\n \t'pFilter', sFilter, 'pFilterParallel', '',\r\n \t'pDimDelim', pDimDelim, 'pEleStartDelim', pEleStartDelim, 'pEleDelim', pEleDelim,\r\n \t'pSuppressZero', pSuppressZero, 'pSuppressConsol', pSuppressConsol, 'pSuppressRules', pSuppressRules,\r\n \t'pZeroSource', pZeroSource, 'pCubeLogging', pCubeLogging,\r\n \t'pTemp', pTemp, 'pFilePath', pFilePath, 'pFileName', sFileName,\r\n \t'pDelim', pFieldDelim, 'pDecimalSeparator', pDecimalSeparator, 'pThousandSeparator', pThousandSeparator,\r\n 'pQuote', pQuote, 'pTitleRecord', pTitleRecord, 'pSandbox', pSandbox, 'pSuppressConsolStrings', pSuppressConsolStrings, 'pCubeNameExport', pCubeNameExport\r\n );\r\n \t nThreadElCounter = 0;\r\n \t sFilter = '';\r\n \t sFileName = '';\r\n \t ENDIF;\r\n End;\r\n ## Process last elements - only when filter is not empty (there are still elements)\r\n IF( sFilter @<> '' );\r\n sFileName = Expand('%sFileName%%sExt%');\r\n RunProcess( cThisProcName, 'pLogoutput', pLogoutput,\r\n \t'pCube', pCube, 'pView', '',\r\n \t'pFilter', sFilter, 'pFilterParallel', '',\r\n \t'pDimDelim', pDimDelim, 'pEleStartDelim', pEleStartDelim, 'pEleDelim', pEleDelim,\r\n \t'pSuppressZero', pSuppressZero, 'pSuppressConsol', pSuppressConsol, 'pSuppressRules', pSuppressRules,\r\n \t'pZeroSource', pZeroSource, 'pCubeLogging', pCubeLogging,\r\n \t'pTemp', pTemp, 'pFilePath', pFilePath, 'pFileName', sFileName,\r\n \t'pDelim', pFieldDelim, 'pDecimalSeparator', pDecimalSeparator, 'pThousandSeparator', pThousandSeparator,\r\n 'pQuote', pQuote, 'pTitleRecord', pTitleRecord, 'pSandbox', pSandbox, 'pSuppressConsolStrings', pSuppressConsolStrings, 'pCubeNameExport', pCubeNameExport\r\n );\r\n ENDIF;\r\n DataSourceType = 'NULL';\r\n nParallelRun = 1;\r\nElse;\r\n # No parallelization is being used. Proceed as normal and do everything internally\r\n\r\n # Determine number of dims in source cube & create strings to expand on title and rows\r\n nCount = 1;\r\n nDimensionIndex = 0;\r\n\r\n ## Skip cube name from export\r\n IF (pCubeNameExport = 0);\r\n sTitle = '';\r\n sRow = '';\r\n\r\n While( TabDim( pCube, nCount ) @<> '' );\r\n sDimension = TabDim( pCube, nCount );\r\n\r\n ## Determine title string for the source cube\r\n sTitle = sTitle|'%pQuote%'|sDimension|'%pQuote%%pFieldDelim%';\r\n # Determine row string for the source cube\r\n sRow = sRow|'%pQuote%%V'| numbertostring(nCount) |'%%pQuote%%pFieldDelim%';\r\n\r\n nCount = nCount + 1;\r\n End;\r\n nDimensionCount = nCount - 1;\r\n\r\n # Finish off the strings\r\n sTitle = sTitle|'%pQuote%Value%pQuote%';\r\n sRow = sRow|'%pQuote%%sValue%%pQuote%';\r\n\r\n ELSE;\r\n sTitle = '%pQuote%Cube%pQuote%';\r\n sRow = '%pQuote%%pCube%%pQuote%';\r\n\r\n While( TabDim( pCube, nCount ) @<> '' );\r\n sDimension = TabDim( pCube, nCount );\r\n\r\n ## Determine title string for the source cube\r\n sTitle = sTitle|'%pFieldDelim%%pQuote%'|sDimension|'%pQuote%';\r\n # Determine row string for the source cube\r\n sRow = sRow|'%pFieldDelim%%pQuote%%V'| numbertostring(nCount) |'%%pQuote%';\r\n\r\n nCount = nCount + 1;\r\n End;\r\n nDimensionCount = nCount - 1;\r\n\r\n # Finish off the strings\r\n sTitle = sTitle|'%pFieldDelim%%pQuote%Value%pQuote%';\r\n sRow = sRow|'%pFieldDelim%%pQuote%%sValue%%pQuote%';\r\n ENDIF;\r\n\r\n # Create Processing View for source version\r\n nRet = ExecuteProcess('}bedrock.cube.view.create',\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pCube', pCube,\r\n 'pView', cView,\r\n 'pFilter', pFilter,\r\n 'pSuppressZero', pSuppressZero,\r\n 'pSuppressConsol', pSuppressConsol,\r\n 'pSuppressRules', pSuppressRules,\r\n 'pSuppressConsolStrings', pSuppressConsolStrings,\r\n 'pIncludeDescendants',pIncludeDescendants,\r\n 'pDimDelim', pDimDelim,\r\n 'pEleStartDelim', pEleStartDelim,\r\n 'pEleDelim', pEleDelim,\r\n 'pTemp', pTemp,\r\n 'pSubN', pSubN\r\n );\r\n\r\n # Validate Sandbox\r\n If( TRIM( pSandbox ) @<> '' );\r\n If( ServerSandboxExists( pSandbox ) = 0 );\r\n SetUseActiveSandboxProperty( 0 );\r\n nErrors = nErrors + 1;\r\n sMessage = Expand('Sandbox %pSandbox% is invalid for the current user.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n Else;\r\n ServerActiveSandboxSet( pSandbox );\r\n SetUseActiveSandboxProperty( 1 );\r\n EndIf;\r\n Else;\r\n SetUseActiveSandboxProperty( 0 );\r\n EndIf;\r\n\r\n\r\n IF( nRet <> ProcessExitNormal() );\r\n sMessage = 'Error creating the view from the filter.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 );\r\n ProcessQuit;\r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n ENDIF;\r\n\r\n sParsedFilter = sBedrockViewCreateParsedFilter;\r\n sFilterRow = '%pQuote%%pCube%%pQuote%%pFieldDelim%%pQuote%Filter%pQuote%%pFieldDelim%%pQuote%%sParsedFilter%%pQuote%%pFieldDelim%%pQuote%%pDimDelim%%pQuote%%pFieldDelim%%pQuote%%pEleStartDelim%%pQuote%%pFieldDelim%%pQuote%%pEleDelim%%pQuote%';\r\n\r\n # Assign Datasource\r\n DataSourceType = 'VIEW';\r\n DatasourceNameForServer = pCube;\r\n DatasourceNameForClient = pCube;\r\n DatasourceCubeView = cView;\r\n DatasourceAsciiDelimiter= pFieldDelim;\r\n DatasourceAsciiQuoteCharacter = '';\r\n nParallelRun = 0;\r\nEndIf;\r\n\r\n### End Prolog ###", "MetadataProcedure": "#****Begin: Generated Statements***\r\n#****End: Generated Statements****", "DataProcedure": "#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n#################################################################################################\r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n#################################################################################################\r\n\r\n# Set the output character set\r\nSetOutputCharacterSet( cExportFile, pCharacterSet );\r\n\r\n### Data Count ###\r\nnDataCount = nDataCount + 1;\r\n\r\n# Output the title string\r\nIF( nDataCount = 1 & pTitleRecord >= 1 );\r\n TextOutput( cExportFile, Expand(sTitle) );\r\nEndif;\r\n\r\n### Export filter into the 1st record of the file, it will be used from import process to zero out the corresponding slice, if specified\r\nIF( nDataCount = 1 & pTitleRecord = 2 );\r\n TextOutput( cExportFile, Expand(sFilterRow) );\r\nEndif;\r\n\r\n### Export data from source version to file ###\r\nIf( value_is_string = 0 );\r\n sValue = NumberToStringEx( nValue, '#,0.#############', sDecimalSeparator, sThousandSeparator );\r\nEndIf;\r\n\r\n# Selects the correct TextOutput formula depending upon the number of dimensions in the cube\r\nIF(SCAN( CHAR( 10 ), sValue ) > 0 );\r\n sValueCleaned = '';\r\n nNoChar = 1;\r\n nLimit = LONG( sValue );\r\n WHILE( nNoChar <= nLimit ) ;\r\n sChar = SUBST( sValue, nNoChar, 1 );\r\n IF( CODE( sChar, 1 ) <> 10 );\r\n sValueCleaned = sValueCleaned | sChar ;\r\n ELSE;\r\n sValueCleaned = sValueCleaned | ' ';\r\n ENDIF;\r\n nNoChar = nNoChar + 1;\r\n END;\r\n sValue = sValueCleaned;\r\nENDIF;\r\n\r\n# Output data\r\nTextOutput( cExportFile, Expand(sRow) );\r\n\r\n### End Data ###", "EpilogProcedure": "#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n#################################################################################################\r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n#################################################################################################\r\n\r\n### Delete source data ###\r\nIf( pZeroSource = 1 & nErrors = 0 & nParallelRun = 0 );\r\n ViewZeroOut( pCube, cView );\r\nEndIf;\r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 );\r\n ProcessQuit;\r\n EndIf;\r\nElse;\r\n sDataCount = NUMBERTOSTRING (nDataCount);\r\n sProcessAction = Expand( 'Process:%cThisProcName% exported %sDataCount% records from %pCube% based on filter %pFilter%.' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) );\r\n EndIf;\r\n\r\nEndIf ;\r\n\r\n### End Epilog ###", "HasSecurityAccess": true, - "UIData": "_ParameterConstraints=e30=\f", + "UIData": "", "DataSource": { "Type": "TM1CubeView", "dataSourceNameForClient": "}APQ Staging TempSource", @@ -13,18 +13,6 @@ "view": "}TI_Dummy_View" }, "Parameters": [ - { - "Name": "pLogoutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pCube", "Prompt": "REQUIRED: Cube name", @@ -39,153 +27,171 @@ }, { "Name": "pFilter", - "Prompt": "OPTIONAL: Filter: Year\u00a6 2006 + 2007 & Scenario\u00a6 Actual + Budget & Organization\u00a6 North America Operations (Blank=whole cube)", + "Prompt": "OPTIONAL: Filter on cube in format: 'dim_one\u00a6 el_one + el_two & dim_two\u00a6 el_one + el_two'", "Value": "", "Type": "String" }, { "Name": "pFilterParallel", - "Prompt": "OPTIONAL: Parallelization Filter: Month:Q1+Q2+Q3+Q4 (Blank=run single threaded). Single dimension parallel slices. Will be added to filter single element at a time. Dimension must not be part of filter", + "Prompt": "OPTIONAL: Parallelization filter in format: dim_one\u00a6 el_one + el_two. Dimension must not be part of filter", "Value": "", "Type": "String" }, { "Name": "pParallelThreads", - "Prompt": "OPTIONAL: Maximum number of threads to run when parallel processing is enabled ( if <2 will execute one thread, but parallel filter is still applied )", + "Prompt": "OPTIONAL: Maximum number of threads to run when parallel processing is enabled (Default = 0)", "Value": 0, "Type": "Numeric" }, { "Name": "pDimDelim", - "Prompt": "OPTIONAL: Delimiter between dimensions (default value if blank = '&')", + "Prompt": "OPTIONAL: Delimiter for start of dimension/element set in filter parameters (Default = '&')", "Value": "&", "Type": "String" }, { "Name": "pEleStartDelim", - "Prompt": "OPTIONAL: Delimiter for start of element list (default value if blank = '\u00a6')", + "Prompt": "OPTIONAL: Delimiter for start of element list in filter parameters (Default = '\u00a6')", "Value": "\u00a6", "Type": "String" }, { "Name": "pEleDelim", - "Prompt": "OPTIONAL: Delimiter between elements (default value if blank = '+')", + "Prompt": "OPTIONAL: Delimiter between elements in filter parameters (Default = '+')", "Value": "+", "Type": "String" }, { "Name": "pSuppressZero", - "Prompt": "OPTIONAL: Suppress Zero Values (1=Suppress)", + "Prompt": "OPTIONAL: Suppress zeroes (Boolean. Default = 1)", "Value": 1, "Type": "Numeric" }, { "Name": "pSuppressConsol", - "Prompt": "OPTIONAL: Suppress Consolidated Values? (1=Suppress)", + "Prompt": "OPTIONAL: Suppress consolidated values (Boolean. Default = 1)", "Value": 1, "Type": "Numeric" }, { "Name": "pSuppressRules", - "Prompt": "OPTIONAL: Suppress Rule Values? (1=Suppress)", + "Prompt": "OPTIONAL: Suppress rules (Boolean. Default = 1)", "Value": 1, "Type": "Numeric" }, { "Name": "pSuppressConsolStrings", - "Prompt": "OPTIONAL: Suppress Strings on Consolidations (Skip = 1) (Default = 0)", - "Value": 0, + "Prompt": "OPTIONAL: Suppress consolidated string cells (Boolean. Default = 1)", + "Value": 1, "Type": "Numeric" }, { "Name": "pIncludeDescendants", - "Prompt": "", + "Prompt": "OPTIONAL: Include all descendants when source has consolidations (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { "Name": "pZeroSource", - "Prompt": "OPTIONAL: Zero Out view AFTER Copy? (Boolean 1=True)", + "Prompt": "OPTIONAL: Zero out source after end of process (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { "Name": "pTemp", - "Prompt": "OPTIONAL: Retain temporary view and Subset ( 0 = retain View and Subsets 1 = use temp objects)", + "Prompt": "OPTIONAL: Delete/create temporary objects (0 = Do not delete, 1 = Delete, 2 = if view and subsets are created, keep only subsets)", "Value": 1, "Type": "Numeric" }, { "Name": "pFilePath", - "Prompt": "OPTIONAL: Export Directory (will default to error file path)", + "Prompt": "OPTIONAL: File directory (Default = GetProcessErrorFileDirectory)", "Value": "", "Type": "String" }, { "Name": "pFileName", - "Prompt": "OPTIONAL: Export Filename (If Left Blank Defaults to cube_export.csv)", + "Prompt": "OPTIONAL: File name (Default = pCube | '_Export.csv')", "Value": "", "Type": "String" }, { "Name": "pDelim", - "Prompt": "OPTIONAL: AsciiOutput delimiter character (Default = ',' exactly 3 digits = ASCII code)", - "Value": ",", + "Prompt": "OPTIONAL: Delimiter for list parameters (Default = '&')", + "Value": "&", "Type": "String" }, { "Name": "pDecimalSeparator", - "Prompt": "OPTIONAL: Decimal separator for conversion of number to string and string to number (default = '.' exactly 3 digits = ASCII code)", + "Prompt": "OPTIONAL: Decimal separator for string/number conversion (Exactly 3 digits = ASCII code. Default ='.')", "Value": ".", "Type": "String" }, { "Name": "pThousandSeparator", - "Prompt": "OPTIONAL: Thousand separator for conversion of number to string and string to number (default = ',' exactly 3 digits = ASCII code)", + "Prompt": "OPTIONAL: Thousand separator for string/number conversion (Exactly 3 digits = ASCII code. Default = ',')", "Value": ",", "Type": "String" }, { "Name": "pQuote", - "Prompt": "OPTIONAL: AsciiOutput quote character (Accepts empty quote, exactly 3 digits = ASCII code)", + "Prompt": "OPTIONAL: Quote character (2 or 3 digits = ASCII code. Default = '\"')", "Value": "\"", "Type": "String" }, { "Name": "pTitleRecord", - "Prompt": "OPTIONAL: Include Title Record in Export File? (Boolean 0=false, 1=true, 2=title and filter line Default=1)", + "Prompt": "OPTIONAL: Delete temporary view and subsets (0 = Retain View and Subsets, 1 = Delete View and Subsets, 2 = Delete View only. Default = 1)", "Value": 1, "Type": "Numeric" }, { "Name": "pSandbox", - "Prompt": "OPTIONAL: To use sandbox not base data enter the sandbox name (invalid name will result in process error)", + "Prompt": "OPTIONAL: Use sandbox", "Value": "", "Type": "String" }, { "Name": "pSubN", - "Prompt": "OPTIONAL: Create N level subset for all dims not mentioned in pFilter (default=0)", + "Prompt": "OPTIONAL: Create N level subset for all dims not specified (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { "Name": "pCharacterSet", - "Prompt": "OPTIONAL: The output character set (defaults to TM1CS_UTF8 if blank)", - "Value": "", + "Prompt": "OPTIONAL: The output character set (Default = 'TM1CS_UTF8')", + "Value": "TM1CS_UTF8", "Type": "String" }, { "Name": "pCubeNameExport", - "Prompt": "OPTIONAL: Skip cube name from export file, including header (Skip = 0) (Default = 1)", + "Prompt": "OPTIONAL: Export cube name and header to export file (Boolean. Default = 1)", "Value": 1, "Type": "Numeric" }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, { "Name": "pCubeLogging", "Prompt": "OBSOLETE: This parameter does nothing and is only included for backwards compatability", "Value": 0, "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [ diff --git a/bedrock_processes_json/}bedrock.cube.data.hold.json b/bedrock_processes_json/}bedrock.cube.data.hold.json index cd319a6..82d3249 100644 --- a/bedrock_processes_json/}bedrock.cube.data.hold.json +++ b/bedrock_processes_json/}bedrock.cube.data.hold.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.cube.data.hold", - "PrologProcedure": "#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.cube.data.hold', 'pLogOutput', pLogOutput, 'pStrictErrorHandling', pStrictErrorHandling, \r\n 'pMode', 'C / D / R / X / M', 'pCube', '', 'pClient', '', 'pGroup', '', 'pDelim', '&', 'pDir', '', 'pSkipNonExistentHoldsCubes', 1 );\r\nEndIf;\r\n\r\n#################################################################################################\r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n#################################################################################################\r\n\r\n# Description:\r\n# This TI process can manage TM1 cube holds. Holds are a personal tool for a TM1 user in any TM1 client.\r\n# A hold by client A does not restrict data entry by client B.\r\n# A client needs write access to a cell in order to apply a hold to the cell.\r\n# Existing Bedrock processes are leveraged including their default parameter values.\r\n#\r\n# Use case: Intended for development/prototyping or in Production environment.\r\n# - When a user has applied holds and logs off (or is forced to log off), the holds are lost (even though the Holds cube still exists)\r\n# - When the TM1 model is restarted, all holds are lost (even though the Holds cube still exists)\r\n# - The customer could provide a set of holds to be applied, in several cubes and to several clients and even data entry groups of clients. Applying the holds manually would be tedious.\r\n# - A regular clean up of Holds cubes that are out of date could be wise\r\n#\r\n# Parameters:\r\n# - pLogOutput (standard Bedrock parameter, Boolean True = 1)\r\n# - pStrictErrorHandling (standard Bedrock parameter, Boolean True = 1)\r\n# - pMode (see below). It should be one of: C / D / R / X / M\r\n# - pCube (mandatory). Provide the base cuube name(s), not the Holds cube names! It could be a combination of:\r\n# * multiple cubes separated with pDelim\r\n# * wildcards * and ?\r\n# * the keyword MODELCUBES (the cubes excluding the control cubes)\r\n# - pClient (mandatory or used in conjunction with pGroup). It could be a combination of:\r\n# * multiple clients separated with pDelim\r\n# * wildcards * and ?\r\n# * the keyword MYSELF (the client running this TI process)\r\n# - pGroup (mandatory or used in conjunction with pClient). It could be a combination of:\r\n# * multiple clients separated with pDelim\r\n# * wildcards * and ?\r\n# * the keyword MYGROUPS (the groups that the client running this TI process is a member of)\r\n# - pDelim (standard Bedrock parameter to manage above lists, default value if blank = '&')\r\n# - pDir (only used when exporting or importing flat files. If empty, the error file directory is used. If not existing, an error is returned.)\r\n# - pSkipNonExistentHoldsCubes (not used for mode C) (When using lists and wildcards, it can lead to non-existent holds cubes. Use 1 to skip silently.\r\n#\r\n# Supported functionality related to holds, given the selections made:\r\n# - pMode = C: creation of a holds cube\r\n# - pMode = D: destruction of a holds cube\r\n# - pMode = R: release all holds\r\n# - pMode = X: export of holds to text files\r\n# - pMode = M: import of holds from text files (either new holds to be set, either holds exported earlier)\r\n#\r\n# Note:\r\n# - When exporting holds, the file format will respect the default values of the Bedrock process to export data. The file name is '}Hold_[ClientName]_}}_[CubeName].csv so it matches the Holds cubename.\r\n# - To import holds, the file format needs to respect the default values of the Bedrock process to import data. The file name is '}Hold_[ClientName]_}}_[CubeName].csv so it matches the Holds cubename.\r\n# - When importing holds, the cell value needs to be either H or C\r\n# * A value of C is to be put in a consolidated cell of the Holds cube\r\n# * A value of H is to be put in a level 0 cell of the Holds cube\r\n# * Any other combination will not lead to an error but TM1 will not apply the hold as intended\r\n# * String cells should not be used in data holds\r\n# - When importing holds, an additional zeroout should be done with a call to this process with mode 'R'\r\n# - The selections for pClient and pGroup will lead to a list of unique clients, to which the selected mode is applied\r\n# For a group, the members in the group are retrieved, and added to the selected client(s).\r\n# - At least 1 client should be returned from the provided parameter values, if not the process will abort\r\n# - No support for PAW alternate hierarchies\r\n#\r\n###########################################################\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode = 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncUserName = TM1User;\r\ncHoldsCube = '}Hold_%sClient%_}}_%sCube%';\r\ncMsrDim = '}Hold';\r\nnCubes = 0;\r\nnDimMax = 100;\r\nnErrors = 0;\r\nsMessage = '';\r\ncUserName = TM1User();\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pCube:%pCube%, pClient:%pClient%, pGroup:%pGroup%, pDelim:%pDelim%, pMode:%pMode%, pDir:%pDir%, pSkipNonExistentHoldsCubes:%pSkipNonExistentHoldsCubes%.' ;\r\n\r\n\r\n## LogOutput parameters\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) );\r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\n## Validate the Cube parameter\r\nIf( TRIM(pCube) @= '' );\r\n sMessage = 'A cube name must be provided.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# If no clients and groups have been specified then terminate process\r\nIf( Trim( pClient ) @= '' & Trim( pGroup ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No clients and groups specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# The mode is a restricted list of actions\r\nIf( pMode @<> 'C'\r\n & pMode @<> 'D'\r\n & pMode @<> 'R'\r\n & pMode @<> 'X'\r\n & pMode @<> 'M' );\r\n nErrors = 1;\r\n sMessage = Expand( 'Incorrect value for pMode: %pMode%. Valid values are: C, D, R, X, M.' );\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElse;\r\n pMode = Upper( Trim( pMode ));\r\nEndIf;\r\n\r\n# If blank delimiter specified then convert to default\r\nIf( pDelim @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\n# Skipping non-existent holds cubes\r\nIf( pSkipNonExistentHoldsCubes <> 1 );\r\n pSkipNonExistentHoldsCubes = 0;\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 );\r\n ProcessQuit;\r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n\r\n\r\n# # # # # # # # # # SEARCH FOR CUBES BY INSPECTING CUBE PARAMETER\r\n# - pCube (mandatory). It could be a combination of:\r\n# * multiple cubes separated with pDelim\r\n# * wildcards * and ?\r\n# * the keyword MODELCUBES (the cubes excluding the control cubes)\r\n\r\n### Split parameter into individual cubes and store in a temporary subset ###\r\nSubsetCreate( '}Cubes', 'Cubes subset', 1 );\r\n\r\nsCubes = pCube;\r\nnDelimiterIndex = 1;\r\nWhile( nDelimiterIndex <> 0 );\r\n nDelimiterIndex = Scan( pDelim, sCubes );\r\n If( nDelimiterIndex = 0 );\r\n sCube = sCubes;\r\n Else;\r\n sCube = Trim( SubSt( sCubes, 1, nDelimiterIndex - 1 ) );\r\n sCubes = Trim( Delet( sCubes, 1, nDelimiterIndex + Long(pDelim) ) );\r\n EndIf;\r\n\r\n If( sCube @<> '' );\r\n # Create subset of cubes. Wildcards could be involved.\r\n\r\n If( sCube @= 'MODELCUBES' );\r\n sMDX = '{Except( TM1SubsetAll( [}Cubes] ), TM1FilterByPattern( TM1SubsetAll( [}Cubes] ), \"}*\" ))}';\r\n Else;\r\n sMDX = '{TM1FilterByPattern( TM1SubsetAll( [}Cubes] ), \"' | sCube | '\" )}';\r\n EndIf;\r\n\r\n If( SubsetExists( '}Cubes', cTempSub ) = 1 );\r\n # If a delimited list of cube names includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( '}Cubes', cTempSub, sMDX );\r\n Else;\r\n # temp subset, therefore no need to destroy in the Epilog tab\r\n SubsetCreatebyMDX( cTempSub, sMDX, '}Cubes', 1 );\r\n EndIf;\r\n\r\n # Loop through the returned cubes, if any\r\n nCountCubes = 1;\r\n While( nCountCubes <= SubsetGetSize( '}Cubes', cTempSub ) );\r\n sCurrCube = SubsetGetElementName( '}Cubes', cTempSub, nCountCubes );\r\n # Validate cube name\r\n If( CubeExists( sCurrCube ) = 1 );\r\n If( SubsetElementExists( '}Cubes', 'Cubes subset', sCurrCube ) = 0 );\r\n SubsetElementInsert( '}Cubes', 'Cubes subset', sCurrCube, 0 );\r\n EndIf;\r\n EndIf;\r\n nCountCubes = nCountCubes + 1;\r\n End;\r\n EndIf;\r\n\r\nEnd;\r\n\r\n# If no cubes found\r\nnFoundCubesCount = SubsetGetSize( '}Cubes', 'Cubes subset' );\r\nIf( nFoundCubesCount = 0 );\r\n nErrors = 1;\r\n sMessage = 'No cubes found after processing pCube.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElse;\r\n If( pLogOutput = 1 );\r\n sMessage = 'Number of cubes found that match pCube: ' | NumberToString( nFoundCubesCount );\r\n LogOutput('INFO', Expand( sMessage ) );\r\n EndIf;\r\nEndIf;\r\n\r\n\r\n# # # # # # # # # # SEARCH FOR CLIENTS BY INSPECTING CLIENTS AND GROUPS PARAMETERS\r\n# - pClient (mandatory or used in conjunction with pGroup). It could be a combination of:\r\n# * multiple clients separated with pDelim\r\n# * wildcards * and ?\r\n# * the keyword MYSELF (the client running this TI process)\r\n\r\n# - pGroup (mandatory or used in conjunction with pClient). It could be a combination of:\r\n# * multiple clients separated with pDelim\r\n# * wildcards * and ?\r\n# * the keyword MYGROUPS (the groups that the client running this TI process is a member of)\r\n\r\n### Split parameter into individual clients and store in a temporary subset ###\r\nSubsetCreate( '}Clients', 'Clients subset', 1 );\r\n\r\nsClients = pClient;\r\nnDelimiterIndex = 1;\r\nWhile( nDelimiterIndex <> 0 );\r\n nDelimiterIndex = Scan( pDelim, sClients );\r\n If( nDelimiterIndex = 0 );\r\n sClient = sClients;\r\n Else;\r\n sClient = Trim( SubSt( sClients, 1, nDelimiterIndex - 1 ) );\r\n sClients = Trim( Delet( sClients, 1, nDelimiterIndex + Long(pDelim) ) );\r\n EndIf;\r\n\r\n If( sClient @<> '' );\r\n\r\n If( sClient @= 'MYSELF' );\r\n sClient = cUserName;\r\n EndIf;\r\n\r\n # Create subset of clients using Wildcard. Wildcards could be involved.\r\n sMDX = '{TM1FilterByPattern( TM1SubsetAll( [}Clients] ), \"' | sClient | '\" )}';\r\n\r\n If( SubsetExists( '}Clients', cTempSub ) = 1 );\r\n # If a delimited list of client names includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( '}Clients', cTempSub, sMDX );\r\n Else;\r\n # temp subset, therefore no need to destroy in the Epilog tab\r\n SubsetCreatebyMDX( cTempSub, sMDX, '}Clients', 1 );\r\n EndIf;\r\n\r\n # Loop through the returned clients, if any\r\n nCountClients = 1;\r\n While( nCountClients <= SubsetGetSize( '}Clients', cTempSub ) );\r\n sCurrClient = SubsetGetElementName( '}Clients', cTempSub, nCountClients );\r\n # Validate client name\r\n If( Dimix( '}Clients', sCurrClient ) > 0 );\r\n If( SubsetElementExists( '}Clients', 'Clients subset', sCurrClient ) = 0 );\r\n SubsetElementInsert( '}Clients', 'Clients subset', sCurrClient, 0 );\r\n EndIf;\r\n EndIf;\r\n nCountClients = nCountClients + 1;\r\n End;\r\n EndIf;\r\n\r\nEnd;\r\n\r\n\r\n### Split parameter into individual groups and store in a temporary subset ###\r\nSubsetCreate( '}Groups', 'Groups subset', 1 );\r\n\r\nsGroups = pGroup;\r\nnDelimiterIndex = 1;\r\nWhile( nDelimiterIndex <> 0 );\r\n nDelimiterIndex = Scan( pDelim, sGroups );\r\n If( nDelimiterIndex = 0 );\r\n sGroup = sGroups;\r\n Else;\r\n sGroup = Trim( SubSt( sGroups, 1, nDelimiterIndex - 1 ) );\r\n sGroups = Trim( Delet( sGroups, 1, nDelimiterIndex + Long(pDelim) ) );\r\n EndIf;\r\n\r\n If( sGroup @<> '' );\r\n # Create subset of groups. Wildcards could be involved.\r\n\r\n If( sGroup @= 'MYGROUPS' );\r\n sMDX = '{Filter( TM1SubsetAll( [}Groups] ), [}ClientGroups].( [}Clients].[' | cUserName | '] ) <> \"\" )}';\r\n Else;\r\n sMDX = '{TM1FilterByPattern( TM1SubsetAll( [}Groups] ), \"' | sGroup | '\" )}';\r\n EndIf;\r\n\r\n If( SubsetExists( '}Groups', cTempSub ) = 1 );\r\n # If a delimited list of group names includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( '}Groups', cTempSub, sMDX );\r\n Else;\r\n # temp subset, therefore no need to destroy in the Epilog tab\r\n SubsetCreatebyMDX( cTempSub, sMDX, '}Groups', 1 );\r\n EndIf;\r\n\r\n # Loop through the returned groups, if any\r\n nCountGroups = 1;\r\n While( nCountGroups <= SubsetGetSize( '}Groups', cTempSub ) );\r\n sCurrGroup = SubsetGetElementName( '}Groups', cTempSub, nCountGroups );\r\n # Validate group name\r\n If( Dimix( '}Groups', sCurrGroup ) > 0 );\r\n If( SubsetElementExists( '}Groups', 'Groups subset', sCurrGroup ) = 0 );\r\n SubsetElementInsert( '}Groups', 'Groups subset', sCurrGroup, 0 );\r\n EndIf;\r\n EndIf;\r\n nCountGroups = nCountGroups + 1;\r\n End;\r\n EndIf;\r\n\r\nEnd;\r\nnFoundGroupsCount = SubsetGetSize( '}Groups', 'Groups subset' );\r\n\r\n\r\n# Now rework groups into their clients through the security memberships\r\nIf( nFoundGroupsCount > 0 );\r\n\r\n # Create subset of clients using Wildcard. Wildcards could be involved.\r\n sMDX = 'Generate( TM1SubsetToSet([}Groups], \"Groups subset\" ), Filter( TM1SubsetAll([}Clients]), [}ClientGroups].([}Groups].CurrentMember) <> \"\" ))';\r\n If( SubsetExists( '}Clients', cTempSub ) = 1 );\r\n SubsetMDXSet( '}Clients', cTempSub, sMDX );\r\n Else;\r\n SubsetCreatebyMDX( cTempSub, sMDX, '}Clients', 1 );\r\n EndIf;\r\n\r\n # Loop through the returned clients, if any\r\n nCountClients = 1;\r\n While( nCountClients <= SubsetGetSize( '}Clients', cTempSub ) );\r\n sCurrClient = SubsetGetElementName( '}Clients', cTempSub, nCountClients );\r\n If( SubsetElementExists( '}Clients', 'Clients subset', sCurrClient ) = 0 );\r\n SubsetElementInsert( '}Clients', 'Clients subset', sCurrClient, 0 );\r\n EndIf;\r\n nCountClients = nCountClients + 1;\r\n End;\r\nEndIf;\r\n\r\n\r\n# If no clients found\r\nnFoundClientsCount = SubsetGetSize( '}Clients', 'Clients subset' );\r\nIf( nFoundClientsCount = 0 );\r\n nErrors = 1;\r\n sMessage = 'No clients found after processing pClient and pGroup.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElse;\r\n If( pLogOutput = 1 );\r\n sMessage = 'Number of clients found that match pClient and pGroup: ' | NumberToString( nFoundClientsCount );\r\n LogOutput('INFO', Expand( sMessage ) );\r\n EndIf;\r\nEndIf;\r\n\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 );\r\n ProcessQuit;\r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n\r\n# A double loop over cubes and clients to apply the selected action\r\nnCountCubes = 1;\r\nWhile( nCountCubes <= nFoundCubesCount );\r\n sCube = SubsetGetElementName( '}Cubes', 'Cubes subset', nCountCubes );\r\n nCubeDimCount = CubeDimensionCountGet( sCube );\r\n\r\n nCountClients = 1;\r\n While( nCountClients <= nFoundClientsCount );\r\n sClient = SubsetGetElementName( '}Clients', 'Clients subset', nCountClients );\r\n\r\n sHoldsCube = Expand( cHoldsCube );\r\n\r\n\r\n If( pMode @= 'C' );\r\n\r\n\r\n # Create a Holds cube\r\n If( CubeExists( sHoldsCube ) = 1 );\r\n nErrors = 1;\r\n sMessage = Expand( 'The holds cube ''%sHoldsCube%'' already exists so it could not be created.' );\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 );\r\n ProcessQuit;\r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n EndIf;\r\n\r\n If( nCubeDimCount > nDimMax );\r\n nErrors = 1;\r\n sMessage = Expand( 'The base cube ''%sCube%'' for the holds cube ''%sHoldsCube%'' contains too many dimensions. ' | NumberToString( nCubeDimCount ) | ' instead of at most ' | NumberToString( nDimMax ) | '.' );\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 );\r\n ProcessQuit;\r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n EndIf;\r\n\r\n # Create a measures dimension\r\n If( DimensionExists( cMsrDim ) = 0 );\r\n If( pLogOutput = 1 );\r\n sMessage = Expand( 'The measures dimension for hold cubes (%cMsrDim%) does not exist and will be created.' );\r\n LogOutput('INFO', Expand( sMessage ) );\r\n EndIf;\r\n nRet = ExecuteProcess( '}bedrock.hier.create', 'pLogOutput', pLogOutput, 'pStrictErrorHandling', pStrictErrorHandling, 'pDim', cMsrDim );\r\n If( nRet <> 0 );\r\n sMessage = Expand( 'Error creating the dimension ''%cMsrDim%''.' );\r\n nErrors = 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 );\r\n ProcessQuit;\r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n EndIf;\r\n DimensionElementInsert( cMsrDim, '', 'HoldStatus', 'S' );\r\n EndIf;\r\n\r\n # Get the dimension names for the hold cube\r\n sDims = '';\r\n d = 1;\r\n While( d <= nCubeDimCount );\r\n sDim = Tabdim( sCube, d );\r\n sDims = sDims | pDelim | sDim;\r\n d = d + 1;\r\n End;\r\n sDims = sDims | pDelim | cMsrDim;\r\n sDims = Delet( sDims, 1, Long( pDelim ));\r\n\r\n nRet = ExecuteProcess( '}bedrock.cube.create', 'pLogOutput', pLogOutput, 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pCube', sHoldsCube, 'pDims', sDims, 'pRecreate', 0, 'pDelim', pDelim );\r\n If( nRet <> 0 );\r\n sMessage = Expand( 'Error creating the cube ''%sHoldsCube%''.' );\r\n nErrors = 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 );\r\n ProcessQuit;\r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n EndIf;\r\n If( pLogOutput = 1 );\r\n sMessage = Expand( 'The holds cube ''%sHoldsCube%'' was created.' );\r\n LogOutput('INFO', Expand( sMessage ) );\r\n EndIf;\r\n\r\n\r\n ElseIf( pMode @= 'D' );\r\n\r\n\r\n # Destroy a Holds cube\r\n If( CubeExists( sHoldsCube ) = 0 );\r\n If( pSkipNonExistentHoldsCubes = 0 );\r\n # nErrors = 1;\r\n # sMessage = Expand( 'The holds cube ''%sHoldsCube%'' does not exist so it could not be destroyed.' );\r\n # LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n # If( pStrictErrorHandling = 1 );\r\n # ProcessQuit;\r\n # Else;\r\n # ProcessBreak;\r\n # EndIf;\r\n If( pLogOutput = 1 );\r\n sMessage = Expand( 'The holds cube ''%sHoldsCube%'' does not exist so it could not be destroyed.' );\r\n LogOutput('INFO', Expand( sMessage ) );\r\n EndIf;\r\n EndIf;\r\n Else;\r\n\r\n CubeDestroy( sHoldsCube );\r\n If( pLogOutput = 1 );\r\n sMessage = Expand( 'The holds cube ''%sHoldsCube%'' was destroyed.' );\r\n LogOutput('INFO', Expand( sMessage ) );\r\n EndIf;\r\n EndIf;\r\n\r\n\r\n ElseIf( pMode @= 'R' );\r\n\r\n\r\n # In an existing Holds cube, delete all holds (Release)\r\n If( CubeExists( sHoldsCube ) = 0 );\r\n If( pSkipNonExistentHoldsCubes = 0 );\r\n nErrors = 1;\r\n sMessage = Expand( 'The holds cube ''%sHoldsCube%'' does not exist so all of its holds (if any) could not be released.' );\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 );\r\n ProcessQuit;\r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n EndIf;\r\n Else;\r\n\r\n CubeClearData( sHoldsCube );\r\n # nRet = ExecuteProcess( '}bedrock.cube.data.clear', 'pLogOutput', pLogOutput, 'pStrictErrorHandling', pStrictErrorHandling,\r\n # 'pCube', sHoldsCube, 'pView', '', 'pFilter', '', 'pSuppressConsolStrings', 0, 'pCubeLogging', 2 );\r\n # If( nRet <> 0 );\r\n # sMessage = 'Error releasing all the holds in the cube ''%sHoldsCube%''.';\r\n # nErrors = 1;\r\n # LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n # If( pStrictErrorHandling = 1 );\r\n # ProcessQuit;\r\n # Else;\r\n # ProcessBreak;\r\n # EndIf;\r\n # EndIf;\r\n If( pLogOutput = 1 );\r\n sMessage = Expand( 'All the holds in the cube ''%sHoldsCube%'' were released.' );\r\n LogOutput('INFO', Expand( sMessage ) );\r\n EndIf;\r\n\r\n EndIf;\r\n\r\n\r\n ElseIf( pMode @= 'X' );\r\n\r\n\r\n # From an existing Holds cube, export all entries\r\n If( CubeExists( sHoldsCube ) = 0 );\r\n If( pSkipNonExistentHoldsCubes = 0 );\r\n nErrors = 1;\r\n sMessage = Expand( 'The holds cube ''%sHoldsCube%'' does not exist so all of its holds (if any) could not be exported.' );\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 );\r\n ProcessQuit;\r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n EndIf;\r\n Else;\r\n\r\n If( nCubeDimCount > nDimMax );\r\n nErrors = 1;\r\n sMessage = Expand( 'The base cube ''%sCube%'' for the holds cube ''%sHoldsCube%'' contains too many dimensions. ' | NumberToString( nCubeDimCount ) | ' instead of at most ' | NumberToString( nDimMax ) | '.' );\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 );\r\n ProcessQuit;\r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n EndIf;\r\n\r\n # the file directory (If empty, the error file directory is used. If not existing, an error is returned.)\r\n # this is done by the called Bedrock process\r\n # the file name is simply the Holds cube name with file extension csv\r\n sFileName = sHoldsCube | '.csv';\r\n nRet = ExecuteProcess( '}bedrock.cube.data.export', 'pLogOutput', pLogOutput, 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pCube', sHoldsCube, 'pView', '', 'pFilter', '', 'pSuppressConsol', 0, 'pSuppressConsolStrings', 0,\r\n 'pCubeLogging', 2, 'pFilePath', pDir, 'pFileName', sFileName );\r\n If( nRet <> 0 );\r\n sMessage = Expand( 'Error exporting all the holds from the cube ''%sHoldsCube%'' to a flat file.' );\r\n nErrors = 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 );\r\n ProcessQuit;\r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n EndIf;\r\n If( pLogOutput = 1 );\r\n sMessage = Expand( 'All the holds in the cube ''%sHoldsCube%'' were exported.' );\r\n LogOutput('INFO', Expand( sMessage ) );\r\n EndIf;\r\n EndIf;\r\n\r\n\r\n ElseIf( pMode @= 'M' );\r\n\r\n\r\n # To an existing Holds cube, import all entries\r\n # If the Holds cube does not exist, you need to create it first with mode C\r\n If( CubeExists( sHoldsCube ) = 0 );\r\n If( pSkipNonExistentHoldsCubes = 0 );\r\n nErrors = 1;\r\n sMessage = Expand( 'The holds cube ''%sHoldsCube%'' does not exist so holds (if any) could not be imported. You might want to create it first using mode ''C''.' );\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 );\r\n ProcessQuit;\r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n EndIf;\r\n Else;\r\n\r\n # the file directory (If empty, the error file directory is used. If not existing, an error is returned.)\r\n # this is done by the called Bedrock process\r\n # the file name is simply the Holds cube name with file extension csv\r\n sFileName = sHoldsCube | '.csv';\r\n nRet = ExecuteProcess( '}bedrock.cube.data.import', 'pLogOutput', pLogOutput, 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pCube', sHoldsCube, 'pSrcDir', pDir, 'pSrcFile', sFileName, 'pCubeLogging', 2, 'pFileDelete', 0, 'pSkipInvalidRecords', 0 );\r\n If( nRet <> 0 );\r\n sMessage = Expand( 'Error importing all the holds to the cube ''%sHoldsCube%'' from a flat file.' );\r\n nErrors = 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 );\r\n ProcessQuit;\r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n EndIf;\r\n If( pLogOutput = 1 );\r\n sMessage = Expand( 'All the holds were imported to the cube ''%sHoldsCube%''.' );\r\n LogOutput('INFO', Expand( sMessage ) );\r\n EndIf;\r\n EndIf;\r\n EndIf;\r\n\r\n nCountClients = nCountClients + 1;\r\n End;\r\n\r\n nCountCubes = nCountCubes + 1;\r\nEnd;", + "PrologProcedure": "#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.cube.data.hold', 'pLogOutput', pLogOutput, 'pStrictErrorHandling', pStrictErrorHandling, \r\n 'pMode', 'C / D / R / X / M', 'pCube', '', 'pClient', '', 'pGroup', '', 'pDelim', '&', 'pDir', '', 'pSkipNonExistentHoldsCubes', 1 );\r\nEndIf;\r\n\r\n#################################################################################################\r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n#################################################################################################\r\n\r\n# Description:\r\n# This TI process can manage TM1 cube holds. Holds are a personal tool for a TM1 user in any TM1 client.\r\n# A hold by client A does not restrict data entry by client B.\r\n# A client needs write access to a cell in order to apply a hold to the cell.\r\n# Existing Bedrock processes are leveraged including their default parameter values.\r\n#\r\n# Use case: Intended for development/prototyping or in Production environment.\r\n# - When a user has applied holds and logs off (or is forced to log off), the holds are lost (even though the Holds cube still exists)\r\n# - When the TM1 model is restarted, all holds are lost (even though the Holds cube still exists)\r\n# - The customer could provide a set of holds to be applied, in several cubes and to several clients and even data entry groups of clients. Applying the holds manually would be tedious.\r\n# - A regular clean up of Holds cubes that are out of date could be wise\r\n#\r\n# Parameters:\r\n# - pLogOutput (standard Bedrock parameter, Boolean True = 1)\r\n# - pStrictErrorHandling (standard Bedrock parameter, Boolean True = 1)\r\n# - pMode (see below). It should be one of: C / D / R / X / M\r\n# - pCube (mandatory). Provide the base cuube name(s), not the Holds cube names! It could be a combination of:\r\n# * multiple cubes separated with pDelim\r\n# * wildcards * and ?\r\n# * the keyword MODELCUBES (the cubes excluding the control cubes)\r\n# - pClient (mandatory or used in conjunction with pGroup). It could be a combination of:\r\n# * multiple clients separated with pDelim\r\n# * wildcards * and ?\r\n# * the keyword MYSELF (the client running this TI process)\r\n# - pGroup (mandatory or used in conjunction with pClient). It could be a combination of:\r\n# * multiple clients separated with pDelim\r\n# * wildcards * and ?\r\n# * the keyword MYGROUPS (the groups that the client running this TI process is a member of)\r\n# - pDelim (standard Bedrock parameter to manage above lists, default value if blank = '&')\r\n# - pDir (only used when exporting or importing flat files. If empty, the error file directory is used. If not existing, an error is returned.)\r\n# - pSkipNonExistentHoldsCubes (not used for mode C) (When using lists and wildcards, it can lead to non-existent holds cubes. Use 1 to skip silently.\r\n#\r\n# Supported functionality related to holds, given the selections made:\r\n# - pMode = C: creation of a holds cube\r\n# - pMode = D: destruction of a holds cube\r\n# - pMode = R: release all holds\r\n# - pMode = X: export of holds to text files\r\n# - pMode = M: import of holds from text files (either new holds to be set, either holds exported earlier)\r\n#\r\n# Note:\r\n# - When exporting holds, the file format will respect the default values of the Bedrock process to export data. The file name is '}Hold_[ClientName]_}}_[CubeName].csv so it matches the Holds cubename.\r\n# - To import holds, the file format needs to respect the default values of the Bedrock process to import data. The file name is '}Hold_[ClientName]_}}_[CubeName].csv so it matches the Holds cubename.\r\n# - When importing holds, the cell value needs to be either H or C\r\n# * A value of C is to be put in a consolidated cell of the Holds cube\r\n# * A value of H is to be put in a level 0 cell of the Holds cube\r\n# * Any other combination will not lead to an error but TM1 will not apply the hold as intended\r\n# * String cells should not be used in data holds\r\n# - When importing holds, an additional zeroout should be done with a call to this process with mode 'R'\r\n# - The selections for pClient and pGroup will lead to a list of unique clients, to which the selected mode is applied\r\n# For a group, the members in the group are retrieved, and added to the selected client(s).\r\n# - At least 1 client should be returned from the provided parameter values, if not the process will abort\r\n# - No support for PAW alternate hierarchies\r\n#\r\n###########################################################\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode = 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncUserName = TM1User;\r\ncHoldsCube = '}Hold_%sClient%_}}_%sCube%';\r\ncMsrDim = '}Hold';\r\nnCubes = 0;\r\nnDimMax = 100;\r\nnErrors = 0;\r\nsMessage = '';\r\ncUserName = TM1User();\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pCube:%pCube%, pClient:%pClient%, pGroup:%pGroup%, pDelim:%pDelim%, pMode:%pMode%, pDir:%pDir%, pSkipNonExistentHoldsCubes:%pSkipNonExistentHoldsCubes%.' ;\r\n\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pClient\": null,\r\n \"pCube\": null,\r\n \"pDelim\": \"&\",\r\n \"pDir\": \"\",\r\n \"pGroup\": null,\r\n \"pMode\": null,\r\n \"pLogOutput\": 0,\r\n \"pSkipNonExistentHoldsCubes\": 0,\r\n \"pStrictErrorHandling\": 0\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pClient\": '|StringToJson ( pClient )|',\r\n \"pCube\": '|StringToJson ( pCube )|',\r\n \"pDelim\": '|StringToJson ( pDelim )|',\r\n \"pDir\": '|StringToJson ( pDir )|',\r\n \"pGroup\": '|StringToJson ( pGroup )|',\r\n \"pMode\": '|StringToJson ( pMode )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pSkipNonExistentHoldsCubes\": '|NumberToString( pSkipNonExistentHoldsCubes )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npClient = JsonToString( JsonGet( pJson, 'pClient' ) );\r\npCube = JsonToString( JsonGet( pJson, 'pCube' ) );\r\npDelim = JsonToString( JsonGet( pJson, 'pDelim' ) );\r\npDir = JsonToString( JsonGet( pJson, 'pDir' ) );\r\npGroup = JsonToString( JsonGet( pJson, 'pGroup' ) );\r\npMode = JsonToString( JsonGet( pJson, 'pMode' ) );\r\n# Numeric Parameters\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npSkipNonExistentHoldsCubes = StringToNumber( JsonToString( JsonGet( pJson, 'pSkipNonExistentHoldsCubes' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n## LogOutput parameters\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) );\r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\n## Validate the Cube parameter\r\nIf( TRIM(pCube) @= '' );\r\n sMessage = 'A cube name must be provided.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# If no clients and groups have been specified then terminate process\r\nIf( Trim( pClient ) @= '' & Trim( pGroup ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No clients and groups specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# The mode is a restricted list of actions\r\nIf( pMode @<> 'C'\r\n & pMode @<> 'D'\r\n & pMode @<> 'R'\r\n & pMode @<> 'X'\r\n & pMode @<> 'M' );\r\n nErrors = 1;\r\n sMessage = Expand( 'Incorrect value for pMode: %pMode%. Valid values are: C, D, R, X, M.' );\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElse;\r\n pMode = Upper( Trim( pMode ));\r\nEndIf;\r\n\r\n# If blank delimiter specified then convert to default\r\nIf( pDelim @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\n# Skipping non-existent holds cubes\r\nIf( pSkipNonExistentHoldsCubes <> 1 );\r\n pSkipNonExistentHoldsCubes = 0;\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 );\r\n ProcessQuit;\r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n\r\n\r\n# # # # # # # # # # SEARCH FOR CUBES BY INSPECTING CUBE PARAMETER\r\n# - pCube (mandatory). It could be a combination of:\r\n# * multiple cubes separated with pDelim\r\n# * wildcards * and ?\r\n# * the keyword MODELCUBES (the cubes excluding the control cubes)\r\n\r\n### Split parameter into individual cubes and store in a temporary subset ###\r\nSubsetCreate( '}Cubes', 'Cubes subset', 1 );\r\n\r\nsCubes = pCube;\r\nnDelimiterIndex = 1;\r\nWhile( nDelimiterIndex <> 0 );\r\n nDelimiterIndex = Scan( pDelim, sCubes );\r\n If( nDelimiterIndex = 0 );\r\n sCube = sCubes;\r\n Else;\r\n sCube = Trim( SubSt( sCubes, 1, nDelimiterIndex - 1 ) );\r\n sCubes = Trim( Delet( sCubes, 1, nDelimiterIndex + Long(pDelim) ) );\r\n EndIf;\r\n\r\n If( sCube @<> '' );\r\n # Create subset of cubes. Wildcards could be involved.\r\n\r\n If( sCube @= 'MODELCUBES' );\r\n sMDX = '{Except( TM1SubsetAll( [}Cubes] ), TM1FilterByPattern( TM1SubsetAll( [}Cubes] ), \"}*\" ))}';\r\n Else;\r\n sMDX = '{TM1FilterByPattern( TM1SubsetAll( [}Cubes] ), \"' | sCube | '\" )}';\r\n EndIf;\r\n\r\n If( SubsetExists( '}Cubes', cTempSub ) = 1 );\r\n # If a delimited list of cube names includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( '}Cubes', cTempSub, sMDX );\r\n Else;\r\n # temp subset, therefore no need to destroy in the Epilog tab\r\n SubsetCreatebyMDX( cTempSub, sMDX, '}Cubes', 1 );\r\n EndIf;\r\n\r\n # Loop through the returned cubes, if any\r\n nCountCubes = 1;\r\n While( nCountCubes <= SubsetGetSize( '}Cubes', cTempSub ) );\r\n sCurrCube = SubsetGetElementName( '}Cubes', cTempSub, nCountCubes );\r\n # Validate cube name\r\n If( CubeExists( sCurrCube ) = 1 );\r\n If( SubsetElementExists( '}Cubes', 'Cubes subset', sCurrCube ) = 0 );\r\n SubsetElementInsert( '}Cubes', 'Cubes subset', sCurrCube, 0 );\r\n EndIf;\r\n EndIf;\r\n nCountCubes = nCountCubes + 1;\r\n End;\r\n EndIf;\r\n\r\nEnd;\r\n\r\n# If no cubes found\r\nnFoundCubesCount = SubsetGetSize( '}Cubes', 'Cubes subset' );\r\nIf( nFoundCubesCount = 0 );\r\n nErrors = 1;\r\n sMessage = 'No cubes found after processing pCube.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElse;\r\n If( pLogOutput = 1 );\r\n sMessage = 'Number of cubes found that match pCube: ' | NumberToString( nFoundCubesCount );\r\n LogOutput('INFO', Expand( sMessage ) );\r\n EndIf;\r\nEndIf;\r\n\r\n\r\n# # # # # # # # # # SEARCH FOR CLIENTS BY INSPECTING CLIENTS AND GROUPS PARAMETERS\r\n# - pClient (mandatory or used in conjunction with pGroup). It could be a combination of:\r\n# * multiple clients separated with pDelim\r\n# * wildcards * and ?\r\n# * the keyword MYSELF (the client running this TI process)\r\n\r\n# - pGroup (mandatory or used in conjunction with pClient). It could be a combination of:\r\n# * multiple clients separated with pDelim\r\n# * wildcards * and ?\r\n# * the keyword MYGROUPS (the groups that the client running this TI process is a member of)\r\n\r\n### Split parameter into individual clients and store in a temporary subset ###\r\nSubsetCreate( '}Clients', 'Clients subset', 1 );\r\n\r\nsClients = pClient;\r\nnDelimiterIndex = 1;\r\nWhile( nDelimiterIndex <> 0 );\r\n nDelimiterIndex = Scan( pDelim, sClients );\r\n If( nDelimiterIndex = 0 );\r\n sClient = sClients;\r\n Else;\r\n sClient = Trim( SubSt( sClients, 1, nDelimiterIndex - 1 ) );\r\n sClients = Trim( Delet( sClients, 1, nDelimiterIndex + Long(pDelim) ) );\r\n EndIf;\r\n\r\n If( sClient @<> '' );\r\n\r\n If( sClient @= 'MYSELF' );\r\n sClient = cUserName;\r\n EndIf;\r\n\r\n # Create subset of clients using Wildcard. Wildcards could be involved.\r\n sMDX = '{TM1FilterByPattern( TM1SubsetAll( [}Clients] ), \"' | sClient | '\" )}';\r\n\r\n If( SubsetExists( '}Clients', cTempSub ) = 1 );\r\n # If a delimited list of client names includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( '}Clients', cTempSub, sMDX );\r\n Else;\r\n # temp subset, therefore no need to destroy in the Epilog tab\r\n SubsetCreatebyMDX( cTempSub, sMDX, '}Clients', 1 );\r\n EndIf;\r\n\r\n # Loop through the returned clients, if any\r\n nCountClients = 1;\r\n While( nCountClients <= SubsetGetSize( '}Clients', cTempSub ) );\r\n sCurrClient = SubsetGetElementName( '}Clients', cTempSub, nCountClients );\r\n # Validate client name\r\n If( Dimix( '}Clients', sCurrClient ) > 0 );\r\n If( SubsetElementExists( '}Clients', 'Clients subset', sCurrClient ) = 0 );\r\n SubsetElementInsert( '}Clients', 'Clients subset', sCurrClient, 0 );\r\n EndIf;\r\n EndIf;\r\n nCountClients = nCountClients + 1;\r\n End;\r\n EndIf;\r\n\r\nEnd;\r\n\r\n\r\n### Split parameter into individual groups and store in a temporary subset ###\r\nSubsetCreate( '}Groups', 'Groups subset', 1 );\r\n\r\nsGroups = pGroup;\r\nnDelimiterIndex = 1;\r\nWhile( nDelimiterIndex <> 0 );\r\n nDelimiterIndex = Scan( pDelim, sGroups );\r\n If( nDelimiterIndex = 0 );\r\n sGroup = sGroups;\r\n Else;\r\n sGroup = Trim( SubSt( sGroups, 1, nDelimiterIndex - 1 ) );\r\n sGroups = Trim( Delet( sGroups, 1, nDelimiterIndex + Long(pDelim) ) );\r\n EndIf;\r\n\r\n If( sGroup @<> '' );\r\n # Create subset of groups. Wildcards could be involved.\r\n\r\n If( sGroup @= 'MYGROUPS' );\r\n sMDX = '{Filter( TM1SubsetAll( [}Groups] ), [}ClientGroups].( [}Clients].[' | cUserName | '] ) <> \"\" )}';\r\n Else;\r\n sMDX = '{TM1FilterByPattern( TM1SubsetAll( [}Groups] ), \"' | sGroup | '\" )}';\r\n EndIf;\r\n\r\n If( SubsetExists( '}Groups', cTempSub ) = 1 );\r\n # If a delimited list of group names includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( '}Groups', cTempSub, sMDX );\r\n Else;\r\n # temp subset, therefore no need to destroy in the Epilog tab\r\n SubsetCreatebyMDX( cTempSub, sMDX, '}Groups', 1 );\r\n EndIf;\r\n\r\n # Loop through the returned groups, if any\r\n nCountGroups = 1;\r\n While( nCountGroups <= SubsetGetSize( '}Groups', cTempSub ) );\r\n sCurrGroup = SubsetGetElementName( '}Groups', cTempSub, nCountGroups );\r\n # Validate group name\r\n If( Dimix( '}Groups', sCurrGroup ) > 0 );\r\n If( SubsetElementExists( '}Groups', 'Groups subset', sCurrGroup ) = 0 );\r\n SubsetElementInsert( '}Groups', 'Groups subset', sCurrGroup, 0 );\r\n EndIf;\r\n EndIf;\r\n nCountGroups = nCountGroups + 1;\r\n End;\r\n EndIf;\r\n\r\nEnd;\r\nnFoundGroupsCount = SubsetGetSize( '}Groups', 'Groups subset' );\r\n\r\n\r\n# Now rework groups into their clients through the security memberships\r\nIf( nFoundGroupsCount > 0 );\r\n\r\n # Create subset of clients using Wildcard. Wildcards could be involved.\r\n sMDX = 'Generate( TM1SubsetToSet([}Groups], \"Groups subset\" ), Filter( TM1SubsetAll([}Clients]), [}ClientGroups].([}Groups].CurrentMember) <> \"\" ))';\r\n If( SubsetExists( '}Clients', cTempSub ) = 1 );\r\n SubsetMDXSet( '}Clients', cTempSub, sMDX );\r\n Else;\r\n SubsetCreatebyMDX( cTempSub, sMDX, '}Clients', 1 );\r\n EndIf;\r\n\r\n # Loop through the returned clients, if any\r\n nCountClients = 1;\r\n While( nCountClients <= SubsetGetSize( '}Clients', cTempSub ) );\r\n sCurrClient = SubsetGetElementName( '}Clients', cTempSub, nCountClients );\r\n If( SubsetElementExists( '}Clients', 'Clients subset', sCurrClient ) = 0 );\r\n SubsetElementInsert( '}Clients', 'Clients subset', sCurrClient, 0 );\r\n EndIf;\r\n nCountClients = nCountClients + 1;\r\n End;\r\nEndIf;\r\n\r\n\r\n# If no clients found\r\nnFoundClientsCount = SubsetGetSize( '}Clients', 'Clients subset' );\r\nIf( nFoundClientsCount = 0 );\r\n nErrors = 1;\r\n sMessage = 'No clients found after processing pClient and pGroup.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElse;\r\n If( pLogOutput = 1 );\r\n sMessage = 'Number of clients found that match pClient and pGroup: ' | NumberToString( nFoundClientsCount );\r\n LogOutput('INFO', Expand( sMessage ) );\r\n EndIf;\r\nEndIf;\r\n\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 );\r\n ProcessQuit;\r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n\r\n# A double loop over cubes and clients to apply the selected action\r\nnCountCubes = 1;\r\nWhile( nCountCubes <= nFoundCubesCount );\r\n sCube = SubsetGetElementName( '}Cubes', 'Cubes subset', nCountCubes );\r\n nCubeDimCount = CubeDimensionCountGet( sCube );\r\n\r\n nCountClients = 1;\r\n While( nCountClients <= nFoundClientsCount );\r\n sClient = SubsetGetElementName( '}Clients', 'Clients subset', nCountClients );\r\n\r\n sHoldsCube = Expand( cHoldsCube );\r\n\r\n\r\n If( pMode @= 'C' );\r\n\r\n\r\n # Create a Holds cube\r\n If( CubeExists( sHoldsCube ) = 1 );\r\n nErrors = 1;\r\n sMessage = Expand( 'The holds cube ''%sHoldsCube%'' already exists so it could not be created.' );\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 );\r\n ProcessQuit;\r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n EndIf;\r\n\r\n If( nCubeDimCount > nDimMax );\r\n nErrors = 1;\r\n sMessage = Expand( 'The base cube ''%sCube%'' for the holds cube ''%sHoldsCube%'' contains too many dimensions. ' | NumberToString( nCubeDimCount ) | ' instead of at most ' | NumberToString( nDimMax ) | '.' );\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 );\r\n ProcessQuit;\r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n EndIf;\r\n\r\n # Create a measures dimension\r\n If( DimensionExists( cMsrDim ) = 0 );\r\n If( pLogOutput = 1 );\r\n sMessage = Expand( 'The measures dimension for hold cubes (%cMsrDim%) does not exist and will be created.' );\r\n LogOutput('INFO', Expand( sMessage ) );\r\n EndIf;\r\n nRet = ExecuteProcess( '}bedrock.hier.create', 'pLogOutput', pLogOutput, 'pStrictErrorHandling', pStrictErrorHandling, 'pDim', cMsrDim );\r\n If( nRet <> 0 );\r\n sMessage = Expand( 'Error creating the dimension ''%cMsrDim%''.' );\r\n nErrors = 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 );\r\n ProcessQuit;\r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n EndIf;\r\n DimensionElementInsert( cMsrDim, '', 'HoldStatus', 'S' );\r\n EndIf;\r\n\r\n # Get the dimension names for the hold cube\r\n sDims = '';\r\n d = 1;\r\n While( d <= nCubeDimCount );\r\n sDim = Tabdim( sCube, d );\r\n sDims = sDims | pDelim | sDim;\r\n d = d + 1;\r\n End;\r\n sDims = sDims | pDelim | cMsrDim;\r\n sDims = Delet( sDims, 1, Long( pDelim ));\r\n\r\n nRet = ExecuteProcess( '}bedrock.cube.create', 'pLogOutput', pLogOutput, 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pCube', sHoldsCube, 'pDims', sDims, 'pRecreate', 0, 'pDelim', pDelim );\r\n If( nRet <> 0 );\r\n sMessage = Expand( 'Error creating the cube ''%sHoldsCube%''.' );\r\n nErrors = 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 );\r\n ProcessQuit;\r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n EndIf;\r\n If( pLogOutput = 1 );\r\n sMessage = Expand( 'The holds cube ''%sHoldsCube%'' was created.' );\r\n LogOutput('INFO', Expand( sMessage ) );\r\n EndIf;\r\n\r\n\r\n ElseIf( pMode @= 'D' );\r\n\r\n\r\n # Destroy a Holds cube\r\n If( CubeExists( sHoldsCube ) = 0 );\r\n If( pSkipNonExistentHoldsCubes = 0 );\r\n # nErrors = 1;\r\n # sMessage = Expand( 'The holds cube ''%sHoldsCube%'' does not exist so it could not be destroyed.' );\r\n # LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n # If( pStrictErrorHandling = 1 );\r\n # ProcessQuit;\r\n # Else;\r\n # ProcessBreak;\r\n # EndIf;\r\n If( pLogOutput = 1 );\r\n sMessage = Expand( 'The holds cube ''%sHoldsCube%'' does not exist so it could not be destroyed.' );\r\n LogOutput('INFO', Expand( sMessage ) );\r\n EndIf;\r\n EndIf;\r\n Else;\r\n\r\n CubeDestroy( sHoldsCube );\r\n If( pLogOutput = 1 );\r\n sMessage = Expand( 'The holds cube ''%sHoldsCube%'' was destroyed.' );\r\n LogOutput('INFO', Expand( sMessage ) );\r\n EndIf;\r\n EndIf;\r\n\r\n\r\n ElseIf( pMode @= 'R' );\r\n\r\n\r\n # In an existing Holds cube, delete all holds (Release)\r\n If( CubeExists( sHoldsCube ) = 0 );\r\n If( pSkipNonExistentHoldsCubes = 0 );\r\n nErrors = 1;\r\n sMessage = Expand( 'The holds cube ''%sHoldsCube%'' does not exist so all of its holds (if any) could not be released.' );\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 );\r\n ProcessQuit;\r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n EndIf;\r\n Else;\r\n\r\n CubeClearData( sHoldsCube );\r\n # nRet = ExecuteProcess( '}bedrock.cube.data.clear', 'pLogOutput', pLogOutput, 'pStrictErrorHandling', pStrictErrorHandling,\r\n # 'pCube', sHoldsCube, 'pView', '', 'pFilter', '', 'pSuppressConsolStrings', 0, 'pCubeLogging', 2 );\r\n # If( nRet <> 0 );\r\n # sMessage = 'Error releasing all the holds in the cube ''%sHoldsCube%''.';\r\n # nErrors = 1;\r\n # LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n # If( pStrictErrorHandling = 1 );\r\n # ProcessQuit;\r\n # Else;\r\n # ProcessBreak;\r\n # EndIf;\r\n # EndIf;\r\n If( pLogOutput = 1 );\r\n sMessage = Expand( 'All the holds in the cube ''%sHoldsCube%'' were released.' );\r\n LogOutput('INFO', Expand( sMessage ) );\r\n EndIf;\r\n\r\n EndIf;\r\n\r\n\r\n ElseIf( pMode @= 'X' );\r\n\r\n\r\n # From an existing Holds cube, export all entries\r\n If( CubeExists( sHoldsCube ) = 0 );\r\n If( pSkipNonExistentHoldsCubes = 0 );\r\n nErrors = 1;\r\n sMessage = Expand( 'The holds cube ''%sHoldsCube%'' does not exist so all of its holds (if any) could not be exported.' );\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 );\r\n ProcessQuit;\r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n EndIf;\r\n Else;\r\n\r\n If( nCubeDimCount > nDimMax );\r\n nErrors = 1;\r\n sMessage = Expand( 'The base cube ''%sCube%'' for the holds cube ''%sHoldsCube%'' contains too many dimensions. ' | NumberToString( nCubeDimCount ) | ' instead of at most ' | NumberToString( nDimMax ) | '.' );\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 );\r\n ProcessQuit;\r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n EndIf;\r\n\r\n # the file directory (If empty, the error file directory is used. If not existing, an error is returned.)\r\n # this is done by the called Bedrock process\r\n # the file name is simply the Holds cube name with file extension csv\r\n sFileName = sHoldsCube | '.csv';\r\n nRet = ExecuteProcess( '}bedrock.cube.data.export', 'pLogOutput', pLogOutput, 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pCube', sHoldsCube, 'pView', '', 'pFilter', '', 'pSuppressConsol', 0, 'pSuppressConsolStrings', 0,\r\n 'pCubeLogging', 2, 'pFilePath', pDir, 'pFileName', sFileName );\r\n If( nRet <> 0 );\r\n sMessage = Expand( 'Error exporting all the holds from the cube ''%sHoldsCube%'' to a flat file.' );\r\n nErrors = 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 );\r\n ProcessQuit;\r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n EndIf;\r\n If( pLogOutput = 1 );\r\n sMessage = Expand( 'All the holds in the cube ''%sHoldsCube%'' were exported.' );\r\n LogOutput('INFO', Expand( sMessage ) );\r\n EndIf;\r\n EndIf;\r\n\r\n\r\n ElseIf( pMode @= 'M' );\r\n\r\n\r\n # To an existing Holds cube, import all entries\r\n # If the Holds cube does not exist, you need to create it first with mode C\r\n If( CubeExists( sHoldsCube ) = 0 );\r\n If( pSkipNonExistentHoldsCubes = 0 );\r\n nErrors = 1;\r\n sMessage = Expand( 'The holds cube ''%sHoldsCube%'' does not exist so holds (if any) could not be imported. You might want to create it first using mode ''C''.' );\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 );\r\n ProcessQuit;\r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n EndIf;\r\n Else;\r\n\r\n # the file directory (If empty, the error file directory is used. If not existing, an error is returned.)\r\n # this is done by the called Bedrock process\r\n # the file name is simply the Holds cube name with file extension csv\r\n sFileName = sHoldsCube | '.csv';\r\n nRet = ExecuteProcess( '}bedrock.cube.data.import', 'pLogOutput', pLogOutput, 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pCube', sHoldsCube, 'pSrcDir', pDir, 'pSrcFile', sFileName, 'pCubeLogging', 2, 'pFileDelete', 0, 'pSkipInvalidRecords', 0 );\r\n If( nRet <> 0 );\r\n sMessage = Expand( 'Error importing all the holds to the cube ''%sHoldsCube%'' from a flat file.' );\r\n nErrors = 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 );\r\n ProcessQuit;\r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n EndIf;\r\n If( pLogOutput = 1 );\r\n sMessage = Expand( 'All the holds were imported to the cube ''%sHoldsCube%''.' );\r\n LogOutput('INFO', Expand( sMessage ) );\r\n EndIf;\r\n EndIf;\r\n EndIf;\r\n\r\n nCountClients = nCountClients + 1;\r\n End;\r\n\r\n nCountCubes = nCountCubes + 1;\r\nEnd;", "MetadataProcedure": "#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "DataProcedure": "#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "EpilogProcedure": "#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n#################################################################################################\r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n#################################################################################################\r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 );\r\n ProcessQuit;\r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully performed %pMode% for cube ''%pCube%'', with client ''%pGroup%'' and group ''%pGroup%''.' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogOutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) );\r\n EndIf;\r\nEndIf;", @@ -10,18 +10,6 @@ "Type": "None" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pMode", "Prompt": "REQUIRED: Use C / D / R / X / M. See inside process for information. Supported operations for holds cubes: Create, Destroy, Release, Export, Import.", @@ -30,39 +18,57 @@ }, { "Name": "pCube", - "Prompt": "REQUIRED: Treat which Holds cube(s) ? Provide the base cube name(s). Supports a list and wildcards * and ? and keyword MODELCUBES.", + "Prompt": "REQUIRED: Cube name", "Value": "", "Type": "String" }, { "Name": "pClient", - "Prompt": "REQUIRED or used in conjunction with pGroup. Treat the Holds cube(s) of which client(s) ? Supports a list and wildcards * and ? and keyword MYSELF.", + "Prompt": "REQUIRED: or used in conjunction with pGroup. Treat the Holds cube(s) of which client(s) ? Supports a list and wildcards * and ? and keyword MYSELF.", "Value": "", "Type": "String" }, { "Name": "pGroup", - "Prompt": "REQUIRED or used in conjunction with pClient. Treat the Holds cube(s) of which client(s) in which group(s) ? Supports a list and wildcards * and ? and keyword MYGROUPS.", + "Prompt": "REQUIRED: or used in conjunction with pClient. Treat the Holds cube(s) of which client(s) in which group(s) ? Delimited list of groups", "Value": "", "Type": "String" }, { "Name": "pDelim", - "Prompt": "OPTIONAL: delimiter character for the different lists. (default value if blank = '&')", + "Prompt": "OPTIONAL: Delimiter for list parameters (Default = '&')", "Value": "&", "Type": "String" }, { "Name": "pDir", - "Prompt": "OPTIONAL: Directory (will default to error file path)", + "Prompt": "OPTIONAL: File directory (Default = GetProcessErrorFileDirectory)", "Value": "", "Type": "String" }, { "Name": "pSkipNonExistentHoldsCubes", - "Prompt": "OPTIONAL: When using lists and wildcards, it can lead to non-existent holds cubes. 1=Silently ignore these. Default=0.", + "Prompt": "OPTIONAL: When using lists and wildcards, it can lead to non-existent holds cubes (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [], diff --git a/bedrock_processes_json/}bedrock.cube.data.import.json b/bedrock_processes_json/}bedrock.cube.data.import.json index 8eaa9ba..45be8a0 100644 --- a/bedrock_processes_json/}bedrock.cube.data.import.json +++ b/bedrock_processes_json/}bedrock.cube.data.import.json @@ -1,11 +1,11 @@ { "Name": "}bedrock.cube.data.import", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.cube.data.import', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pCube', '', 'pSrcDir', '', 'pSrcFile', '',\r\n \t'pDim', '', 'pSrcEle', '', 'pTgtEle', '',\r\n \t'pTitleRows', 1, 'pDelim', ',', 'pQuote', '\"', 'pDecimalSeparator', '.', 'pThousandSeparator', ',',\r\n \t'pCumulate', 0, 'pCubeLogging', 0, 'pSandbox', pSandbox, 'pZeroFilter', 0, \r\n \t'pMappingToNewDims','', 'pDimDelim', '&', 'pEleStartDelim', '\u00a6', 'pEleDelim', '+', 'pFileDelete', 0, 'pSkipInvalidRecords', 0\r\n );\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will load a csv text file to the target cube.\r\n\r\n# Use case: Intended for development/prototyping or in Production environment.\r\n#1/ Import data from another TM1 model.\r\n#2/ To eliminate possibility of locking it is sometimes better to export and import when needing to copy data from one cube to another.\r\n\r\n# Note:\r\n# Naturally, a valid target cube name (pCube) is mandatory otherwise the process will abort.\r\n# Element mapping for new dimensions (pMappingToNewDims ) is also required when the target cube has more dimensions than the source, otherwise the process will abort.\r\n# The default input path is the same as the error file path if not specified.\r\n# If the file name is left blank, the process will look for a file called pCube_Export.csv.\r\n\r\n# Format:\r\n# The assumed file format is as per standard CMA export:\r\n# - v1 specIfies cube name, subsequent fields specify cube address ( individual element names ).\r\n# - vN specIfies cell data value to load. With provision for files with header rows.\r\n# Format of filter row for Zero out:\r\n# - v1 specifies source cube name\r\n# - v2 must be equal to \"Filter\".\r\n# - v3 specifies the filter to be used to zero out. Please note if target cube has additional dimensions this is the final filter used if pMappingToNewDims is not speficied. All the elements in additional dimensions will be cleaned \r\n# - v4 specifies the dimension delimiter used in filter\r\n# - v5 specifies the element start delimiter used in filter\r\n# - v6 specifies the element delimiter used in filter\r\n# Note about the Zero out:\r\n# if pMappingToNewDims parameter is specified, it will be concatenated to the filter in the file to restict the cube slice to be zeroed out. Similarly, if pDim is specified the source element is substituted with the targed one, sould it be in the filter string\r\n# in both cases the delimiters in the source file must match the delimiters passed in parameters of this process.\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pSrcDir:%pSrcDir%, pSrcFile:%pSrcFile%, pCube:%pCube%, pDim:%pDim%, pSrcEle:%pSrcEle%, pTgtEle:%pTgtEle%, pTitleRows:%pTitleRows%, pDelim:%pDelim%, pQuote:%pQuote%, pCumulate:%pCumulate%, pCubeLogging:%pCubeLogging%, pSandbox:%pSandbox%, pZeroFilter:%pZeroFilter%, pMappingToNewDims:%pMappingToNewDims%, pDimDelim:%pDimDelim%, pEleStartDelim:%pEleStartDelim%, pEleDelim:%pEleDelim%.'; \r\ncMinLenASCIICode = 2;\r\ncMaxLenASCIICode = 3;\r\n\r\npDelimiter = TRIM(pDelim);\r\nsDelimDim = TRIM(pDimDelim);\r\nsElementStartDelim = TRIM(pElEStartDelim);\r\nsDelimElem = TRIM(pEleDelim);\r\npDecimalSeparator = TRIM(pDecimalSeparator);\r\npThousandSeparator = TRIM(pThousandSeparator);\r\n\r\n## LogOutput parameters\r\nIf( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\nnRecordProcessedCount = 0;\r\nnRecordPostedCount = 0;\r\nnErrors = 0;\r\n\r\n\r\n### Validate Parameters ###\r\npSourceDir = TRIM(pSrcDir);\r\npSourceFile = TRIM(pSrcFile);\r\n\r\n## check operating system\r\nIf( SubSt( GetProcessErrorFileDirectory, 2, 1 ) @= ':' );\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nElseIf( Scan( '/', GetProcessErrorFileDirectory ) > 0 );\r\n sOS = 'Linux';\r\n sOSDelim = '/';\r\nElse;\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nEndIf;\r\n\r\n# Validate source directory\r\nIf(Trim( pSourceDir ) @= '' );\r\n pSourceDir = GetProcessErrorFileDirectory;\r\nEndIf;\r\n\r\nIf( SubSt( pSourceDir, Long( pSourceDir ), 1 ) @= sOSDelim );\r\n pSourceDir = SubSt( pSourceDir, 1, Long( pSourceDir ) - 1 );\r\nEndIf;\r\n\r\nIf( FileExists( pSourceDir ) = 0 );\r\n sMessage = 'Invalid source directory specified: folder does not exist.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nIf( pSourceFile @= '' );\r\n pSourceFile = Expand('%pCube%_Export.csv');\r\nEndIf;\r\n\r\nsFile = pSourceDir | sOSDelim | pSourceFile;\r\n# Validate source file\r\nIf( FileExists( sFile ) = 0 );\r\n sMessage = 'Invalid source file specified: file does not exist in directory:' | sFile;\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Automatic file deletion\r\nIf( pFileDelete <> 1 );\r\n pFileDelete = 0;\r\nEndIf;\r\n\r\n# Skip invalid records\r\nIf( pSkipInvalidRecords <> 1 );\r\n pSkipInvalidRecords = 0;\r\nEndIf;\r\n\r\n## Validate cube\r\nIf( Trim( pCube ) @= '' );\r\n sMessage = 'No target cube specified.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( CubeExists( pCube ) = 0 );\r\n sMessage = 'Invalid target cube specified: ' | pCube;\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate file delimiter & quote character\r\nIf( pDelimiter @= '' );\r\n pDelimiter = ',';\r\nElse;\r\n # If length of pDelimiter is between 2 and 3 chars and each of them is decimal digit, then the pDelimiter is entered as ASCII code\r\n If ( LONG(pDelimiter) <= cMaxLenASCIICode & LONG(pDelimiter) >= cMinLenASCIICode );\r\n nValid = 1;\r\n nChar = 1;\r\n While ( nChar <= LONG(pDelimiter) );\r\n If( CODE( pDelimiter, nChar ) < CODE( '0', 1 ) % CODE( pDelimiter, nChar ) > CODE( '9', 1 ) );\r\n nValid = 0;\r\n Break;\r\n EndIf;\r\n nChar = nChar + 1;\r\n End;\r\n If ( nValid<>0 );\r\n pDelimiter=CHAR(StringToNumber( pDelimiter ));\r\n EndIf;\r\n EndIf;\r\nEndIf;\r\n\r\nIf( pQuote @= '' );\r\n ## Use no quote character \r\nElse;\r\n # If length of pQuote is between 2 and 3 chars and each of them is decimal digit, then the pQuote is entered as ASCII code\r\n If ( LONG(pQuote) <= cMaxLenASCIICode & LONG(pQuote) >= cMinLenASCIICode);\r\n nValid = 1;\r\n nChar = 1;\r\n While ( nChar <= LONG(pQuote) );\r\n If( CODE( pQuote, nChar ) < CODE( '0', 1 ) % CODE( pQuote, nChar ) > CODE( '9', 1 ) );\r\n nValid = 0;\r\n Break;\r\n EndIf;\r\n nChar = nChar + 1;\r\n End;\r\n If ( nValid<>0 );\r\n pQuote=CHAR(StringToNumber( pQuote ));\r\n EndIf;\r\n EndIf;\r\nEndIf;\r\n\r\nIf ( LONG(pDecimalSeparator) <= cMaxLenASCIICode & LONG(pDecimalSeparator) >= cMinLenASCIICode );\r\n nValid = 0;\r\n nChar = 1;\r\n While ( nChar <= LONG(pDecimalSeparator) );\r\n If( CODE( pDecimalSeparator, nChar ) >= CODE( '0', 1 ) & CODE( pDecimalSeparator, nChar ) <= CODE( '9', 1 ) );\r\n nValid = 1;\r\n Else;\r\n nValid = 0;\r\n Break;\r\n EndIf;\r\n nChar = nChar + 1;\r\n End;\r\n If ( nValid<>0 );\r\n pDecimalSeparator = CHAR(StringToNumber( pDecimalSeparator ));\r\n Else;\r\n pDecimalSeparator = SubSt( Trim( pDecimalSeparator ), 1, 1 );\r\n EndIf;\r\nEndIf;\r\nsDecimalSeparator = pDecimalSeparator;\r\n\r\nIf ( LONG(pThousandSeparator) <= cMaxLenASCIICode & LONG(pThousandSeparator) >= cMinLenASCIICode );\r\n nValid = 0;\r\n nChar = 1;\r\n While ( nChar <= LONG(pThousandSeparator) );\r\n If( CODE( pThousandSeparator, nChar ) >= CODE( '0', 1 ) & CODE( pThousandSeparator, nChar ) <= CODE( '9', 1 ) );\r\n nValid = 1;\r\n Else;\r\n nValid = 0;\r\n Break;\r\n EndIf;\r\n nChar = nChar + 1;\r\n End;\r\n If ( nValid<>0 );\r\n pThousandSeparator = CHAR(StringToNumber( pThousandSeparator ));\r\n Else;\r\n pThousandSeparator = SubSt( Trim( pThousandSeparator ), 1, 1 );\r\n EndIf;\r\nEndIf;\r\nsThousandSeparator = pThousandSeparator;\r\n\r\n# Validate Sandbox\r\nIf( TRIM( pSandbox ) @<> '' );\r\n If( ServerSandboxExists( pSandbox ) = 0 );\r\n SetUseActiveSandboxProperty( 0 );\r\n nErrors = nErrors + 1;\r\n sMessage = Expand('Sandbox %pSandbox% is invalid for the current user.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n Else;\r\n ServerActiveSandboxSet( pSandbox );\r\n SetUseActiveSandboxProperty( 1 );\r\n EndIf;\r\nElse;\r\n SetUseActiveSandboxProperty( 0 );\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n## Validate Dimension\r\npDimension = TRIM( pDim);\r\npSourceElement = TRIM(pSrcEle);\r\npTargetElement = TRIM(pTgtEle);\r\n\r\nIf( pDimension @<> '');\r\n \r\n If( DimensionExists( pDimension ) = 0 );\r\n sMessage = 'Invalid dimension specified: ' | pDimension;\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n EndIf;\r\n\r\n # Validate Source Element\r\n If( pSourceElement @= '' );\r\n sMessage = 'Error: The Source Element parameter is blank.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n EndIf;\r\n\r\n If( DimIx( pDimension, pSourceElement ) = 0 );\r\n sMessage = 'Invalid source element, ' | pSourceElement | ' specified for ' | pDimension | ' dimension.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n EndIf;\r\n sSourceElement = DimensionElementPrincipalName( pDimension, pSourceElement);\r\n\r\n # Validate Target Element\r\n If( pTargetElement @= '' );\r\n sMessage = 'Error: The Target Element parameter is blank.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n ElseIf( DimIx( pDimension, pTargetElement ) = 0 );\r\n sMessage = 'Invalid target element, ' | pTargetElement | ' specified for ' | pDimension | ' dimension.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n EndIf;\r\n sTargetElement = DimensionElementPrincipalName( pDimension, pTargetElement);\r\n\r\nENDIF;\r\n\r\n## Validate delimiter\r\n\r\nIf( pDelimiter @= '' );\r\n sMessage = 'Error: The file delimiter parameter is blank.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( Long( pDelimiter ) > 1 );\r\n sMessage = 'Invalid delimiter specified: ' | pDelimiter | ' field delimiter must be single character or 2-3 symbols number representing ASCII code.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n## Validate quote character\r\nIf( Long( pQuote ) > 1 );\r\n sMessage = 'Invalid string qualIfier: ' | pQuote | ' quote character must be single character or empty string or 2-3 symbols number representing ASCII code.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### Determine number of dims in target cube ###\r\nnCount = 1;\r\nnSubstututeDimensionIndex = 0;\r\nWhile( \r\nTabDim( pCube, nCount ) @<> '' );\r\n sDimension = TabDim( pCube, nCount );\r\n If( sDimension @= pDimension );\r\n nSubstututeDimensionIndex = nCount;\r\n EndIf;\r\n nCount = nCount + 1;\r\nEnd;\r\nnDimensionCount = nCount - 1;\r\n\r\n## Validate the dimension is part of the cube.\r\nIf( pDimension @= '');\r\n ## CONTINUE;\r\nELSEIf( nSubstututeDimensionIndex = 0 );\r\n sMessage = 'Specified dimension: ' | pDimension | ' is not a component of the cube: ' | pCube;\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nENDIF;\r\n\r\n ## Default filter delimiters\r\n If( pDimDelim @= '' );\r\n pDimDelim = '&';\r\n EndIf;\r\n If( pEleStartDelim@= '' );\r\n pEleStartDelim= '\u00a6';\r\n EndIf;\r\n If( pEleDelim @= '' );\r\n pEleDelim = '+';\r\n EndIf;\r\n \r\n\r\nIf( nDimensionCount > 27 );\r\n sMessage = 'Cube has too many dimensions: ' | pCube | ' max 27 dimensions.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### Determine dimensions in target cube, we need to know this to test cell type before loading ###\r\nsDim1 = TabDim( pCube, 1 );\r\nsDim2 = TabDim( pCube, 2 );\r\nsDim3 = TabDim( pCube, 3 );\r\nsDim4 = TabDim( pCube, 4 );\r\nsDim5 = TabDim( pCube, 5 );\r\nsDim6 = TabDim( pCube, 6 );\r\nsDim7 = TabDim( pCube, 7 );\r\nsDim8 = TabDim( pCube, 8 );\r\nsDim9 = TabDim( pCube, 9 );\r\nsDim10 = TabDim( pCube, 10 );\r\nsDim11 = TabDim( pCube, 11 );\r\nsDim12 = TabDim( pCube, 12 );\r\nsDim13 = TabDim( pCube, 13 );\r\nsDim14 = TabDim( pCube, 14 );\r\nsDim15 = TabDim( pCube, 15 );\r\nsDim16 = TabDim( pCube, 16 );\r\nsDim17 = TabDim( pCube, 17 );\r\nsDim18 = TabDim( pCube, 18 );\r\nsDim19 = TabDim( pCube, 19 );\r\nsDim20 = TabDim( pCube, 20 );\r\nsDim21 = TabDim( pCube, 21 );\r\nsDim22 = TabDim( pCube, 22 );\r\nsDim23 = TabDim( pCube, 23 );\r\nsDim24 = TabDim( pCube, 24 );\r\nsDim25 = TabDim( pCube, 25 );\r\nsDim26 = TabDim( pCube, 26 );\r\nsDim27 = TabDim( pCube, 27 );\r\n\r\n### Placeholders for mappped dimensions and for new dimensions\r\n\r\nnMappedDim1 = 0;\tsMappedV1 = '';\t\tnNewDim1 = 0;\t sNewV1 = '';\r\nnMappedDim2 = 0;\tsMappedV2 = '';\t\tnNewDim2 = 0;\t sNewV2 = '';\r\nnMappedDim3 = 0;\tsMappedV3 = '';\t\tnNewDim3 = 0;\t sNewV3 = '';\r\nnMappedDim4 = 0;\tsMappedV4 = '';\t\tnNewDim4 = 0;\t sNewV4 = '';\r\nnMappedDim5 = 0;\tsMappedV5 = '';\t\tnNewDim5 = 0;\t sNewV5 = '';\r\nnMappedDim6 = 0;\tsMappedV6 = '';\t\tnNewDim6 = 0;\t sNewV6 = '';\r\nnMappedDim7 = 0;\tsMappedV7 = '';\t\tnNewDim7 = 0;\t sNewV7 = '';\r\nnMappedDim8 = 0;\tsMappedV8 = '';\t\tnNewDim8 = 0;\t sNewV8 = '';\r\nnMappedDim9 = 0;\tsMappedV9 = '';\t\tnNewDim9 = 0;\t sNewV9 = '';\r\nnMappedDim10 = 0;\tsMappedV10 = '';\tnNewDim10 = 0;\tsNewV10 = '';\r\nnMappedDim11 = 0;\tsMappedV11 = '';\tnNewDim11 = 0;\tsNewV11 = '';\r\nnMappedDim12 = 0;\tsMappedV12 = '';\tnNewDim12 = 0;\tsNewV12 = '';\r\nnMappedDim13 = 0;\tsMappedV13 = '';\tnNewDim13 = 0;\tsNewV13 = '';\r\nnMappedDim14 = 0;\tsMappedV14 = '';\tnNewDim14 = 0;\tsNewV14 = '';\r\nnMappedDim15 = 0;\tsMappedV15 = '';\tnNewDim15 = 0;\tsNewV15 = '';\r\nnMappedDim16 = 0;\tsMappedV16 = '';\tnNewDim16 = 0;\tsNewV16 = '';\r\nnMappedDim17 = 0;\tsMappedV17 = '';\tnNewDim17 = 0;\tsNewV17 = '';\r\nnMappedDim18 = 0;\tsMappedV18 = '';\tnNewDim18 = 0;\tsNewV18 = '';\r\nnMappedDim19 = 0;\tsMappedV19 = '';\tnNewDim19 = 0;\tsNewV19 = '';\r\nnMappedDim20 = 0;\tsMappedV20 = '';\tnNewDim20 = 0;\tsNewV20 = '';\r\nnMappedDim21 = 0;\tsMappedV21 = '';\tnNewDim21 = 0;\tsNewV21 = '';\r\nnMappedDim22 = 0;\tsMappedV22 = '';\tnNewDim22 = 0;\tsNewV22 = '';\r\nnMappedDim23 = 0;\tsMappedV23 = '';\tnNewDim23 = 0;\tsNewV23 = '';\r\nnMappedDim24 = 0;\tsMappedV24 = '';\tnNewDim24 = 0;\tsNewV24 = '';\r\nnMappedDim25 = 0;\tsMappedV25 = '';\tnNewDim25 = 0;\tsNewV25 = '';\r\nnMappedDim26 = 0;\tsMappedV26 = '';\tnNewDim26 = 0;\tsNewV26 = '';\r\nnMappedDim27 = 0;\tsMappedV27 = '';\tnNewDim27 = 0;\tsNewV27 = '';\r\n sMappedV28 = '';\r\n\r\n###########################################\r\n### SPLIT MAPPING TO NEW DIMS PARAMETER ###\r\n###########################################\r\n\r\nnTargetCubeDimensionCount = nDimensionCount;\r\n\r\nsElementMapping = TRIM( pMappingToNewDims );\r\nnChar = 1;\r\nnCharCount = LONG( sElementMapping );\r\n\r\nsTargetFilter = '';\r\nsWord = '';\r\nsLastDelim = '';\r\nnIndex = 1;\r\n\r\n# Add a trailing element delimiter so that the last element is picked up\r\nIf( nCharCount > 0 );\r\n sElementMapping = sElementMapping | sDelimDim;\r\n nCharCount = nCharCount + LONG(sDelimDim);\r\nEndIf;\r\n\r\nWHILE (nChar <= nCharCount);\r\n sChar = SUBST( sElementMapping, nChar, 1);\r\n\r\n # Used for delimiters, required for multiple character delimiters\r\n sDelim = '';\r\n nAddExtra = 0;\r\n\r\n # Ignore spaces\r\n IF (TRIM(sChar) @<> '' );\r\n\r\n ### Dimension Name ###\r\n\r\n # If the delimiter is more than 1 character peek ahead the same amount\r\n # Ignore the first character\r\n sDelim = sChar;\r\n nCount = LONG(sElementStartDelim) - 1;\r\n If( nCount > 0 & nChar + nCount <= nCharCount );\r\n # Add the extra characters\r\n sDelim = sDelim | SUBST( sElementMapping, nChar + 1, nCount);\r\n # Move to the end of the delimter\r\n\r\n EndIf;\r\n\r\n If( sDelim @= sElementStartDelim );\r\n nAddExtra = nCount;\r\n sChar = sDelim;\r\n\r\n If( sLastDelim @<> '' & sLastDelim @<> sDelimDim );\r\n sMessage = 'In pMappingToNewDims the name of a dimension must follow a dimension delimiter (' | sDelimDim | ')';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n #ProcessError();\r\n EndIf;\r\n\r\n # Found a dimension\r\n sDimension = sWord;\r\n\r\n If( DimensionExists( sDimension ) = 0 );\r\n # The dimension does not exist in the model. Cancel process\r\n sMessage = 'In pMappingToNewDims - Dimension: ' | sDimension | ' does not exist';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n #ProcessError();\r\n EndIf;\r\n \r\n ### Determine the dimension is a member of the cube ###\r\n nMapCount = 1;\r\n nMapDimensionIndex = 0;\r\n While( TabDim( pCube, nMapCount ) @<> '' );\r\n sMapCubeDimName = TabDim( pCube, nMapCount );\r\n If( sDimension @= sMapCubeDimName );\r\n nMapDimensionIndex = nMapCount;\r\n EndIf;\r\n nMapCount = nMapCount + 1;\r\n End;\r\n\r\n If( nMapDimensionIndex = 0 );\r\n # The dimension does not exist in the cube. Cancel process\r\n sMessage = 'Dimension: ' | sDimension | ' is not a member of: '| pCube | ' cube.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n EndIf;\r\n\r\n # Find the index of the dimension is in the Target cube\r\n nTargetIndexCounter = 1;\r\n\r\n WHILE(nTargetIndexCounter <= nTargetCubeDimensionCount );\r\n sNthDimension = TabDim( pCube, nTargetIndexCounter );\r\n\r\n If(sDimension @= sNthDimension);\r\n nTargetIndex = nTargetIndexCounter;\r\n nTargetIndexCounter = 1000;\r\n EndIf;\r\n\r\n nTargetIndexCounter = nTargetIndexCounter + 1;\r\n END;\r\n \r\n #Add to the Target filter\r\n If(sTargetFilter@='');\r\n sTargetFilter=sDimension; \r\n Else;\r\n sTargetFilter=sTargetFilter|sDelimDim|sDimension;\r\n Endif; \r\n \r\n sLastDelim = sChar;\r\n # Clear the word\r\n sWord = '';\r\n\r\n Else;\r\n\r\n # Reset extra chars\r\n nAddExtra = 0;\r\n\r\n ### Check both dim delimiter and element delimiter ###\r\n nIsDelimiter = 0;\r\n\r\n ## Check dimension delimiter first\r\n # If the delimiter is more than 1 character peek ahead the same amount\r\n # Ignore the first character\r\n sDelim = sChar;\r\n nCount = LONG(sDelimDim) - 1;\r\n If( nCount > 0 & nChar + nCount <= nCharCount );\r\n # Add the extra characters\r\n sDelim = sDelim | SUBST( sElementMapping, nChar + 1, nCount);\r\n # Move to the end of the delimter\r\n \r\n EndIf;\r\n\r\n If( sDelim @= sDelimDim );\r\n nIsDelimiter = 1;\r\n sChar = sDelim;\r\n nAddExtra = nCount;\r\n EndIf;\r\n\r\n If ( nIsDelimiter = 1 );\r\n\r\n If( sLastDelim @= '' % sLastDelim @= sDelimDim );\r\n sMessage = 'In pMappingToNewDims - an element delimiter must follow a dimension name: ' | sChar | ' (' | NumberToString(nChar) | ')';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n #ProcessError();\r\n EndIf;\r\n\r\n # an element has been found\r\n sElement = sWord;\r\n\r\n If( DimIx( sDimension, sElement ) = 0 );\r\n # The element does not exist in the dimension. Cancel process\r\n sMessage = 'In pMappingToNewDims - Element: ' | sElement | ' in dimension ' | sDimension | ' does not exist';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n #ProcessError();\r\n EndIf;\r\n\r\n # Allow consolidations only if pSuppressConsol is set to 0\r\n\r\n If ( DTYPE( sDimension, sElement) @= 'C' );\r\n sMessage = Expand( 'In pMappingToNewDims - Target element: %sElement% for dimension %sDimension% is consolidated' );\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n #ProcessError();\r\n Endif; \r\n \r\n\r\n # Add the element to the source or target depending on whether it's the first or the second element\r\n # Get principal name\r\n # in case source element and this element are using different aliases\r\n\r\n sElement = DimensionElementPrincipalName(sDimension,sElement);\r\n\r\n ### Update the variable for InputElement Target Dim ######################################\r\n If(nTargetIndex = 1);\r\n nNewDim1 = 1;\r\n sNewV1 = sElement;\r\n ElseIf(nTargetIndex = 2);\r\n nNewDim2 = 1;\r\n sNewV2 = sElement;\r\n ElseIf(nTargetIndex = 3);\r\n nNewDim3 = 1;\r\n sNewV3 = sElement;\r\n ElseIf(nTargetIndex = 4);\r\n nNewDim4 = 1;\r\n sNewV4 = sElement;\r\n ElseIf(nTargetIndex = 5);\r\n nNewDim5 = 1;\r\n sNewV5 = sElement;\r\n ElseIf(nTargetIndex = 6);\r\n nNewDim6 = 1;\r\n sNewV6 = sElement;\r\n ElseIf(nTargetIndex = 7);\r\n nNewDim7 = 1;\r\n sNewV7 = sElement;\r\n ElseIf(nTargetIndex = 8);\r\n nNewDim8 = 1;\r\n sNewV8 = sElement;\r\n ElseIf(nTargetIndex = 9);\r\n nNewDim9 = 1;\r\n sNewV9 = sElement;\r\n ElseIf(nTargetIndex = 10);\r\n nNewDim10 = 1;\r\n sNewV10 = sElement;\r\n ElseIf(nTargetIndex = 11);\r\n nNewDim11 = 1;\r\n sNewV11 = sElement;\r\n ElseIf(nTargetIndex = 12);\r\n nNewDim12 = 1;\r\n sNewV12 = sElement;\r\n ElseIf(nTargetIndex = 13);\r\n nNewDim13 = 1;\r\n sNewV13 = sElement;\r\n ElseIf(nTargetIndex = 14);\r\n nNewDim14 = 1;\r\n sNewV14 = sElement;\r\n ElseIf(nTargetIndex = 15);\r\n nNewDim15 = 1;\r\n sNewV15 = sElement;\r\n ElseIf(nTargetIndex = 16);\r\n nNewDim16 = 1;\r\n sNewV16 = sElement;\r\n ElseIf(nTargetIndex = 17);\r\n nNewDim17 = 1;\r\n sNewV17 = sElement;\r\n ElseIf(nTargetIndex = 18);\r\n nNewDim18 = 1;\r\n sNewV18 = sElement;\r\n ElseIf(nTargetIndex = 19);\r\n nNewDim19 = 1;\r\n sNewV19 = sElement;\r\n ElseIf(nTargetIndex = 20);\r\n nNewDim20 = 1;\r\n sNewV20 = sElement;\r\n ElseIf(nTargetIndex = 21);\r\n nNewDim21 = 1;\r\n sNewV21 = sElement;\r\n ElseIf(nTargetIndex = 22);\r\n nNewDim22 = 1;\r\n sNewV22 = sElement;\r\n ElseIf(nTargetIndex = 23);\r\n nNewDim23 = 1;\r\n sNewV23 = sElement;\r\n ElseIf(nTargetIndex = 24);\r\n nNewDim24 = 1;\r\n sNewV24 = sElement;\r\n ElseIf(nTargetIndex = 25);\r\n nNewDim25 = 1;\r\n sNewV25 = sElement;\r\n ElseIf(nTargetIndex = 26);\r\n nNewDim26 = 1;\r\n sNewV26 = sElement;\r\n ElseIf(nTargetIndex = 27);\r\n nNewDim27 = 1;\r\n sNewV27 = sElement;\r\n EndIf;\r\n\r\n #Add to the Target filter - no need to manage element separators, since just one target element is possible in mapping\r\n sTargetFilter=sTargetFilter|sElementStartDelim|sElement;\r\n \r\n # Clear the word\r\n sWord = '';\r\n sLastDelim = sChar;\r\n \r\n Else;\r\n sWord = sWord | sChar;\r\n EndIf;\r\n\r\n EndIf;\r\n\r\n EndIf;\r\n\r\n nChar = nChar + nAddExtra + 1;\r\n\r\nEND;\r\n\r\n\r\n###########################################\r\n#Region ### MAPPING Target DIMENSIONS #####\r\n\r\n## Source index starting from 2, since first columns holds the export cube name\r\nnSourceIndex = 2;\r\nnTargetIndex = 1;\r\nWHILE(TabDim( pCube, nTargetIndex ) @<> '');\r\n sTargetDim = TabDim( pCube, nTargetIndex );\r\n \r\n If(nTargetIndex = 1);\r\n If( nNewDim1 = 0 );\r\n nMappedDim1 = 1;\r\n sMappedV1 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\n Else;\r\n \r\n EndIf;\r\n ElseIf(nTargetIndex = 2 & nNewDim2 = 0);\r\n nMappedDim2 = 1;\r\n sMappedV2 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\n ElseIf(nTargetIndex = 3 & nNewDim3 = 0);\r\n nMappedDim3 = 1;\r\n sMappedV3 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\n ElseIf(nTargetIndex = 4 & nNewDim4 = 0);\r\n nMappedDim4 = 1;\r\n sMappedV4 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\n ElseIf(nTargetIndex = 5 & nNewDim5 = 0);\r\n nMappedDim5 = 1;\r\n sMappedV5 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\n ElseIf(nTargetIndex = 6 & nNewDim6 = 0);\r\n nMappedDim6 = 1;\r\n sMappedV6 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\n ElseIf(nTargetIndex = 7 & nNewDim7 = 0);\r\n nMappedDim7 = 1;\r\n sMappedV7 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\n ElseIf(nTargetIndex = 8 & nNewDim8 = 0);\r\n nMappedDim8 = 1;\r\n sMappedV8 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\n ElseIf(nTargetIndex = 9 & nNewDim9 = 0);\r\n nMappedDim9 = 1;\r\n sMappedV9 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\n ElseIf(nTargetIndex = 10 & nNewDim10 = 0);\r\n nMappedDim10 = 1;\r\n sMappedV10 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\n ElseIf(nTargetIndex = 11 & nNewDim11 = 0);\r\n nMappedDim11 = 1;\r\n sMappedV11 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\n ElseIf(nTargetIndex = 12 & nNewDim12 = 0 );\r\n nMappedDim12 = 1;\r\n sMappedV12 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\n ElseIf(nTargetIndex = 13 & nNewDim13 = 0 );\r\n nMappedDim13 = 1;\r\n sMappedV13 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\n ElseIf(nTargetIndex = 14 & nNewDim14 = 0 );\r\n nMappedDim14 = 1;\r\n sMappedV14 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\n ElseIf(nTargetIndex = 15 & nNewDim15 = 0 );\r\n nMappedDim15 = 1;\r\n sMappedV15 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\n ElseIf(nTargetIndex = 16 & nNewDim16 = 0 );\r\n nMappedDim16 = 1;\r\n sMappedV16 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\n ElseIf(nTargetIndex = 17 & nNewDim17 = 0 );\r\n nMappedDim17 = 1;\r\n sMappedV17 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\n ElseIf(nTargetIndex = 18 & nNewDim18 = 0 );\r\n nMappedDim18 = 1;\r\n sMappedV18 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\n ElseIf(nTargetIndex = 19 & nNewDim19 = 0 );\r\n nMappedDim19 = 1;\r\n sMappedV19 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\n ElseIf(nTargetIndex = 20 & nNewDim20 = 0 );\r\n nMappedDim20 = 1;\r\n sMappedV20 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\n ElseIf(nTargetIndex = 21 & nNewDim21 = 0 );\r\n nMappedDim21 = 1;\r\n sMappedV21 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\n ElseIf(nTargetIndex = 22 & nNewDim22 = 0 );\r\n nMappedDim22 = 1;\r\n sMappedV22 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\n ElseIf(nTargetIndex = 23 & nNewDim23 = 0 );\r\n nMappedDim23 = 1;\r\n sMappedV23 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\n ElseIf(nTargetIndex = 24 & nNewDim24 = 0 );\r\n nMappedDim24 = 1;\r\n sMappedV24 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\n ElseIf(nTargetIndex = 25 & nNewDim25 = 0 );\r\n nMappedDim25 = 1;\r\n sMappedV25 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\n ElseIf(nTargetIndex = 26 & nNewDim26 = 0 );\r\n nMappedDim26 = 1;\r\n sMappedV26 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\n ElseIf(nTargetIndex = 27 & nNewDim27 = 0 );\r\n nMappedDim27 = 1;\r\n sMappedV27 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\n EndIf;\r\n\r\n nTargetIndex = nTargetIndex + 1;\r\n\r\nEND;\r\n\r\n# The last variable in the data source holds the values\r\n# which need to be mapped to the last variable in the target\r\n\r\nIf(nTargetIndex = 1 & nNewDim1 = 0);\r\n nMappedDim1 = 1;\r\n sMappedV1 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\nElseIf(nTargetIndex = 2 & nNewDim2 = 0);\r\n nMappedDim2 = 1;\r\n sMappedV2 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\nElseIf(nTargetIndex = 3 & nNewDim3 = 0);\r\n nMappedDim3 = 1;\r\n sMappedV3 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\nElseIf(nTargetIndex = 4 & nNewDim4 = 0);\r\n nMappedDim4 = 1;\r\n sMappedV4 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\nElseIf(nTargetIndex = 5 & nNewDim5 = 0);\r\n nMappedDim5 = 1;\r\n sMappedV5 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\nElseIf(nTargetIndex = 6 & nNewDim6 = 0);\r\n nMappedDim6 = 1;\r\n sMappedV6 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\nElseIf(nTargetIndex = 7 & nNewDim7 = 0);\r\n nMappedDim7 = 1;\r\n sMappedV7 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\nElseIf(nTargetIndex = 8 & nNewDim8 = 0);\r\n nMappedDim8 = 1;\r\n sMappedV8 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\nElseIf(nTargetIndex = 9 & nNewDim9 = 0);\r\n nMappedDim9 = 1;\r\n sMappedV9 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\nElseIf(nTargetIndex = 10 & nNewDim10 = 0);\r\n nMappedDim10 = 1;\r\n sMappedV10 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\nElseIf(nTargetIndex = 11 & nNewDim11 = 0);\r\n nMappedDim11 = 1;\r\n sMappedV11 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\nElseIf(nTargetIndex = 12);\r\n nMappedDim12 = 1;\r\n sMappedV12 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\nElseIf(nTargetIndex = 13);\r\n nMappedDim13 = 1;\r\n sMappedV13 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\nElseIf(nTargetIndex = 14);\r\n nMappedDim14 = 1;\r\n sMappedV14 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\nElseIf(nTargetIndex = 15);\r\n nMappedDim15 = 1;\r\n sMappedV15 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\nElseIf(nTargetIndex = 16);\r\n nMappedDim16 = 1;\r\n sMappedV16 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\nElseIf(nTargetIndex = 17);\r\n nMappedDim17 = 1;\r\n sMappedV17 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\nElseIf(nTargetIndex = 18);\r\n nMappedDim18 = 1;\r\n sMappedV18 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\nElseIf(nTargetIndex = 19);\r\n nMappedDim19 = 1;\r\n sMappedV19 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\nElseIf(nTargetIndex = 20);\r\n nMappedDim20 = 1;\r\n sMappedV20 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\nElseIf(nTargetIndex = 21);\r\n nMappedDim21 = 1;\r\n sMappedV21 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\nElseIf(nTargetIndex = 22);\r\n nMappedDim22 = 1;\r\n sMappedV22 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\nElseIf(nTargetIndex = 23);\r\n nMappedDim23 = 1;\r\n sMappedV23 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\nElseIf(nTargetIndex = 24);\r\n nMappedDim24 = 1;\r\n sMappedV24 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\nElseIf(nTargetIndex = 25);\r\n nMappedDim25 = 1;\r\n sMappedV25 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\nElseIf(nTargetIndex = 26);\r\n nMappedDim26 = 1;\r\n sMappedV26 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\nElseIf(nTargetIndex = 27);\r\n nMappedDim27 = 1;\r\n sMappedV27 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\n\r\n# a cube with 27 dimensions uses V28 to hold the values\r\nElseIf(nTargetIndex = 28);\r\n nMappedDim28 = 1;\r\n sMapped28 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\nEndIf;\r\n\r\n# Check that an input element or variable has been specified for all dimensions in the target cube\r\n\r\nnIndexInTarget = 1;\r\nWHILE(nIndexInTarget <= nTargetCubeDimensionCount);\r\n \r\n sMapped = Expand('%nMappedDim'| NumberToString(nIndexInTarget) |'%'); \r\n sMapped = Subst( sMapped , Scan( '.' , sMapped )-1 , 99);\r\n nMapped = StringToNumber( Trim( sMapped ) );\r\n sNew = Expand('%nNewDim'| NumberToString(nIndexInTarget) |'%'); \r\n sNew = Subst( sNew , Scan( '.' , sNew )-1 , 99);\r\n nNew = StringToNumber( Trim( sNew ) );\r\n \r\n If(nMapped = 0 & nNew = 0 );\r\n # there's no input element and this dimension is not in the source\r\n nErrors = nErrors + 1;\r\n sTargetDimName = TabDim( pCube, nIndexInTarget );\r\n sMessage = 'Dimension ' | sTargetDimName | ' is missing an input element in pMappingToNewDims';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n EndIf;\r\n \r\n nIndexInTarget = nIndexInTarget + 1;\r\nEND;\r\n#EndRegion ### MAPPING Target DIMENSIONS #####\r\n##############################################\r\n\r\n### Assign Datasource ###\r\nDataSourceType = 'CHARACTERDELIMITED';\r\nDatasourceNameForServer = sFile;\r\nDatasourceNameForClient = sFile;\r\nDatasourceASCIIHeaderRecords = pTitleRows;\r\nDatasourceASCIIDelimiter = pDelimiter;\r\nDatasourceASCIIQuoteCharacter = pQuote;\r\nSetInputCharacterSet (pCharacterSet);\r\n\r\n### End Prolog ###", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.cube.data.import', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pCube', '', 'pSrcDir', '', 'pSrcFile', '',\r\n \t'pDim', '', 'pSrcEle', '', 'pTgtEle', '',\r\n \t'pTitleRows', 1, 'pDelim', ',', 'pQuote', '\"', 'pDecimalSeparator', '.', 'pThousandSeparator', ',',\r\n \t'pCumulate', 0, 'pCubeLogging', 0, 'pSandbox', pSandbox, 'pZeroFilter', 0, \r\n \t'pMappingToNewDims','', 'pDimDelim', '&', 'pEleStartDelim', '\u00a6', 'pEleDelim', '+', 'pFileDelete', 0, 'pSkipInvalidRecords', 0\r\n );\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will load a csv text file to the target cube.\r\n\r\n# Use case: Intended for development/prototyping or in Production environment.\r\n#1/ Import data from another TM1 model.\r\n#2/ To eliminate possibility of locking it is sometimes better to export and import when needing to copy data from one cube to another.\r\n\r\n# Note:\r\n# Naturally, a valid target cube name (pCube) is mandatory otherwise the process will abort.\r\n# Element mapping for new dimensions (pMappingToNewDims ) is also required when the target cube has more dimensions than the source, otherwise the process will abort.\r\n# The default input path is the same as the error file path if not specified.\r\n# If the file name is left blank, the process will look for a file called pCube_Export.csv.\r\n\r\n# Format:\r\n# The assumed file format is as per standard CMA export:\r\n# - v1 specIfies cube name, subsequent fields specify cube address ( individual element names ).\r\n# - vN specIfies cell data value to load. With provision for files with header rows.\r\n# Format of filter row for Zero out:\r\n# - v1 specifies source cube name\r\n# - v2 must be equal to \"Filter\".\r\n# - v3 specifies the filter to be used to zero out. Please note if target cube has additional dimensions this is the final filter used if pMappingToNewDims is not speficied. All the elements in additional dimensions will be cleaned \r\n# - v4 specifies the dimension delimiter used in filter\r\n# - v5 specifies the element start delimiter used in filter\r\n# - v6 specifies the element delimiter used in filter\r\n# Note about the Zero out:\r\n# if pMappingToNewDims parameter is specified, it will be concatenated to the filter in the file to restict the cube slice to be zeroed out. Similarly, if pDim is specified the source element is substituted with the targed one, sould it be in the filter string\r\n# in both cases the delimiters in the source file must match the delimiters passed in parameters of this process.\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pSrcDir:%pSrcDir%, pSrcFile:%pSrcFile%, pCube:%pCube%, pDim:%pDim%, pSrcEle:%pSrcEle%, pTgtEle:%pTgtEle%, pTitleRows:%pTitleRows%, pDelim:%pDelim%, pQuote:%pQuote%, pCumulate:%pCumulate%, pCubeLogging:%pCubeLogging%, pSandbox:%pSandbox%, pZeroFilter:%pZeroFilter%, pMappingToNewDims:%pMappingToNewDims%, pDimDelim:%pDimDelim%, pEleStartDelim:%pEleStartDelim%, pEleDelim:%pEleDelim%.'; \r\ncMinLenASCIICode = 2;\r\ncMaxLenASCIICode = 3;\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pCharacterSet\": \"TM1CS_UTF8\",\r\n \"pCube\": null,\r\n \"pDecimalSeparator\": \".\",\r\n \"pDelim\": \"\",\r\n \"pDim\": \"\",\r\n \"pDimDelim\": \"&\",\r\n \"pEleDelim\": \"+\",\r\n \"pEleStartDelim\": \"\u00a6\",\r\n \"pMappingToNewDims\": \"\",\r\n \"pQuote\": \"\"\",\r\n \"pSandbox\": \"\",\r\n \"pSrcDir\": \"\",\r\n \"pSrcEle\": \"\",\r\n \"pSrcFile\": \"\",\r\n \"pTgtEle\": \"\",\r\n \"pThousandSeparator\": \",\",\r\n \"pCumulate\": 0,\r\n \"pFileDelete\": 0,\r\n \"pLogOutput\": 0,\r\n \"pSkipInvalidRecords\": 0,\r\n \"pStrictErrorHandling\": 0,\r\n \"pTitleRows\": 1,\r\n \"pZeroFilter\": 0\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pCharacterSet\": '|StringToJson ( pCharacterSet )|',\r\n \"pCube\": '|StringToJson ( pCube )|',\r\n \"pDecimalSeparator\": '|StringToJson ( pDecimalSeparator )|',\r\n \"pDelim\": '|StringToJson ( pDelim )|',\r\n \"pDim\": '|StringToJson ( pDim )|',\r\n \"pDimDelim\": '|StringToJson ( pDimDelim )|',\r\n \"pEleDelim\": '|StringToJson ( pEleDelim )|',\r\n \"pEleStartDelim\": '|StringToJson ( pEleStartDelim )|',\r\n \"pMappingToNewDims\": '|StringToJson ( pMappingToNewDims )|',\r\n \"pQuote\": '|StringToJson ( pQuote )|',\r\n \"pSandbox\": '|StringToJson ( pSandbox )|',\r\n \"pSrcDir\": '|StringToJson ( pSrcDir )|',\r\n \"pSrcEle\": '|StringToJson ( pSrcEle )|',\r\n \"pSrcFile\": '|StringToJson ( pSrcFile )|',\r\n \"pTgtEle\": '|StringToJson ( pTgtEle )|',\r\n \"pThousandSeparator\": '|StringToJson ( pThousandSeparator )|',\r\n \"pCumulate\": '|NumberToString( pCumulate )|',\r\n \"pFileDelete\": '|NumberToString( pFileDelete )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pSkipInvalidRecords\": '|NumberToString( pSkipInvalidRecords )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|',\r\n \"pTitleRows\": '|NumberToString( pTitleRows )|',\r\n \"pZeroFilter\": '|NumberToString( pZeroFilter )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npCharacterSet = JsonToString( JsonGet( pJson, 'pCharacterSet' ) );\r\npCube = JsonToString( JsonGet( pJson, 'pCube' ) );\r\npDecimalSeparator = JsonToString( JsonGet( pJson, 'pDecimalSeparator' ) );\r\npDelim = JsonToString( JsonGet( pJson, 'pDelim' ) );\r\npDim = JsonToString( JsonGet( pJson, 'pDim' ) );\r\npDimDelim = JsonToString( JsonGet( pJson, 'pDimDelim' ) );\r\npEleDelim = JsonToString( JsonGet( pJson, 'pEleDelim' ) );\r\npEleStartDelim = JsonToString( JsonGet( pJson, 'pEleStartDelim' ) );\r\npMappingToNewDims = JsonToString( JsonGet( pJson, 'pMappingToNewDims' ) );\r\npQuote = JsonToString( JsonGet( pJson, 'pQuote' ) );\r\npSandbox = JsonToString( JsonGet( pJson, 'pSandbox' ) );\r\npSrcDir = JsonToString( JsonGet( pJson, 'pSrcDir' ) );\r\npSrcEle = JsonToString( JsonGet( pJson, 'pSrcEle' ) );\r\npSrcFile = JsonToString( JsonGet( pJson, 'pSrcFile' ) );\r\npTgtEle = JsonToString( JsonGet( pJson, 'pTgtEle' ) );\r\npThousandSeparator = JsonToString( JsonGet( pJson, 'pThousandSeparator' ) );\r\n# Numeric Parameters\r\npCumulate = StringToNumber( JsonToString( JsonGet( pJson, 'pCumulate' ) ) );\r\npFileDelete = StringToNumber( JsonToString( JsonGet( pJson, 'pFileDelete' ) ) );\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npSkipInvalidRecords = StringToNumber( JsonToString( JsonGet( pJson, 'pSkipInvalidRecords' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\npTitleRows = StringToNumber( JsonToString( JsonGet( pJson, 'pTitleRows' ) ) );\r\npZeroFilter = StringToNumber( JsonToString( JsonGet( pJson, 'pZeroFilter' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\npDelimiter = TRIM(pDelim);\r\nsDelimDim = TRIM(pDimDelim);\r\nsElementStartDelim = TRIM(pElEStartDelim);\r\nsDelimElem = TRIM(pEleDelim);\r\npDecimalSeparator = TRIM(pDecimalSeparator);\r\npThousandSeparator = TRIM(pThousandSeparator);\r\n\r\n## LogOutput parameters\r\nIf( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\nnRecordProcessedCount = 0;\r\nnRecordPostedCount = 0;\r\nnErrors = 0;\r\n\r\n\r\n### Validate Parameters ###\r\npSourceDir = TRIM(pSrcDir);\r\npSourceFile = TRIM(pSrcFile);\r\n\r\n## check operating system\r\nIf( SubSt( GetProcessErrorFileDirectory, 2, 1 ) @= ':' );\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nElseIf( Scan( '/', GetProcessErrorFileDirectory ) > 0 );\r\n sOS = 'Linux';\r\n sOSDelim = '/';\r\nElse;\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nEndIf;\r\n\r\n# Validate source directory\r\nIf(Trim( pSourceDir ) @= '' );\r\n pSourceDir = GetProcessErrorFileDirectory;\r\nEndIf;\r\n\r\nIf( SubSt( pSourceDir, Long( pSourceDir ), 1 ) @= sOSDelim );\r\n pSourceDir = SubSt( pSourceDir, 1, Long( pSourceDir ) - 1 );\r\nEndIf;\r\n\r\nIf( FileExists( pSourceDir ) = 0 );\r\n sMessage = 'Invalid source directory specified: folder does not exist.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nIf( pSourceFile @= '' );\r\n pSourceFile = Expand('%pCube%_Export.csv');\r\nEndIf;\r\n\r\nsFile = pSourceDir | sOSDelim | pSourceFile;\r\n# Validate source file\r\nIf( FileExists( sFile ) = 0 );\r\n sMessage = 'Invalid source file specified: file does not exist in directory:' | sFile;\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Automatic file deletion\r\nIf( pFileDelete <> 1 );\r\n pFileDelete = 0;\r\nEndIf;\r\n\r\n# Skip invalid records\r\nIf( pSkipInvalidRecords <> 1 );\r\n pSkipInvalidRecords = 0;\r\nEndIf;\r\n\r\n## Validate cube\r\nIf( Trim( pCube ) @= '' );\r\n sMessage = 'No target cube specified.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( CubeExists( pCube ) = 0 );\r\n sMessage = 'Invalid target cube specified: ' | pCube;\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate file delimiter & quote character\r\nIf( pDelimiter @= '' );\r\n pDelimiter = ',';\r\nElse;\r\n # If length of pDelimiter is between 2 and 3 chars and each of them is decimal digit, then the pDelimiter is entered as ASCII code\r\n If ( LONG(pDelimiter) <= cMaxLenASCIICode & LONG(pDelimiter) >= cMinLenASCIICode );\r\n nValid = 1;\r\n nChar = 1;\r\n While ( nChar <= LONG(pDelimiter) );\r\n If( CODE( pDelimiter, nChar ) < CODE( '0', 1 ) % CODE( pDelimiter, nChar ) > CODE( '9', 1 ) );\r\n nValid = 0;\r\n Break;\r\n EndIf;\r\n nChar = nChar + 1;\r\n End;\r\n If ( nValid<>0 );\r\n pDelimiter=CHAR(StringToNumber( pDelimiter ));\r\n EndIf;\r\n EndIf;\r\nEndIf;\r\n\r\nIf( pQuote @= '' );\r\n ## Use no quote character \r\nElse;\r\n # If length of pQuote is between 2 and 3 chars and each of them is decimal digit, then the pQuote is entered as ASCII code\r\n If ( LONG(pQuote) <= cMaxLenASCIICode & LONG(pQuote) >= cMinLenASCIICode);\r\n nValid = 1;\r\n nChar = 1;\r\n While ( nChar <= LONG(pQuote) );\r\n If( CODE( pQuote, nChar ) < CODE( '0', 1 ) % CODE( pQuote, nChar ) > CODE( '9', 1 ) );\r\n nValid = 0;\r\n Break;\r\n EndIf;\r\n nChar = nChar + 1;\r\n End;\r\n If ( nValid<>0 );\r\n pQuote=CHAR(StringToNumber( pQuote ));\r\n EndIf;\r\n EndIf;\r\nEndIf;\r\n\r\nIf ( LONG(pDecimalSeparator) <= cMaxLenASCIICode & LONG(pDecimalSeparator) >= cMinLenASCIICode );\r\n nValid = 0;\r\n nChar = 1;\r\n While ( nChar <= LONG(pDecimalSeparator) );\r\n If( CODE( pDecimalSeparator, nChar ) >= CODE( '0', 1 ) & CODE( pDecimalSeparator, nChar ) <= CODE( '9', 1 ) );\r\n nValid = 1;\r\n Else;\r\n nValid = 0;\r\n Break;\r\n EndIf;\r\n nChar = nChar + 1;\r\n End;\r\n If ( nValid<>0 );\r\n pDecimalSeparator = CHAR(StringToNumber( pDecimalSeparator ));\r\n Else;\r\n pDecimalSeparator = SubSt( Trim( pDecimalSeparator ), 1, 1 );\r\n EndIf;\r\nEndIf;\r\nsDecimalSeparator = pDecimalSeparator;\r\n\r\nIf ( LONG(pThousandSeparator) <= cMaxLenASCIICode & LONG(pThousandSeparator) >= cMinLenASCIICode );\r\n nValid = 0;\r\n nChar = 1;\r\n While ( nChar <= LONG(pThousandSeparator) );\r\n If( CODE( pThousandSeparator, nChar ) >= CODE( '0', 1 ) & CODE( pThousandSeparator, nChar ) <= CODE( '9', 1 ) );\r\n nValid = 1;\r\n Else;\r\n nValid = 0;\r\n Break;\r\n EndIf;\r\n nChar = nChar + 1;\r\n End;\r\n If ( nValid<>0 );\r\n pThousandSeparator = CHAR(StringToNumber( pThousandSeparator ));\r\n Else;\r\n pThousandSeparator = SubSt( Trim( pThousandSeparator ), 1, 1 );\r\n EndIf;\r\nEndIf;\r\nsThousandSeparator = pThousandSeparator;\r\n\r\n# Validate Sandbox\r\nIf( TRIM( pSandbox ) @<> '' );\r\n If( ServerSandboxExists( pSandbox ) = 0 );\r\n SetUseActiveSandboxProperty( 0 );\r\n nErrors = nErrors + 1;\r\n sMessage = Expand('Sandbox %pSandbox% is invalid for the current user.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n Else;\r\n ServerActiveSandboxSet( pSandbox );\r\n SetUseActiveSandboxProperty( 1 );\r\n EndIf;\r\nElse;\r\n SetUseActiveSandboxProperty( 0 );\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n## Validate Dimension\r\npDimension = TRIM( pDim);\r\npSourceElement = TRIM(pSrcEle);\r\npTargetElement = TRIM(pTgtEle);\r\n\r\nIf( pDimension @<> '');\r\n \r\n If( DimensionExists( pDimension ) = 0 );\r\n sMessage = 'Invalid dimension specified: ' | pDimension;\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n EndIf;\r\n\r\n # Validate Source Element\r\n If( pSourceElement @= '' );\r\n sMessage = 'Error: The Source Element parameter is blank.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n EndIf;\r\n\r\n If( DimIx( pDimension, pSourceElement ) = 0 );\r\n sMessage = 'Invalid source element, ' | pSourceElement | ' specified for ' | pDimension | ' dimension.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n EndIf;\r\n sSourceElement = DimensionElementPrincipalName( pDimension, pSourceElement);\r\n\r\n # Validate Target Element\r\n If( pTargetElement @= '' );\r\n sMessage = 'Error: The Target Element parameter is blank.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n ElseIf( DimIx( pDimension, pTargetElement ) = 0 );\r\n sMessage = 'Invalid target element, ' | pTargetElement | ' specified for ' | pDimension | ' dimension.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n EndIf;\r\n sTargetElement = DimensionElementPrincipalName( pDimension, pTargetElement);\r\n\r\nENDIF;\r\n\r\n## Validate delimiter\r\n\r\nIf( pDelimiter @= '' );\r\n sMessage = 'Error: The file delimiter parameter is blank.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( Long( pDelimiter ) > 1 );\r\n sMessage = 'Invalid delimiter specified: ' | pDelimiter | ' field delimiter must be single character or 2-3 symbols number representing ASCII code.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n## Validate quote character\r\nIf( Long( pQuote ) > 1 );\r\n sMessage = 'Invalid string qualIfier: ' | pQuote | ' quote character must be single character or empty string or 2-3 symbols number representing ASCII code.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### Determine number of dims in target cube ###\r\nnCount = 1;\r\nnSubstututeDimensionIndex = 0;\r\nWhile( \r\nTabDim( pCube, nCount ) @<> '' );\r\n sDimension = TabDim( pCube, nCount );\r\n If( sDimension @= pDimension );\r\n nSubstututeDimensionIndex = nCount;\r\n EndIf;\r\n nCount = nCount + 1;\r\nEnd;\r\nnDimensionCount = nCount - 1;\r\n\r\n## Validate the dimension is part of the cube.\r\nIf( pDimension @= '');\r\n ## CONTINUE;\r\nELSEIf( nSubstututeDimensionIndex = 0 );\r\n sMessage = 'Specified dimension: ' | pDimension | ' is not a component of the cube: ' | pCube;\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nENDIF;\r\n\r\n ## Default filter delimiters\r\n If( pDimDelim @= '' );\r\n pDimDelim = '&';\r\n EndIf;\r\n If( pEleStartDelim@= '' );\r\n pEleStartDelim= '\u00a6';\r\n EndIf;\r\n If( pEleDelim @= '' );\r\n pEleDelim = '+';\r\n EndIf;\r\n \r\n\r\nIf( nDimensionCount > 27 );\r\n sMessage = 'Cube has too many dimensions: ' | pCube | ' max 27 dimensions.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### Determine dimensions in target cube, we need to know this to test cell type before loading ###\r\nsDim1 = TabDim( pCube, 1 );\r\nsDim2 = TabDim( pCube, 2 );\r\nsDim3 = TabDim( pCube, 3 );\r\nsDim4 = TabDim( pCube, 4 );\r\nsDim5 = TabDim( pCube, 5 );\r\nsDim6 = TabDim( pCube, 6 );\r\nsDim7 = TabDim( pCube, 7 );\r\nsDim8 = TabDim( pCube, 8 );\r\nsDim9 = TabDim( pCube, 9 );\r\nsDim10 = TabDim( pCube, 10 );\r\nsDim11 = TabDim( pCube, 11 );\r\nsDim12 = TabDim( pCube, 12 );\r\nsDim13 = TabDim( pCube, 13 );\r\nsDim14 = TabDim( pCube, 14 );\r\nsDim15 = TabDim( pCube, 15 );\r\nsDim16 = TabDim( pCube, 16 );\r\nsDim17 = TabDim( pCube, 17 );\r\nsDim18 = TabDim( pCube, 18 );\r\nsDim19 = TabDim( pCube, 19 );\r\nsDim20 = TabDim( pCube, 20 );\r\nsDim21 = TabDim( pCube, 21 );\r\nsDim22 = TabDim( pCube, 22 );\r\nsDim23 = TabDim( pCube, 23 );\r\nsDim24 = TabDim( pCube, 24 );\r\nsDim25 = TabDim( pCube, 25 );\r\nsDim26 = TabDim( pCube, 26 );\r\nsDim27 = TabDim( pCube, 27 );\r\n\r\n### Placeholders for mappped dimensions and for new dimensions\r\n\r\nnMappedDim1 = 0;\tsMappedV1 = '';\t\tnNewDim1 = 0;\t sNewV1 = '';\r\nnMappedDim2 = 0;\tsMappedV2 = '';\t\tnNewDim2 = 0;\t sNewV2 = '';\r\nnMappedDim3 = 0;\tsMappedV3 = '';\t\tnNewDim3 = 0;\t sNewV3 = '';\r\nnMappedDim4 = 0;\tsMappedV4 = '';\t\tnNewDim4 = 0;\t sNewV4 = '';\r\nnMappedDim5 = 0;\tsMappedV5 = '';\t\tnNewDim5 = 0;\t sNewV5 = '';\r\nnMappedDim6 = 0;\tsMappedV6 = '';\t\tnNewDim6 = 0;\t sNewV6 = '';\r\nnMappedDim7 = 0;\tsMappedV7 = '';\t\tnNewDim7 = 0;\t sNewV7 = '';\r\nnMappedDim8 = 0;\tsMappedV8 = '';\t\tnNewDim8 = 0;\t sNewV8 = '';\r\nnMappedDim9 = 0;\tsMappedV9 = '';\t\tnNewDim9 = 0;\t sNewV9 = '';\r\nnMappedDim10 = 0;\tsMappedV10 = '';\tnNewDim10 = 0;\tsNewV10 = '';\r\nnMappedDim11 = 0;\tsMappedV11 = '';\tnNewDim11 = 0;\tsNewV11 = '';\r\nnMappedDim12 = 0;\tsMappedV12 = '';\tnNewDim12 = 0;\tsNewV12 = '';\r\nnMappedDim13 = 0;\tsMappedV13 = '';\tnNewDim13 = 0;\tsNewV13 = '';\r\nnMappedDim14 = 0;\tsMappedV14 = '';\tnNewDim14 = 0;\tsNewV14 = '';\r\nnMappedDim15 = 0;\tsMappedV15 = '';\tnNewDim15 = 0;\tsNewV15 = '';\r\nnMappedDim16 = 0;\tsMappedV16 = '';\tnNewDim16 = 0;\tsNewV16 = '';\r\nnMappedDim17 = 0;\tsMappedV17 = '';\tnNewDim17 = 0;\tsNewV17 = '';\r\nnMappedDim18 = 0;\tsMappedV18 = '';\tnNewDim18 = 0;\tsNewV18 = '';\r\nnMappedDim19 = 0;\tsMappedV19 = '';\tnNewDim19 = 0;\tsNewV19 = '';\r\nnMappedDim20 = 0;\tsMappedV20 = '';\tnNewDim20 = 0;\tsNewV20 = '';\r\nnMappedDim21 = 0;\tsMappedV21 = '';\tnNewDim21 = 0;\tsNewV21 = '';\r\nnMappedDim22 = 0;\tsMappedV22 = '';\tnNewDim22 = 0;\tsNewV22 = '';\r\nnMappedDim23 = 0;\tsMappedV23 = '';\tnNewDim23 = 0;\tsNewV23 = '';\r\nnMappedDim24 = 0;\tsMappedV24 = '';\tnNewDim24 = 0;\tsNewV24 = '';\r\nnMappedDim25 = 0;\tsMappedV25 = '';\tnNewDim25 = 0;\tsNewV25 = '';\r\nnMappedDim26 = 0;\tsMappedV26 = '';\tnNewDim26 = 0;\tsNewV26 = '';\r\nnMappedDim27 = 0;\tsMappedV27 = '';\tnNewDim27 = 0;\tsNewV27 = '';\r\n sMappedV28 = '';\r\n\r\n###########################################\r\n### SPLIT MAPPING TO NEW DIMS PARAMETER ###\r\n###########################################\r\n\r\nnTargetCubeDimensionCount = nDimensionCount;\r\n\r\nsElementMapping = TRIM( pMappingToNewDims );\r\nnChar = 1;\r\nnCharCount = LONG( sElementMapping );\r\n\r\nsTargetFilter = '';\r\nsWord = '';\r\nsLastDelim = '';\r\nnIndex = 1;\r\n\r\n# Add a trailing element delimiter so that the last element is picked up\r\nIf( nCharCount > 0 );\r\n sElementMapping = sElementMapping | sDelimDim;\r\n nCharCount = nCharCount + LONG(sDelimDim);\r\nEndIf;\r\n\r\nWHILE (nChar <= nCharCount);\r\n sChar = SUBST( sElementMapping, nChar, 1);\r\n\r\n # Used for delimiters, required for multiple character delimiters\r\n sDelim = '';\r\n nAddExtra = 0;\r\n\r\n # Ignore spaces\r\n IF (TRIM(sChar) @<> '' );\r\n\r\n ### Dimension Name ###\r\n\r\n # If the delimiter is more than 1 character peek ahead the same amount\r\n # Ignore the first character\r\n sDelim = sChar;\r\n nCount = LONG(sElementStartDelim) - 1;\r\n If( nCount > 0 & nChar + nCount <= nCharCount );\r\n # Add the extra characters\r\n sDelim = sDelim | SUBST( sElementMapping, nChar + 1, nCount);\r\n # Move to the end of the delimter\r\n\r\n EndIf;\r\n\r\n If( sDelim @= sElementStartDelim );\r\n nAddExtra = nCount;\r\n sChar = sDelim;\r\n\r\n If( sLastDelim @<> '' & sLastDelim @<> sDelimDim );\r\n sMessage = 'In pMappingToNewDims the name of a dimension must follow a dimension delimiter (' | sDelimDim | ')';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n #ProcessError();\r\n EndIf;\r\n\r\n # Found a dimension\r\n sDimension = sWord;\r\n\r\n If( DimensionExists( sDimension ) = 0 );\r\n # The dimension does not exist in the model. Cancel process\r\n sMessage = 'In pMappingToNewDims - Dimension: ' | sDimension | ' does not exist';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n #ProcessError();\r\n EndIf;\r\n \r\n ### Determine the dimension is a member of the cube ###\r\n nMapCount = 1;\r\n nMapDimensionIndex = 0;\r\n While( TabDim( pCube, nMapCount ) @<> '' );\r\n sMapCubeDimName = TabDim( pCube, nMapCount );\r\n If( sDimension @= sMapCubeDimName );\r\n nMapDimensionIndex = nMapCount;\r\n EndIf;\r\n nMapCount = nMapCount + 1;\r\n End;\r\n\r\n If( nMapDimensionIndex = 0 );\r\n # The dimension does not exist in the cube. Cancel process\r\n sMessage = 'Dimension: ' | sDimension | ' is not a member of: '| pCube | ' cube.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n EndIf;\r\n\r\n # Find the index of the dimension is in the Target cube\r\n nTargetIndexCounter = 1;\r\n\r\n WHILE(nTargetIndexCounter <= nTargetCubeDimensionCount );\r\n sNthDimension = TabDim( pCube, nTargetIndexCounter );\r\n\r\n If(sDimension @= sNthDimension);\r\n nTargetIndex = nTargetIndexCounter;\r\n nTargetIndexCounter = 1000;\r\n EndIf;\r\n\r\n nTargetIndexCounter = nTargetIndexCounter + 1;\r\n END;\r\n \r\n #Add to the Target filter\r\n If(sTargetFilter@='');\r\n sTargetFilter=sDimension; \r\n Else;\r\n sTargetFilter=sTargetFilter|sDelimDim|sDimension;\r\n Endif; \r\n \r\n sLastDelim = sChar;\r\n # Clear the word\r\n sWord = '';\r\n\r\n Else;\r\n\r\n # Reset extra chars\r\n nAddExtra = 0;\r\n\r\n ### Check both dim delimiter and element delimiter ###\r\n nIsDelimiter = 0;\r\n\r\n ## Check dimension delimiter first\r\n # If the delimiter is more than 1 character peek ahead the same amount\r\n # Ignore the first character\r\n sDelim = sChar;\r\n nCount = LONG(sDelimDim) - 1;\r\n If( nCount > 0 & nChar + nCount <= nCharCount );\r\n # Add the extra characters\r\n sDelim = sDelim | SUBST( sElementMapping, nChar + 1, nCount);\r\n # Move to the end of the delimter\r\n \r\n EndIf;\r\n\r\n If( sDelim @= sDelimDim );\r\n nIsDelimiter = 1;\r\n sChar = sDelim;\r\n nAddExtra = nCount;\r\n EndIf;\r\n\r\n If ( nIsDelimiter = 1 );\r\n\r\n If( sLastDelim @= '' % sLastDelim @= sDelimDim );\r\n sMessage = 'In pMappingToNewDims - an element delimiter must follow a dimension name: ' | sChar | ' (' | NumberToString(nChar) | ')';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n #ProcessError();\r\n EndIf;\r\n\r\n # an element has been found\r\n sElement = sWord;\r\n\r\n If( DimIx( sDimension, sElement ) = 0 );\r\n # The element does not exist in the dimension. Cancel process\r\n sMessage = 'In pMappingToNewDims - Element: ' | sElement | ' in dimension ' | sDimension | ' does not exist';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n #ProcessError();\r\n EndIf;\r\n\r\n # Allow consolidations only if pSuppressConsol is set to 0\r\n\r\n If ( DTYPE( sDimension, sElement) @= 'C' );\r\n sMessage = Expand( 'In pMappingToNewDims - Target element: %sElement% for dimension %sDimension% is consolidated' );\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n #ProcessError();\r\n Endif; \r\n \r\n\r\n # Add the element to the source or target depending on whether it's the first or the second element\r\n # Get principal name\r\n # in case source element and this element are using different aliases\r\n\r\n sElement = DimensionElementPrincipalName(sDimension,sElement);\r\n\r\n ### Update the variable for InputElement Target Dim ######################################\r\n If(nTargetIndex = 1);\r\n nNewDim1 = 1;\r\n sNewV1 = sElement;\r\n ElseIf(nTargetIndex = 2);\r\n nNewDim2 = 1;\r\n sNewV2 = sElement;\r\n ElseIf(nTargetIndex = 3);\r\n nNewDim3 = 1;\r\n sNewV3 = sElement;\r\n ElseIf(nTargetIndex = 4);\r\n nNewDim4 = 1;\r\n sNewV4 = sElement;\r\n ElseIf(nTargetIndex = 5);\r\n nNewDim5 = 1;\r\n sNewV5 = sElement;\r\n ElseIf(nTargetIndex = 6);\r\n nNewDim6 = 1;\r\n sNewV6 = sElement;\r\n ElseIf(nTargetIndex = 7);\r\n nNewDim7 = 1;\r\n sNewV7 = sElement;\r\n ElseIf(nTargetIndex = 8);\r\n nNewDim8 = 1;\r\n sNewV8 = sElement;\r\n ElseIf(nTargetIndex = 9);\r\n nNewDim9 = 1;\r\n sNewV9 = sElement;\r\n ElseIf(nTargetIndex = 10);\r\n nNewDim10 = 1;\r\n sNewV10 = sElement;\r\n ElseIf(nTargetIndex = 11);\r\n nNewDim11 = 1;\r\n sNewV11 = sElement;\r\n ElseIf(nTargetIndex = 12);\r\n nNewDim12 = 1;\r\n sNewV12 = sElement;\r\n ElseIf(nTargetIndex = 13);\r\n nNewDim13 = 1;\r\n sNewV13 = sElement;\r\n ElseIf(nTargetIndex = 14);\r\n nNewDim14 = 1;\r\n sNewV14 = sElement;\r\n ElseIf(nTargetIndex = 15);\r\n nNewDim15 = 1;\r\n sNewV15 = sElement;\r\n ElseIf(nTargetIndex = 16);\r\n nNewDim16 = 1;\r\n sNewV16 = sElement;\r\n ElseIf(nTargetIndex = 17);\r\n nNewDim17 = 1;\r\n sNewV17 = sElement;\r\n ElseIf(nTargetIndex = 18);\r\n nNewDim18 = 1;\r\n sNewV18 = sElement;\r\n ElseIf(nTargetIndex = 19);\r\n nNewDim19 = 1;\r\n sNewV19 = sElement;\r\n ElseIf(nTargetIndex = 20);\r\n nNewDim20 = 1;\r\n sNewV20 = sElement;\r\n ElseIf(nTargetIndex = 21);\r\n nNewDim21 = 1;\r\n sNewV21 = sElement;\r\n ElseIf(nTargetIndex = 22);\r\n nNewDim22 = 1;\r\n sNewV22 = sElement;\r\n ElseIf(nTargetIndex = 23);\r\n nNewDim23 = 1;\r\n sNewV23 = sElement;\r\n ElseIf(nTargetIndex = 24);\r\n nNewDim24 = 1;\r\n sNewV24 = sElement;\r\n ElseIf(nTargetIndex = 25);\r\n nNewDim25 = 1;\r\n sNewV25 = sElement;\r\n ElseIf(nTargetIndex = 26);\r\n nNewDim26 = 1;\r\n sNewV26 = sElement;\r\n ElseIf(nTargetIndex = 27);\r\n nNewDim27 = 1;\r\n sNewV27 = sElement;\r\n EndIf;\r\n\r\n #Add to the Target filter - no need to manage element separators, since just one target element is possible in mapping\r\n sTargetFilter=sTargetFilter|sElementStartDelim|sElement;\r\n \r\n # Clear the word\r\n sWord = '';\r\n sLastDelim = sChar;\r\n \r\n Else;\r\n sWord = sWord | sChar;\r\n EndIf;\r\n\r\n EndIf;\r\n\r\n EndIf;\r\n\r\n nChar = nChar + nAddExtra + 1;\r\n\r\nEND;\r\n\r\n\r\n###########################################\r\n#Region ### MAPPING Target DIMENSIONS #####\r\n\r\n## Source index starting from 2, since first columns holds the export cube name\r\nnSourceIndex = 2;\r\nnTargetIndex = 1;\r\nWHILE(TabDim( pCube, nTargetIndex ) @<> '');\r\n sTargetDim = TabDim( pCube, nTargetIndex );\r\n \r\n If(nTargetIndex = 1);\r\n If( nNewDim1 = 0 );\r\n nMappedDim1 = 1;\r\n sMappedV1 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\n Else;\r\n \r\n EndIf;\r\n ElseIf(nTargetIndex = 2 & nNewDim2 = 0);\r\n nMappedDim2 = 1;\r\n sMappedV2 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\n ElseIf(nTargetIndex = 3 & nNewDim3 = 0);\r\n nMappedDim3 = 1;\r\n sMappedV3 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\n ElseIf(nTargetIndex = 4 & nNewDim4 = 0);\r\n nMappedDim4 = 1;\r\n sMappedV4 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\n ElseIf(nTargetIndex = 5 & nNewDim5 = 0);\r\n nMappedDim5 = 1;\r\n sMappedV5 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\n ElseIf(nTargetIndex = 6 & nNewDim6 = 0);\r\n nMappedDim6 = 1;\r\n sMappedV6 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\n ElseIf(nTargetIndex = 7 & nNewDim7 = 0);\r\n nMappedDim7 = 1;\r\n sMappedV7 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\n ElseIf(nTargetIndex = 8 & nNewDim8 = 0);\r\n nMappedDim8 = 1;\r\n sMappedV8 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\n ElseIf(nTargetIndex = 9 & nNewDim9 = 0);\r\n nMappedDim9 = 1;\r\n sMappedV9 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\n ElseIf(nTargetIndex = 10 & nNewDim10 = 0);\r\n nMappedDim10 = 1;\r\n sMappedV10 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\n ElseIf(nTargetIndex = 11 & nNewDim11 = 0);\r\n nMappedDim11 = 1;\r\n sMappedV11 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\n ElseIf(nTargetIndex = 12 & nNewDim12 = 0 );\r\n nMappedDim12 = 1;\r\n sMappedV12 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\n ElseIf(nTargetIndex = 13 & nNewDim13 = 0 );\r\n nMappedDim13 = 1;\r\n sMappedV13 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\n ElseIf(nTargetIndex = 14 & nNewDim14 = 0 );\r\n nMappedDim14 = 1;\r\n sMappedV14 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\n ElseIf(nTargetIndex = 15 & nNewDim15 = 0 );\r\n nMappedDim15 = 1;\r\n sMappedV15 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\n ElseIf(nTargetIndex = 16 & nNewDim16 = 0 );\r\n nMappedDim16 = 1;\r\n sMappedV16 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\n ElseIf(nTargetIndex = 17 & nNewDim17 = 0 );\r\n nMappedDim17 = 1;\r\n sMappedV17 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\n ElseIf(nTargetIndex = 18 & nNewDim18 = 0 );\r\n nMappedDim18 = 1;\r\n sMappedV18 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\n ElseIf(nTargetIndex = 19 & nNewDim19 = 0 );\r\n nMappedDim19 = 1;\r\n sMappedV19 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\n ElseIf(nTargetIndex = 20 & nNewDim20 = 0 );\r\n nMappedDim20 = 1;\r\n sMappedV20 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\n ElseIf(nTargetIndex = 21 & nNewDim21 = 0 );\r\n nMappedDim21 = 1;\r\n sMappedV21 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\n ElseIf(nTargetIndex = 22 & nNewDim22 = 0 );\r\n nMappedDim22 = 1;\r\n sMappedV22 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\n ElseIf(nTargetIndex = 23 & nNewDim23 = 0 );\r\n nMappedDim23 = 1;\r\n sMappedV23 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\n ElseIf(nTargetIndex = 24 & nNewDim24 = 0 );\r\n nMappedDim24 = 1;\r\n sMappedV24 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\n ElseIf(nTargetIndex = 25 & nNewDim25 = 0 );\r\n nMappedDim25 = 1;\r\n sMappedV25 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\n ElseIf(nTargetIndex = 26 & nNewDim26 = 0 );\r\n nMappedDim26 = 1;\r\n sMappedV26 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\n ElseIf(nTargetIndex = 27 & nNewDim27 = 0 );\r\n nMappedDim27 = 1;\r\n sMappedV27 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\n EndIf;\r\n\r\n nTargetIndex = nTargetIndex + 1;\r\n\r\nEND;\r\n\r\n# The last variable in the data source holds the values\r\n# which need to be mapped to the last variable in the target\r\n\r\nIf(nTargetIndex = 1 & nNewDim1 = 0);\r\n nMappedDim1 = 1;\r\n sMappedV1 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\nElseIf(nTargetIndex = 2 & nNewDim2 = 0);\r\n nMappedDim2 = 1;\r\n sMappedV2 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\nElseIf(nTargetIndex = 3 & nNewDim3 = 0);\r\n nMappedDim3 = 1;\r\n sMappedV3 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\nElseIf(nTargetIndex = 4 & nNewDim4 = 0);\r\n nMappedDim4 = 1;\r\n sMappedV4 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\nElseIf(nTargetIndex = 5 & nNewDim5 = 0);\r\n nMappedDim5 = 1;\r\n sMappedV5 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\nElseIf(nTargetIndex = 6 & nNewDim6 = 0);\r\n nMappedDim6 = 1;\r\n sMappedV6 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\nElseIf(nTargetIndex = 7 & nNewDim7 = 0);\r\n nMappedDim7 = 1;\r\n sMappedV7 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\nElseIf(nTargetIndex = 8 & nNewDim8 = 0);\r\n nMappedDim8 = 1;\r\n sMappedV8 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\nElseIf(nTargetIndex = 9 & nNewDim9 = 0);\r\n nMappedDim9 = 1;\r\n sMappedV9 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\nElseIf(nTargetIndex = 10 & nNewDim10 = 0);\r\n nMappedDim10 = 1;\r\n sMappedV10 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\nElseIf(nTargetIndex = 11 & nNewDim11 = 0);\r\n nMappedDim11 = 1;\r\n sMappedV11 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\nElseIf(nTargetIndex = 12);\r\n nMappedDim12 = 1;\r\n sMappedV12 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\nElseIf(nTargetIndex = 13);\r\n nMappedDim13 = 1;\r\n sMappedV13 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\nElseIf(nTargetIndex = 14);\r\n nMappedDim14 = 1;\r\n sMappedV14 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\nElseIf(nTargetIndex = 15);\r\n nMappedDim15 = 1;\r\n sMappedV15 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\nElseIf(nTargetIndex = 16);\r\n nMappedDim16 = 1;\r\n sMappedV16 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\nElseIf(nTargetIndex = 17);\r\n nMappedDim17 = 1;\r\n sMappedV17 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\nElseIf(nTargetIndex = 18);\r\n nMappedDim18 = 1;\r\n sMappedV18 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\nElseIf(nTargetIndex = 19);\r\n nMappedDim19 = 1;\r\n sMappedV19 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\nElseIf(nTargetIndex = 20);\r\n nMappedDim20 = 1;\r\n sMappedV20 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\nElseIf(nTargetIndex = 21);\r\n nMappedDim21 = 1;\r\n sMappedV21 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\nElseIf(nTargetIndex = 22);\r\n nMappedDim22 = 1;\r\n sMappedV22 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\nElseIf(nTargetIndex = 23);\r\n nMappedDim23 = 1;\r\n sMappedV23 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\nElseIf(nTargetIndex = 24);\r\n nMappedDim24 = 1;\r\n sMappedV24 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\nElseIf(nTargetIndex = 25);\r\n nMappedDim25 = 1;\r\n sMappedV25 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\nElseIf(nTargetIndex = 26);\r\n nMappedDim26 = 1;\r\n sMappedV26 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\nElseIf(nTargetIndex = 27);\r\n nMappedDim27 = 1;\r\n sMappedV27 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\n\r\n# a cube with 27 dimensions uses V28 to hold the values\r\nElseIf(nTargetIndex = 28);\r\n nMappedDim28 = 1;\r\n sMapped28 = 'V' | NumberToString(nSourceIndex);\r\n nSourceIndex = nSourceIndex + 1;\r\nEndIf;\r\n\r\n# Check that an input element or variable has been specified for all dimensions in the target cube\r\n\r\nnIndexInTarget = 1;\r\nWHILE(nIndexInTarget <= nTargetCubeDimensionCount);\r\n \r\n sMapped = Expand('%nMappedDim'| NumberToString(nIndexInTarget) |'%'); \r\n sMapped = Subst( sMapped , Scan( '.' , sMapped )-1 , 99);\r\n nMapped = StringToNumber( Trim( sMapped ) );\r\n sNew = Expand('%nNewDim'| NumberToString(nIndexInTarget) |'%'); \r\n sNew = Subst( sNew , Scan( '.' , sNew )-1 , 99);\r\n nNew = StringToNumber( Trim( sNew ) );\r\n \r\n If(nMapped = 0 & nNew = 0 );\r\n # there's no input element and this dimension is not in the source\r\n nErrors = nErrors + 1;\r\n sTargetDimName = TabDim( pCube, nIndexInTarget );\r\n sMessage = 'Dimension ' | sTargetDimName | ' is missing an input element in pMappingToNewDims';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n EndIf;\r\n \r\n nIndexInTarget = nIndexInTarget + 1;\r\nEND;\r\n#EndRegion ### MAPPING Target DIMENSIONS #####\r\n##############################################\r\n\r\n### Assign Datasource ###\r\nDataSourceType = 'CHARACTERDELIMITED';\r\nDatasourceNameForServer = sFile;\r\nDatasourceNameForClient = sFile;\r\nDatasourceASCIIHeaderRecords = pTitleRows;\r\nDatasourceASCIIDelimiter = pDelimiter;\r\nDatasourceASCIIQuoteCharacter = pQuote;\r\nSetInputCharacterSet (pCharacterSet);\r\n\r\n### End Prolog ###", "MetadataProcedure": "#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "DataProcedure": "#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n# It would be too exhaustive to error trap elements not existing in dimension for each possible number of dimensions\r\n# If an incorrect source file is specfied for a target cube then the TI will error with standard TI error messages.\r\n# Note: that the assumed file format is standard .cma cube export of Cube, d1, d2, dn, value\r\n# This is equivalent to using the Bedrock.Cube.ExportToFile TI.\r\n\r\n## Increase Record count\r\nnRecordProcessedCount = nRecordProcessedCount + 1;\r\n\r\n### Zero out Target view using filter in the 1st record of the data source, if requested\r\nIf( nRecordProcessedCount = 1 );\r\n If( pZeroFilter = 2 );\r\n sRowIsFilter = v2;\r\n sImportedFilter = v3;\r\n sImportedDelimDim = v4;\r\n sImportedElementStartDelim = v5;\r\n sImportedDelimElem = v6;\r\n ### Check Filter row\r\n If(sRowIsFilter @<> 'Filter');\r\n sMessage = 'Filter row in source file not having the expected format.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n ENDIF;\r\n ### Check delimiters are the same when using any mapping. This because filter from the file and mappings form the params will be concatenated / substituted\r\n If((sElementMapping @<> '' % pDimension @<>'') & (sDelimDim @<> sImportedDelimDim % sElementStartDelim @<> sImportedElementStartDelim % sDelimElem @<> sImportedDelimElem));\r\n sMessage = 'Error zeroing out target slice corresponding to the filter plus new mapped dimensions: delimiters in source file do not match with the ones in parameters.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n ENDIF;\r\n \r\n ### Check filter in source file and validate its dimensions\r\n sFilter = TRIM( sImportedFilter );\r\n nChar = 1;\r\n nCharCount = LONG( sFilter );\r\n sWord = '';\r\n sLastDelim = '';\r\n nIndex = 1;\r\n # Add a trailing element delimiter so that the last element is picked up\r\n If( nCharCount > 0 );\r\n sFilter = sFilter | sDelimElem;\r\n nCharCount = nCharCount + LONG(sDelimElem);\r\n EndIf;\r\n \r\n WHILE (nChar <= nCharCount);\r\n sChar = SUBST( sFilter, nChar, 1);\r\n \r\n # Used for delimiters, required for multiple character delimiters\r\n sDelim = '';\r\n nAddExtra = 0;\r\n \r\n # Ignore spaces\r\n IF (TRIM(sChar) @<> '' );\r\n \r\n ### Dimension Name ###\r\n \r\n # If the delimiter is more than 1 character peek ahead the same amount\r\n # Ignore the first character\r\n sDelim = sChar;\r\n nCount = LONG(sElementStartDelim) - 1;\r\n If( nCount > 0 & nChar + nCount <= nCharCount );\r\n # Add the extra characters\r\n sDelim = sDelim | SUBST( sFilter, nChar + 1, nCount);\r\n # Move to the end of the delimter\r\n nAddExtra = nCount;\r\n EndIf;\r\n \r\n If( sDelim @= sElementStartDelim );\r\n \r\n sChar = sDelim;\r\n \r\n If( sLastDelim @<> '' & sLastDelim @<> sDelimDim );\r\n sMessage = 'The name of a dimension must follow a dimension delimiter (' | sDelimDim | ')';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n EndIf;\r\n \r\n sDimension = sWord;\r\n \r\n If( DimensionExists( sDimension ) = 0 );\r\n # The dimension does not exist in the model. Cancel process\r\n sMessage = 'Dimension: ' | sDimension | ' does not exist';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n EndIf;\r\n \r\n ### Determine the dimension is a member of the cube ###\r\n nCount = 1;\r\n nDimensionIndex = 0;\r\n While( TabDim( pCube, nCount ) @<> '' );\r\n sCubeDimName = TabDim( pCube, nCount );\r\n If( sDimension @= sCubeDimName );\r\n nDimensionIndex = nCount;\r\n EndIf;\r\n nCount = nCount + 1;\r\n End;\r\n \r\n If( nDimensionIndex = 0 );\r\n # The dimension does not exist in the cube. Cancel process\r\n sMessage = 'Dimension: ' | sDimension | ' is not a member of: '| pCube | ' cube.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n EndIf;\r\n \r\n\r\n \r\n nIndex = 1;\r\n sLastDelim = sChar;\r\n # Clear the word\r\n sWord = '';\r\n Else;\r\n \r\n # Reset extra chars\r\n nAddExtra = 0;\r\n \r\n ### Check both both dim delimiter and element delimiter ###\r\n nIsDelimiter = 0;\r\n \r\n ## Check dimension delimiter first\r\n # If the delimiter is more than 1 character peek ahead the same amount\r\n # Ignore the first character\r\n sDelim = sChar;\r\n nCount = LONG(sDelimDim) - 1;\r\n If( nCount > 0 & nChar + nCount <= nCharCount );\r\n # Add the extra characters\r\n sDelim = sDelim | SUBST( sFilter, nChar + 1, nCount);\r\n # Move to the end of the delimter\r\n nAddExtra = nCount;\r\n EndIf;\r\n \r\n If( sDelim @= sDelimDim );\r\n nIsDelimiter = 1;\r\n sChar = sDelim;\r\n Else;\r\n # Reset extra chars\r\n nAddExtra = 0;\r\n \r\n ## Check element delimiter\r\n \r\n # If the delimiter is more than 1 character peek ahead the same amount\r\n # Ignore the first character\r\n sDelim = sChar;\r\n nCount = LONG(sDelimElem) - 1;\r\n If( nCount > 0 & nChar + nCount <= nCharCount );\r\n # Add the extra characters\r\n sDelim = sDelim | SUBST( sFilter, nChar + 1, nCount);\r\n # Move to the end of the delimter\r\n nAddExtra = nCount;\r\n EndIf;\r\n \r\n If( sDelim @= sDelimElem );\r\n nIsDelimiter = 1;\r\n sChar = sDelim;\r\n Else;\r\n # Reset extra chars\r\n nAddExtra = 0;\r\n EndIf;\r\n \r\n EndIf;\r\n \r\n If ( nIsDelimiter = 1 );\r\n \r\n If( sLastDelim @= '' % sLastDelim @= sDelimDim );\r\n sMessage = 'An element delimiter must follow a dimension name: ' | sChar | ' (' | NumberToString(nChar) | ')';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n #ProcessError();\r\n EndIf;\r\n \r\n sElement = sWord;\r\n \r\n If( DimIx( sDimension, sElement ) = 0 );\r\n # The element does not exist in the dimension. Cancel process\r\n sMessage = 'Element: ' | sElement | ' in dimension ' | sDimension | ' does not exist';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n #ProcessError();\r\n EndIf;\r\n \r\n nIndex = nIndex + 1;\r\n sLastDelim = sChar;\r\n \r\n # Clear the word\r\n sWord = '';\r\n Else;\r\n sWord = sWord | sChar;\r\n EndIf;\r\n \r\n EndIf;\r\n \r\n EndIf;\r\n \r\n nChar = nChar + nAddExtra + 1;\r\n END;\r\n\r\n ### Check for errors before continuing\r\n If( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n EndIf;\r\n \r\n If( sTargetFilter @= '' );\r\n sTargetFilter = sImportedFilter;\r\n Else;\r\n sTargetFilter = sTargetFilter | sDelimDim | sImportedFilter;\r\n EndIf;\r\n ### Determine target dimension substitution in data clear filter\r\n If( pDimension @<>'');\r\n If( sTargetFilter @= '' );\r\n sTargetFilter = pDimension | sElementStartDelim | sTargetElement;\r\n Else;\r\n ### Remove spaces from the string, then remove source element from the filter if present\r\n sTargetFilter = UPPER( sTargetFilter );\r\n nSPIndex = SCAN( ' ', sTargetFilter );\r\n While ( nSPIndex <> 0);\r\n sTargetFilter = DELET( sTargetFilter, nSPIndex, 1 );\r\n nSPIndex = SCAN( ' ', sTargetFilter );\r\n End;\r\n sRemoveString = UPPER( sDelimDim | pDimension | sElementStartDelim | pSrcEle );\r\n nRemoveIndex = SCAN( sRemoveString, sTargetFilter );\r\n If( nRemoveIndex <> 0 );\r\n sTargetFilter = DELET( sTargetFilter, nRemoveIndex, Long(sRemoveString) );\r\n EndIf;\r\n sRemoveString2 = UPPER( pDimension | sElementStartDelim | pSrcEle | sDelimDim );\r\n nRemoveIndex = SCAN( sRemoveString2, sTargetFilter );\r\n If( nRemoveIndex <> 0 );\r\n sTargetFilter = DELET( sTargetFilter, nRemoveIndex, Long(sRemoveString2) );\r\n EndIf;\r\n sRemoveString3 = UPPER( sDelimDim | pDimension | sElementStartDelim | sSourceElement );\r\n nRemoveIndex = SCAN( sRemoveString3, sTargetFilter );\r\n If( nRemoveIndex <> 0 );\r\n sTargetFilter = DELET( sTargetFilter, nRemoveIndex, Long(sRemoveString3) );\r\n EndIf;\r\n sRemoveString4 = UPPER( pDimension | sElementStartDelim | sSourceElement | sDelimDim );\r\n nRemoveIndex = SCAN( sRemoveString4, sTargetFilter );\r\n If( nRemoveIndex <> 0 );\r\n sTargetFilter = DELET( sTargetFilter, nRemoveIndex, Long(sRemoveString4) );\r\n EndIf;\r\n ## Add target element to the filter\r\n sTargetFilter = sTargetFilter | sDelimDim | pDimension | sElementStartDelim | sTargetElement;\r\n EndIf;\r\n Endif;\r\n \r\n nRet = ExecuteProcess('}bedrock.cube.data.clear',\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pCube', pCube,\r\n 'pView', '',\r\n 'pFilter', sTargetFilter,\r\n 'pFilterParallel', '',\r\n 'pParallelThreads', 0,\r\n 'pDimDelim', sImportedDelimDim,\r\n 'pEleStartDelim', sImportedElementStartDelim,\r\n 'pEleDelim', sImportedDelimElem,\r\n 'pCubeLogging', pCubeLogging,\r\n 'pTemp', 1,\r\n 'pSandbox', pSandbox\r\n );\r\n \r\n If(nRet <> 0);\r\n sMessage = 'Error zeroing out target slice corresponding to the filter.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n ENDIF;\r\n ENDIF;\r\n If( pZeroFilter > 0 );\r\n ItemSkip;\r\n ENDIF;\r\nEndif;\r\n\r\n### Determine target dimension SubStitution ###\r\nIf( pDimension @<>'');\r\n \r\n If(sSourceElement@<>Expand('%v'|numbertostring(nSubstututeDimensionIndex+1)|'%'));\r\n # leave variable as is\r\n Else; \r\n \r\n v2 = If(nSubstututeDimensionIndex = 1, sTargetElement, v2);\r\n v3 = If(nSubstututeDimensionIndex = 2, sTargetElement, v3);\r\n v4 = If(nSubstututeDimensionIndex = 3, sTargetElement, v4);\r\n v5 = If(nSubstututeDimensionIndex = 4, sTargetElement, v5);\r\n v6 = If(nSubstututeDimensionIndex = 5, sTargetElement, v6);\r\n v7 = If(nSubstututeDimensionIndex = 6, sTargetElement, v7);\r\n v8 = If(nSubstututeDimensionIndex = 7, sTargetElement, v8);\r\n v9 = If(nSubstututeDimensionIndex = 8, sTargetElement, v9);\r\n v10 = If(nSubstututeDimensionIndex = 9, sTargetElement, v10);\r\n v11 = If(nSubstututeDimensionIndex = 10, sTargetElement, v11);\r\n v12 = If(nSubstututeDimensionIndex = 11, sTargetElement, v12);\r\n v13 = If(nSubstututeDimensionIndex = 12, sTargetElement, v13);\r\n v14 = If(nSubstututeDimensionIndex = 13, sTargetElement, v14);\r\n v15 = If(nSubstututeDimensionIndex = 14, sTargetElement, v15);\r\n v16 = If(nSubstututeDimensionIndex = 15, sTargetElement, v16);\r\n v17 = If(nSubstututeDimensionIndex = 16, sTargetElement, v17);\r\n v18 = If(nSubstututeDimensionIndex = 17, sTargetElement, v18);\r\n v19 = If(nSubstututeDimensionIndex = 18, sTargetElement, v19);\r\n v20 = If(nSubstututeDimensionIndex = 19, sTargetElement, v20);\r\n v21 = If(nSubstututeDimensionIndex = 20, sTargetElement, v21);\r\n v22 = If(nSubstututeDimensionIndex = 21, sTargetElement, v22);\r\n v23 = If(nSubstututeDimensionIndex = 22, sTargetElement, v23);\r\n v24 = If(nSubstututeDimensionIndex = 23, sTargetElement, v24);\r\n v25 = If(nSubstututeDimensionIndex = 24, sTargetElement, v25);\r\n v26 = If(nSubstututeDimensionIndex = 25, sTargetElement, v26);\r\n v27 = If(nSubstututeDimensionIndex = 26, sTargetElement, v27);\r\n EndIf;\r\n\r\nEndif;\r\n\r\n### Determine dimension Mapping SubStitution ###\r\nsV2 =If(nMappedDim1=1, Expand('%'|sMappedV1|'%'), If(nNewDim1=1, sNewV1,V1));\r\nsV3 =If(nMappedDim2=1, Expand('%'|sMappedV2|'%'), If(nNewDim2=1, sNewV2,V2));\r\nsV4 =If(nMappedDim3=1, Expand('%'|sMappedV3|'%'), If(nNewDim3=1, sNewV3,V3));\r\nsV5 =If(nMappedDim4=1, Expand('%'|sMappedV4|'%'), If(nNewDim4=1, sNewV4,V4));\r\nsV6 =If(nMappedDim5=1, Expand('%'|sMappedV5|'%'), If(nNewDim5=1, sNewV5,V5));\r\nsV7 =If(nMappedDim6=1, Expand('%'|sMappedV6|'%'), If(nNewDim6=1, sNewV6,V6));\r\nsV8 =If(nMappedDim7=1, Expand('%'|sMappedV7|'%'), If(nNewDim7=1, sNewV7,V7));\r\nsV9 =If(nMappedDim8=1, Expand('%'|sMappedV8|'%'), If(nNewDim8=1, sNewV8,V8));\r\nsV10 =If(nMappedDim9=1, Expand('%'|sMappedV9|'%'), If(nNewDim9=1, sNewV9,V9));\r\nsV11=If(nMappedDim10=1, Expand('%'|sMappedV10|'%'),If(nNewDim10=1,sNewV10,V10));\r\nsV12=If(nMappedDim11=1, Expand('%'|sMappedV11|'%'),If(nNewDim11=1,sNewV11,V11));\r\nsV13=If(nMappedDim12=1, Expand('%'|sMappedV12|'%'),If(nNewDim12=1,sNewV12,V12)); \r\nsV14=If(nMappedDim13=1, Expand('%'|sMappedV13|'%'),If(nNewDim13=1,sNewV13,V13)); \r\nsV15=If(nMappedDim14=1, Expand('%'|sMappedV14|'%'),If(nNewDim14=1,sNewV14,V14)); \r\nsV16=If(nMappedDim15=1, Expand('%'|sMappedV15|'%'),If(nNewDim15=1,sNewV15,V15)); \r\nsV17=If(nMappedDim16=1, Expand('%'|sMappedV16|'%'),If(nNewDim16=1,sNewV16,V16)); \r\nsV18=If(nMappedDim17=1, Expand('%'|sMappedV17|'%'),If(nNewDim17=1,sNewV17,V17)); \r\nsV19=If(nMappedDim18=1, Expand('%'|sMappedV18|'%'),If(nNewDim18=1,sNewV18,V18)); \r\nsV20=If(nMappedDim19=1, Expand('%'|sMappedV19|'%'),If(nNewDim19=1,sNewV19,V19)); \r\nsV21=If(nMappedDim20=1, Expand('%'|sMappedV20|'%'),If(nNewDim20=1,sNewV20,V20)); \r\nsV22=If(nMappedDim21=1, Expand('%'|sMappedV21|'%'),If(nNewDim21=1,sNewV21,V21)); \r\nsV23=If(nMappedDim22=1, Expand('%'|sMappedV22|'%'),If(nNewDim22=1,sNewV22,V22)); \r\nsV24=If(nMappedDim23=1, Expand('%'|sMappedV23|'%'),If(nNewDim23=1,sNewV23,V23)); \r\nsV25=If(nMappedDim24=1, Expand('%'|sMappedV24|'%'),If(nNewDim24=1,sNewV24,V24)); \r\nsV26=If(nMappedDim25=1, Expand('%'|sMappedV25|'%'),If(nNewDim25=1,sNewV25,V25)); \r\nsV27=If(nMappedDim26=1, Expand('%'|sMappedV26|'%'),If(nNewDim26=1,sNewV26,V26)); \r\nsV28=If(nMappedDim27=1, Expand('%'|sMappedV27|'%'),If(nNewDim27=1,sNewV27,V27));\r\nsV29=If(nMappedDim28=1, Expand('%'|sMappedV28|'%'),V28); \r\n \r\nV1 = V1;\r\nV2 = sV2; \r\nV3 = sV3; \r\nV4 = sV4; \r\nV5 = sV5; \r\nV6 = sV6; \r\nV7 = sV7; \r\nV8 = sV8; \r\nV9 = sV9; \r\nV10= sV10;\r\nV11= sV11;\r\nV12= sV12;\r\nV13= sV13;\r\nV14= sV14;\r\nV15= sV15;\r\nV16= sV16;\r\nV17= sV17;\r\nV18= sV18;\r\nV19= sV19;\r\nV20= sV20;\r\nV21= sV21;\r\nV22= sV22;\r\nV23= sV23;\r\nV24= sV24;\r\nV25= sV25;\r\nV26= sV26;\r\nV27= sV27;\r\nV28= sV28;\r\nV29= sV29;\r\n \r\nIf( pSkipInvalidRecords < 1 );\r\n ## Do not check for a valid datapoint (any element that doesn't exist will generate error message on CellPut attempt)\r\nElse;\r\n ## Allow records that do not have a valid datapoint to be skipped.\r\n If( nDimensionCount >= 2 & (DimIx( sDim1, v2 ) = 0 % DimIx( sDim2, v3 ) = 0 ) );\r\n ItemSkip;\r\n EndIf;\r\n \r\n If( nDimensionCount >= 3 & DimIx( sDim3, v4 ) = 0 );\r\n ItemSkip;\r\n EndIf;\r\n\r\n If( nDimensionCount >= 4 & DimIx( sDim4, v5 ) = 0 );\r\n ItemSkip;\r\n EndIf;\r\n \r\n If( nDimensionCount >= 5 & DimIx( sDim5, v6 ) = 0 );\r\n ItemSkip;\r\n EndIf;\r\n\r\n If( nDimensionCount >= 6 & DimIx( sDim6, v7 ) = 0 );\r\n ItemSkip;\r\n EndIf;\r\n\r\n If( nDimensionCount >= 7 & DimIx( sDim7, v8 ) = 0 );\r\n ItemSkip;\r\n EndIf;\r\n \r\n If( nDimensionCount >= 8 & DimIx( sDim8, v9 ) = 0 );\r\n ItemSkip;\r\n EndIf;\r\n \r\n If( nDimensionCount >= 9 & DimIx( sDim9, v10 ) = 0 );\r\n ItemSkip;\r\n EndIf;\r\n \r\n If( nDimensionCount >= 10 & DimIx( sDim10, v11 ) = 0 );\r\n ItemSkip;\r\n EndIf;\r\n \r\n If( nDimensionCount >= 11 & DimIx( sDim11, v12 ) = 0 );\r\n ItemSkip;\r\n EndIf;\r\n \r\n If( nDimensionCount >= 12 & DimIx( sDim12, v13 ) = 0 );\r\n ItemSkip;\r\n EndIf;\r\n \r\n If( nDimensionCount >= 13 & DimIx( sDim13, v14 ) = 0 );\r\n ItemSkip;\r\n EndIf;\r\n \r\n If( nDimensionCount >= 14 & DimIx( sDim14, v15 ) = 0 );\r\n ItemSkip;\r\n EndIf;\r\n \r\n If( nDimensionCount >= 15 & DimIx( sDim15, v16 ) = 0 );\r\n ItemSkip;\r\n EndIf;\r\n \r\n If( nDimensionCount >= 16 & DimIx( sDim16, v17 ) = 0 );\r\n ItemSkip;\r\n EndIf;\r\n \r\n If( nDimensionCount >= 17 & DimIx( sDim17, v18 ) = 0 );\r\n ItemSkip;\r\n EndIf;\r\n \r\n If( nDimensionCount >= 18 & DimIx( sDim18, v19 ) = 0 );\r\n ItemSkip;\r\n EndIf;\r\n \r\n If( nDimensionCount >= 19 & DimIx( sDim19, v20 ) = 0 );\r\n ItemSkip;\r\n EndIf;\r\n \r\n If( nDimensionCount >= 20 & DimIx( sDim20, v21 ) = 0 );\r\n ItemSkip;\r\n EndIf;\r\n \r\n If( nDimensionCount >= 21 & DimIx( sDim21, v22 ) = 0 );\r\n ItemSkip;\r\n EndIf;\r\n \r\n If( nDimensionCount >= 22 & DimIx( sDim22, v23 ) = 0 );\r\n ItemSkip;\r\n EndIf;\r\n \r\n If( nDimensionCount >= 23 & DimIx( sDim23, v24 ) = 0 );\r\n ItemSkip;\r\n EndIf;\r\n\r\n If( nDimensionCount >= 24 & DimIx( sDim24, v25 ) = 0 );\r\n ItemSkip;\r\n EndIf;\r\n \r\n If( nDimensionCount >= 25 & DimIx( sDim25, v26 ) = 0 );\r\n ItemSkip;\r\n EndIf;\r\n \r\n If( nDimensionCount >= 26 & DimIx( sDim25, v27 ) = 0 );\r\n ItemSkip;\r\n EndIf;\r\n \r\n If( nDimensionCount >= 27 & DimIx( sDim27, v28 ) = 0 );\r\n ItemSkip;\r\n EndIf;\r\n\r\nEndIf;\r\n\r\n### Write data from source file to target cube ###\r\n\r\nIf( nDimensionCount = 2 );\r\n If( CellIsUpdateable( pCube, v2, v3 ) = 1 );\r\n sElType = DType( sDim2, v3 );\r\n If( SubSt( sDim2, 1, 19 ) @= '}ElementAttributes_' % SubSt( pCube, 1, 17 ) @= '}ElementSecurity_' );\r\n sDim = sDim1;\r\n EndIf;\r\n If( SubSt( pCube, 1, 17 ) @= '}ElementSecurity_' );\r\n v4 = If( v4 @= '', 'NONE', v4 );\r\n ElementSecurityPut( v4, sDim, v2, v3 );\r\n ElseIf( SubSt( sDim2, 1, 19 ) @= '}ElementAttributes_' );\r\n If( sElType @= 'AS');\r\n AttrPutS( v4, sDim, v2, v3 );\r\n ElseIf( sElType @= 'AA');\r\n AttrPutS( v4, sDim, v2, v3, 1 );\r\n ElseIf( sElType @= 'AN');\r\n AttrPutN( StringToNumberEx(v4, sDecimalSeparator, sThousandSeparator), sDim, v2, v3 );\r\n EndIf;\r\n ElseIf( SubSt( sElType, 1, 1) @= 'A' );\r\n If( sElType @= 'AA' % sElType @= 'AS' );\r\n If( pCube @= '}ChoreAttributes' );\r\n ChoreAttrPutS( v4, v2, v3 );\r\n ElseIf( pCube @= '}CubeAttributes' );\r\n CubeAttrPutS( v4, v2, v3 );\r\n ElseIf( pCube @= '}DimensionAttributes' );\r\n DimensionAttrPutS( v4, v2, v3 );\r\n ElseIf( pCube @= '}ProcessAttributes' );\r\n ProcessAttrPutS( v4, v2, v3 );\r\n EndIf;\r\n ElseIf( sElType @= 'AN');\r\n If( pCube @= '}ChoreAttributes' );\r\n ChoreAttrPutN( StringToNumberEx(v4, sDecimalSeparator, sThousandSeparator), v2, v3 );\r\n ElseIf( pCube @= '}CubeAttributes' );\r\n CubeAttrPutN( StringToNumberEx(v4, sDecimalSeparator, sThousandSeparator), v2, v3 );\r\n ElseIf( pCube @= '}DimensionAttributes' );\r\n DimensionAttrPutN( StringToNumberEx(v4, sDecimalSeparator, sThousandSeparator), v2, v3 );\r\n ElseIf( pCube @= '}ProcessAttributes' );\r\n ProcessAttrPutN( StringToNumberEx(v4, sDecimalSeparator, sThousandSeparator), v2, v3 );\r\n EndIf;\r\n EndIf;\r\n ElseIf( sElType @= 'S');\r\n CellPutS( v4, pCube, v2, v3 );\r\n ElseIf( sElType @= 'N' & DimIx( sDim2, v3 ) <> 0 );\r\n If(pCumulate = 1);\r\n nObal = CellGetN( pCube, v2, v3 );\r\n nCbal = nObal + StringToNumberEx(v4, sDecimalSeparator, sThousandSeparator);\r\n ELSE;\r\n nCbal = StringToNumberEx(v4, sDecimalSeparator, sThousandSeparator);\r\n Endif;\r\n CellPutN( nCbal, pCube, v2, v3 );\r\n Else;\r\n If( pStrictErrorHandling = 1 );\r\n sErr = Expand('Unhandled element type %sElType% of element %v3% in dimension %sDim2%');\r\n ItemReject( sErr );\r\n EndIf;\r\n EndIf;\r\n EndIf;\r\nElseIf( nDimensionCount = 3 );\r\n If( CellIsUpdateable( pCube, v2, v3, v4 ) = 1 );\r\n sElType = DType( sDim3, v4 );\r\n If( SubSt( sElType, 1, 1 ) @= 'A' );\r\n If( SubSt( pCube, 1, 28 ) @= '}LocalizedElementAttributes_' );\r\n sDim = sDim1;\r\n If( sElType @= 'AS' );\r\n AttrPutS(v5, sDim, v2, v4, v3);\r\n ElseIf( sElType @= 'AA' );\r\n AttrPutS(v5, sDim, v2, v4, v3, 1);\r\n ElseIf( sElType @= 'AN' );\r\n AttrPutN(StringToNumberEx(v5, sDecimalSeparator, sThousandSeparator), sDim, v2, v4, v3);\r\n EndIf;\r\n ElseIf( pCube @= '}LocalizedChoreAttributes' );\r\n If( sElType @= 'AS' % sElType @= 'AA' );\r\n ChoreAttrPutS(v5, v2, v4, v3);\r\n ElseIf( sElType @= 'AN' );\r\n ChoreAttrPutN(StringToNumberEx(v5, sDecimalSeparator, sThousandSeparator), v2, v4, v3);\r\n EndIf;\r\n ElseIf( pCube @= '}LocalizedCubeAttributes' );\r\n If( sElType @= 'AS' % sElType @= 'AA' );\r\n CubeAttrPutS(v5, v2, v4, v3);\r\n ElseIf( sElType @= 'AN' );\r\n CubeAttrPutN(StringToNumberEx(v5, sDecimalSeparator, sThousandSeparator), v2, v4, v3);\r\n EndIf;\r\n ElseIf( pCube @= '}LocalizedDimensionAttributes' );\r\n If( sElType @= 'AS' % sElType @= 'AA' );\r\n DimensionAttrPutS(v5, v2, v4, v3);\r\n ElseIf( sElType @= 'AN' );\r\n DimensionAttrPutN(StringToNumberEx(v5, sDecimalSeparator, sThousandSeparator), v2, v4, v3);\r\n EndIf;\r\n ElseIf( pCube @= '}LocalizedProcessAttributes' );\r\n If( sElType @= 'AS' % sElType @= 'AA' );\r\n ProcessAttrPutS(v5, v2, v4, v3);\r\n ElseIf( sElType @= 'AN' );\r\n ProcessAttrPutN(StringToNumberEx(v5, sDecimalSeparator, sThousandSeparator), v2, v4, v3);\r\n EndIf;\r\n EndIf;\r\n ElseIf( sElType @= 'N' );\r\n If(pCumulate = 1);\r\n nObal = CellGetN( pCube, v2, v3, v4 );\r\n nCbal = nObal + StringToNumberEx(v5, sDecimalSeparator, sThousandSeparator);\r\n ELSE;\r\n nCbal = StringToNumberEx(v5, sDecimalSeparator, sThousandSeparator);\r\n Endif;\r\n CellPutN( nCbal, pCube, v2, v3, v4 );\r\n ElseIf( sElType @= 'S' );\r\n CellPutS( v5, pCube, v2, v3, v4 );\r\n Else;\r\n If( pStrictErrorHandling = 1 );\r\n sErr = Expand('Unhandled element type %sElType% of element %v4% in dimension %sDim3%');\r\n ItemReject( sErr );\r\n EndIf;\r\n EndIf;\r\n EndIf;\r\nElseIf( nDimensionCount = 4 );\r\n If( CellIsUpdateable( pCube, v2, v3, v4, v5 ) = 1 );\r\n sElType = DType( sDim4, v5 );\r\n If( sElType @= 'N' );\r\n If(pCumulate = 1);\r\n nObal = CellGetN( pCube, v2, v3, v4, v5 );\r\n nCbal = nObal + StringToNumberEx(v6, sDecimalSeparator, sThousandSeparator);\r\n ELSE;\r\n nCbal = StringToNumberEx(v6, sDecimalSeparator, sThousandSeparator);\r\n Endif;\r\n CellPutN( nCbal, pCube, v2, v3, v4, v5 );\r\n ElseIf( sElType @= 'S' );\r\n CellPutS( v6, pCube, v2, v3, v4, v5 );\r\n Else;\r\n If( pStrictErrorHandling = 1 );\r\n sErr = Expand('Unhandled element type %sElType% of element %v5% in dimension %sDim4%');\r\n ItemReject( sErr );\r\n EndIf;\r\n EndIf;\r\n EndIf;\r\nElseIf( nDimensionCount = 5 );\r\n If( CellIsUpdateable( pCube, v2, v3, v4, v5, v6 ) = 1 );\r\n sElType = DType( sDim5, v6 );\r\n If( sElType @= 'N' );\r\n If(pCumulate = 1);\r\n nObal = CellGetN( pCube, v2, v3, v4, v5, v6 );\r\n nCbal = nObal + StringToNumberEx(v7, sDecimalSeparator, sThousandSeparator);\r\n ELSE;\r\n nCbal = StringToNumberEx(v7, sDecimalSeparator, sThousandSeparator);\r\n Endif;\r\n CellPutN( nCbal, pCube, v2, v3, v4, v5, v6 );\r\n ElseIf( sElType @= 'S' );\r\n CellPutS( v7, pCube, v2, v3, v4, v5, v6 );\r\n Else;\r\n If( pStrictErrorHandling = 1 );\r\n sErr = Expand('Unhandled element type %sElType% of element %v6% in dimension %sDim5%');\r\n ItemReject( sErr );\r\n EndIf;\r\n EndIf;\r\n EndIf;\r\n ElseIf( nDimensionCount = 6 );\r\n If( CellIsUpdateable( pCube, v2, v3, v4, v5, v6, v7 ) = 1 );\r\n sElType = DType( sDim6, v7 );\r\n If( sElType @= 'N' );\r\n If(pCumulate = 1);\r\n nObal = CellGetN( pCube, v2, v3, v4, v5, v6, v7 );\r\n nCbal = nObal + StringToNumberEx(v8, sDecimalSeparator, sThousandSeparator);\r\n ELSE;\r\n nCbal = StringToNumberEx(v8, sDecimalSeparator, sThousandSeparator);\r\n Endif;\r\n CellPutN( nCbal, pCube, v2, v3, v4, v5, v6, v7 );\r\n ElseIf( sElType @= 'S' );\r\n CellPutS( v8, pCube, v2, v3, v4, v5, v6, v7 );\r\n EndIf;\r\n Else;\r\n If( pStrictErrorHandling = 1 );\r\n sErr = Expand('Unhandled element type %sElType% of element %v7% in dimension %sDim6%');\r\n ItemReject( sErr );\r\n EndIf;\r\n EndIf;\r\n ElseIf( nDimensionCount = 7 );\r\n If( CellIsUpdateable( pCube, v2, v3, v4, v5, v6, v7, v8 ) = 1 );\r\n sElType = DType( sDim7, v8 );\r\n If( sElType @= 'N' );\r\n If( pCumulate = 1);\r\n nObal = CellGetN( pCube, v2, v3, v4, v5, v6, v7, v8 );\r\n nCbal = nObal + StringToNumberEx(v9, sDecimalSeparator, sThousandSeparator);\r\n ELSE;\r\n nCbal = StringToNumberEx(v9, sDecimalSeparator, sThousandSeparator);\r\n Endif;\r\n CellPutN( nCbal, pCube, v2, v3, v4, v5, v6, v7, v8 );\r\n ElseIf( sElType @= 'S' );\r\n CellPutS( v9, pCube, v2, v3, v4, v5, v6, v7, v8 );\r\n Else;\r\n If( pStrictErrorHandling = 1 );\r\n sErr = Expand('Unhandled element type %sElType% of element %v8% in dimension %sDim7%');\r\n ItemReject( sErr );\r\n EndIf;\r\n EndIf;\r\n EndIf;\r\n ElseIf( nDimensionCount = 8 );\r\n If( CellIsUpdateable( pCube, v2, v3, v4, v5, v6, v7, v8, v9 ) = 1 );\r\n sElType = DType( sDim8, v9 );\r\n If( sElType @= 'N' );\r\n If( pCumulate = 1);\r\n nObal = CellGetN( pCube, v2, v3, v4, v5, v6, v7, v8, v9 );\r\n nCbal = nObal + StringToNumberEx(v10, sDecimalSeparator, sThousandSeparator);\r\n ELSE;\r\n nCbal = StringToNumberEx(v10, sDecimalSeparator, sThousandSeparator);\r\n Endif;\r\n CellPutN( nCbal, pCube, v2, v3, v4, v5, v6, v7, v8, v9 );\r\n ElseIf( sElType @= 'S' );\r\n CellPutS( v10, pCube, v2, v3, v4, v5, v6, v7, v8, v9 );\r\n Else;\r\n If( pStrictErrorHandling = 1 );\r\n sErr = Expand('Unhandled element type %sElType% of element %v9% in dimension %sDim8%');\r\n ItemReject( sErr );\r\n EndIf;\r\n EndIf;\r\n EndIf;\r\n ElseIf( nDimensionCount = 9 );\r\n If( CellIsUpdateable( pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10 ) = 1 );\r\n sElType = DType( sDim9, v10 );\r\n If( sElType @= 'N' );\r\n If( pCumulate = 1);\r\n nObal = CellGetN( pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10 );\r\n nCbal = nObal + StringToNumberEx(v11, sDecimalSeparator, sThousandSeparator);\r\n ELSE;\r\n nCbal = StringToNumberEx(v11, sDecimalSeparator, sThousandSeparator);\r\n Endif;\r\n CellPutN( nCbal, pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10 );\r\n ElseIf( sElType @= 'S' );\r\n CellPutS( v11, pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10 );\r\n Else;\r\n If( pStrictErrorHandling = 1 );\r\n sErr = Expand('Unhandled element type %sElType% of element %v10% in dimension %sDim9%');\r\n ItemReject( sErr );\r\n EndIf;\r\n EndIf;\r\n EndIf;\r\n ElseIf( nDimensionCount = 10 );\r\n If( CellIsUpdateable( pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11 ) = 1 );\r\n sElType = DType( sDim10, v11 );\r\n If( sElType @= 'N' );\r\n If(pCumulate = 1);\r\n nObal = CellGetN( pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11 );\r\n nCbal = nObal + StringToNumberEx(v12, sDecimalSeparator, sThousandSeparator);\r\n ELSE;\r\n nCbal = StringToNumberEx(v12, sDecimalSeparator, sThousandSeparator);\r\n Endif;\r\n CellPutN( nCbal, pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11 );\r\n ElseIf( sElType @= 'S' );\r\n CellPutS( v12, pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11 );\r\n Else;\r\n If( pStrictErrorHandling = 1 );\r\n sErr = Expand('Unhandled element type %sElType% of element %v11% in dimension %sDim10%');\r\n ItemReject( sErr );\r\n EndIf;\r\n EndIf;\r\n EndIf;\r\n ElseIf( nDimensionCount = 11 );\r\n If( CellIsUpdateable( pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12 ) = 1 );\r\n sElType = DType( sDim11, v12 );\r\n If( sElType @= 'N' );\r\n If(pCumulate = 1);\r\n nObal = CellGetN( pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12 );\r\n nCbal = nObal + StringToNumberEx(v13, sDecimalSeparator, sThousandSeparator);\r\n ELSE;\r\n nCbal = StringToNumberEx(v13, sDecimalSeparator, sThousandSeparator);\r\n Endif;\r\n CellPutN( nCbal, pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12 );\r\n ElseIf( sElType @= 'S' );\r\n CellPutS( v13, pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12 );\r\n Else;\r\n If( pStrictErrorHandling = 1 );\r\n sErr = Expand('Unhandled element type %sElType% of element %v12% in dimension %sDim11%');\r\n ItemReject( sErr );\r\n EndIf;\r\n EndIf;\r\n EndIf;\r\n ElseIf( nDimensionCount = 12 );\r\n If( CellIsUpdateable( pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13 ) = 1 );\r\n sElType = DType( sDim12, v13 );\r\n If( sElType @= 'N' );\r\n If( pCumulate = 1);\r\n nObal = CellGetN( pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13 );\r\n nCbal = nObal + StringToNumberEx(v14, sDecimalSeparator, sThousandSeparator);\r\n ELSE;\r\n nCbal = StringToNumberEx(v14, sDecimalSeparator, sThousandSeparator);\r\n Endif;\r\n CellPutN( nCbal, pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13 );\r\n ElseIf( sElType @= 'S' );\r\n CellPutS( v14, pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13 );\r\n Else;\r\n If( pStrictErrorHandling = 1 );\r\n sErr = Expand('Unhandled element type %sElType% of element %v13% in dimension %sDim12%');\r\n ItemReject( sErr );\r\n EndIf;\r\n EndIf;\r\n EndIf;\r\n ElseIf( nDimensionCount = 13 );\r\n If( CellIsUpdateable( pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14 ) = 1 );\r\n sElType = DType( sDim13, v14 );\r\n If( sElType @= 'N' );\r\n If(pCumulate = 1);\r\n nObal = CellGetN( pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14 );\r\n nCbal = nObal + StringToNumberEx(v15, sDecimalSeparator, sThousandSeparator);\r\n ELSE;\r\n nCbal = StringToNumberEx(v15, sDecimalSeparator, sThousandSeparator);\r\n Endif;\r\n CellPutN( nCbal, pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14 );\r\n ElseIf( sElType @= 'S' );\r\n CellPutS( v15, pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14 );\r\n Else;\r\n If( pStrictErrorHandling = 1 );\r\n sErr = Expand('Unhandled element type %sElType% of element %v14% in dimension %sDim13%');\r\n ItemReject( sErr );\r\n EndIf;\r\n EndIf;\r\n EndIf;\r\n ElseIf( nDimensionCount = 14 );\r\n If( CellIsUpdateable( pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15 ) = 1 );\r\n sElType = DType( sDim14, v15 );\r\n If( sElType @= 'N' );\r\n If(pCumulate = 1);\r\n nObal = CellGetN( pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15 );\r\n nCbal = nObal + StringToNumberEx(v16, sDecimalSeparator, sThousandSeparator);\r\n ELSE;\r\n nCbal = StringToNumberEx(v16, sDecimalSeparator, sThousandSeparator);\r\n Endif;\r\n CellPutN( nCbal, pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15 );\r\n ElseIf( sElType @= 'S' );\r\n CellPutS( v16, pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15 );\r\n Else;\r\n If( pStrictErrorHandling = 1 );\r\n sErr = Expand('Unhandled element type %sElType% of element %v15% in dimension %sDim14%');\r\n ItemReject( sErr );\r\n EndIf;\r\n EndIf;\r\n EndIf;\r\n ElseIf( nDimensionCount = 15 );\r\n If( CellIsUpdateable( pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16 ) = 1 );\r\n sElType = DType( sDim15, v16 );\r\n If( sElType @= 'N' );\r\n If(pCumulate = 1);\r\n nObal = CellGetN( pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16 );\r\n nCbal = nObal + StringToNumberEx(v17, sDecimalSeparator, sThousandSeparator);\r\n ELSE;\r\n nCbal = StringToNumberEx(v17, sDecimalSeparator, sThousandSeparator);\r\n Endif;\r\n CellPutN( nCbal, pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16 );\r\n ElseIf( sElType @= 'S' );\r\n CellPutS( v17, pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16 );\r\n Else;\r\n If( pStrictErrorHandling = 1 );\r\n sErr = Expand('Unhandled element type %sElType% of element %v16% in dimension %sDim15%');\r\n ItemReject( sErr );\r\n EndIf;\r\n EndIf;\r\n EndIf;\r\n ElseIf( nDimensionCount = 16 );\r\n If( CellIsUpdateable( pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17 ) = 1 );\r\n sElType = DType( sDim16, v17 );\r\n If(pCumulate = 1);\r\n nObal = CellGetN( pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17 );\r\n nCbal = nObal + StringToNumberEx(v18, sDecimalSeparator, sThousandSeparator);\r\n ELSE;\r\n nCbal = StringToNumberEx(v18, sDecimalSeparator, sThousandSeparator);\r\n Endif;\r\n If( sElType @= 'N' );\r\n CellPutN( nCbal, pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17 );\r\n ElseIf( sElType @= 'S' );\r\n CellPutS( v18, pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17 );\r\n Else;\r\n If( pStrictErrorHandling = 1 );\r\n sErr = Expand('Unhandled element type %sElType% of element %v17% in dimension %sDim16%');\r\n ItemReject( sErr );\r\n EndIf;\r\n EndIf;\r\n EndIf;\r\n ElseIf( nDimensionCount = 17 );\r\n If( CellIsUpdateable( pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18 ) = 1 );\r\n sElType = DType( sDim17, v18 );\r\n If( sElType @= 'N' );\r\n If(pCumulate = 1);\r\n nObal = CellGetN( pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18 );\r\n nCbal = nObal + StringToNumberEx(v19, sDecimalSeparator, sThousandSeparator);\r\n ELSE;\r\n nCbal = StringToNumberEx(v19, sDecimalSeparator, sThousandSeparator);\r\n Endif;\r\n CellPutN( nCbal, pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18 );\r\n ElseIf( sElType @= 'S' );\r\n CellPutS( v19, pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18 );\r\n Else;\r\n If( pStrictErrorHandling = 1 );\r\n sErr = Expand('Unhandled element type %sElType% of element %v18% in dimension %sDim17%');\r\n ItemReject( sErr );\r\n EndIf;\r\n EndIf;\r\n EndIf;\r\n ElseIf( nDimensionCount = 18 );\r\n If( CellIsUpdateable( pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19 ) = 1 );\r\n sElType = DType( sDim18, v19 );\r\n If( sElType @= 'N' );\r\n If(pCumulate = 1);\r\n nObal = CellGetN( pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19 );\r\n nCbal = nObal + StringToNumberEx(v20, sDecimalSeparator, sThousandSeparator);\r\n ELSE;\r\n nCbal = StringToNumberEx(v20, sDecimalSeparator, sThousandSeparator);\r\n Endif;\r\n CellPutN( nCbal, pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19 );\r\n ElseIf( sElType @= 'S' );\r\n CellPutS( v20, pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19 );\r\n Else;\r\n If( pStrictErrorHandling = 1 );\r\n sErr = Expand('Unhandled element type %sElType% of element %v19% in dimension %sDim18%');\r\n ItemReject( sErr );\r\n EndIf;\r\n EndIf;\r\n EndIf;\r\n ElseIf( nDimensionCount = 19 );\r\n If( CellIsUpdateable( pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20 ) = 1 );\r\n sElType = DType( sDim19, v20 );\r\n If( sElType @= 'N' );\r\n If(pCumulate = 1);\r\n nObal = CellGetN( pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20 );\r\n nCbal = nObal + StringToNumberEx(v21, sDecimalSeparator, sThousandSeparator);\r\n ELSE;\r\n nCbal = StringToNumberEx(v21, sDecimalSeparator, sThousandSeparator);\r\n Endif;\r\n CellPutN( nCbal, pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20 );\r\n ElseIf( sElType @= 'S' );\r\n CellPutS( v21, pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20 );\r\n Else;\r\n If( pStrictErrorHandling = 1 );\r\n sErr = Expand('Unhandled element type %sElType% of element %v20% in dimension %sDim19%');\r\n ItemReject( sErr );\r\n EndIf;\r\n EndIf;\r\n EndIf;\r\n ElseIf( nDimensionCount = 20 );\r\n If( CellIsUpdateable( pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21 ) = 1 );\r\n sElType = DType( sDim20, v21 );\r\n If( sElType @= 'N' );\r\n If(pCumulate = 1);\r\n nObal = CellGetN( pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21 );\r\n nCbal = nObal + StringToNumberEx(v22, sDecimalSeparator, sThousandSeparator);\r\n ELSE;\r\n nCbal = StringToNumberEx(v22, sDecimalSeparator, sThousandSeparator);\r\n Endif;\r\n CellPutN( nCbal, pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21 );\r\n ElseIf( sElType @= 'S' );\r\n CellPutS( v22, pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21 );\r\n Else;\r\n If( pStrictErrorHandling = 1 );\r\n sErr = Expand('Unhandled element type %sElType% of element %v21% in dimension %sDim20%');\r\n ItemReject( sErr );\r\n EndIf;\r\n EndIf;\r\n EndIf;\r\n ElseIf( nDimensionCount = 21 );\r\n If( CellIsUpdateable( pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22 ) = 1 );\r\n sElType = DType( sDim21, v22 );\r\n If( sElType @= 'N' );\r\n If(pCumulate = 1);\r\n nObal = CellGetN( pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22 );\r\n nCbal = nObal + StringToNumberEx(v23, sDecimalSeparator, sThousandSeparator);\r\n ELSE;\r\n nCbal = StringToNumberEx(v23, sDecimalSeparator, sThousandSeparator);\r\n Endif;\r\n CellPutN( nCbal, pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22 );\r\n ElseIf( sElType @= 'S' );\r\n CellPutS( v23, pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22 );\r\n Else;\r\n If( pStrictErrorHandling = 1 );\r\n sErr = Expand('Unhandled element type %sElType% of element %v22% in dimension %sDim21%');\r\n ItemReject( sErr );\r\n EndIf;\r\n EndIf;\r\n EndIf;\r\n ElseIf( nDimensionCount = 22 );\r\n If( CellIsUpdateable( pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23 ) = 1 );\r\n sElType = DType( sDim22, v23 );\r\n If( sElType @= 'N' );\r\n If(pCumulate = 1);\r\n nObal = CellGetN( pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23 );\r\n nCbal = nObal + StringToNumberEx(v24, sDecimalSeparator, sThousandSeparator);\r\n ELSE;\r\n nCbal = StringToNumberEx(v24, sDecimalSeparator, sThousandSeparator);\r\n Endif;\r\n CellPutN( nCbal, pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23 );\r\n ElseIf( sElType @= 'S' );\r\n CellPutS( v24, pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23 );\r\n Else;\r\n If( pStrictErrorHandling = 1 );\r\n sErr = Expand('Unhandled element type %sElType% of element %v23% in dimension %sDim22%');\r\n ItemReject( sErr );\r\n EndIf;\r\n EndIf;\r\n EndIf;\r\n ElseIf( nDimensionCount = 23 );\r\n If( CellIsUpdateable( pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22,\r\n v23, v24 ) = 1 );\r\n sElType = DType( sDim23, v24 );\r\n If( sElType @= 'N' );\r\n If(pCumulate = 1);\r\n nObal = CellGetN( pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22,\r\n v23, v24 );\r\n nCbal = nObal + StringToNumberEx(v25, sDecimalSeparator, sThousandSeparator);\r\n ELSE;\r\n nCbal = StringToNumberEx(v25, sDecimalSeparator, sThousandSeparator);\r\n Endif;\r\n CellPutN( nCbal, pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24 );\r\n ElseIf( sElType @= 'S' );\r\n CellPutS( v25, pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24 );\r\n Else;\r\n If( pStrictErrorHandling = 1 );\r\n sErr = Expand('Unhandled element type %sElType% of element %v24% in dimension %sDim23%');\r\n ItemReject( sErr );\r\n EndIf;\r\n EndIf;\r\n EndIf;\r\n ElseIf( nDimensionCount = 24 );\r\n If( CellIsUpdateable( pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22,\r\n v23, v24, v25 ) = 1 );\r\n sElType = DType( sDim24, v25 );\r\n If( sElType @= 'N' );\r\n If(pCumulate = 1);\r\n nObal = CellGetN( pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22,\r\n v23, v24, v25 );\r\n nCbal = nObal + StringToNumberEx(v26, sDecimalSeparator, sThousandSeparator);\r\n ELSE;\r\n nCbal = StringToNumberEx(v26, sDecimalSeparator, sThousandSeparator);\r\n Endif;\r\n CellPutN( nCbal, pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25 );\r\n ElseIf( sElType @= 'S' );\r\n CellPutS( v26, pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25 );\r\n Else;\r\n If( pStrictErrorHandling = 1 );\r\n sErr = Expand('Unhandled element type %sElType% of element %v25% in dimension %sDim24%');\r\n ItemReject( sErr );\r\n EndIf;\r\n EndIf;\r\n EndIf;\r\n ElseIf( nDimensionCount = 25 );\r\n If( CellIsUpdateable( pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26 ) = 1 );\r\n sElType = DType( sDim25, v26 );\r\n If( sElType @= 'N' );\r\n If(pCumulate = 1);\r\n nObal = CellGetN( pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26 );\r\n nCbal = nObal + StringToNumberEx(v27, sDecimalSeparator, sThousandSeparator);\r\n ELSE;\r\n nCbal = StringToNumberEx(v27, sDecimalSeparator, sThousandSeparator);\r\n Endif;\r\n CellPutN( nCbal, pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26 );\r\n ElseIf( sElType @= 'S' );\r\n CellPutS( v27, pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26 );\r\n Else;\r\n If( pStrictErrorHandling = 1 );\r\n sErr = Expand('Unhandled element type %sElType% of element %v26% in dimension %sDim25%');\r\n ItemReject( sErr );\r\n EndIf;\r\n EndIf;\r\n EndIf;\r\nElseIf( nDimensionCount = 26 );\r\n If( CellIsUpdateable( pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27 ) = 1 );\r\n sElType = DType( sDim26, v27 );\r\n If( sElType @= 'N' );\r\n If( pCumulate = 1);\r\n nObal = CellGetN( pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27 );\r\n nCbal = nObal + StringToNumberEx(v28, sDecimalSeparator, sThousandSeparator);\r\n ELSE;\r\n nCbal = StringToNumberEx(v28, sDecimalSeparator, sThousandSeparator);\r\n Endif;\r\n CellPutN( nCbal, pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27 );\r\n ElseIf( sElType @= 'S' );\r\n CellPutS( v28, pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27 );\r\n Else;\r\n If( pStrictErrorHandling = 1 );\r\n sErr = Expand('Unhandled element type %sElType% of element %v27% in dimension %sDim26%');\r\n ItemReject( sErr );\r\n EndIf;\r\n EndIf;\r\n EndIf;\r\nElseIf( nDimensionCount = 27 );\r\n If( CellIsUpdateable( pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28 ) = 1 );\r\n sElType = DType( sDim27, v28 );\r\n If( sElType @= 'N' );\r\n If(pCumulate = 1);\r\n nObal = CellGetN( pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28 );\r\n nCbal = nObal + StringToNumberEx(v29, sDecimalSeparator, sThousandSeparator);\r\n ELSE;\r\n nCbal = StringToNumberEx(v29, sDecimalSeparator, sThousandSeparator);\r\n Endif;\r\n CellPutN( nCbal, pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28 );\r\n ElseIf( sElType @= 'S' );\r\n CellPutS( v29, pCube, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28 );\r\n Else;\r\n If( pStrictErrorHandling = 1 );\r\n sErr = Expand('Unhandled element type %sElType% of element %v28% in dimension %sDim27%');\r\n ItemReject( sErr );\r\n EndIf;\r\n EndIf;\r\n EndIf;\r\n\r\n\r\n EndIf;\r\n \r\n## Increase Record count\r\nnRecordPostedCount = nRecordPostedCount + 1;\r\n### End Data ###", "EpilogProcedure": "#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n### Delete source file (only if no errors) ###\r\nIf( nErrors = 0 & pFileDelete = 1 );\r\n ASCIIDelete(sFile);\r\nEndIf;\r\n \r\n### If errors occurred terminate process with a major error status ###\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 major error and consequently aborted. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% aborted. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nEndIf;\r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully imported data from file %sFile%.' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n### End Epilog ###", "HasSecurityAccess": true, - "UIData": "_ParameterConstraints=e30=\f", + "UIData": "", "DataSource": { "Type": "ASCII", "asciiDecimalSeparator": ".", @@ -18,93 +18,81 @@ "dataSourceNameForServer": "C:/TM1/Bedrock/Data/Bedrock.Z.Cube.Placeholder.csv" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pCube", - "Prompt": "REQUIRED: Target Cube", + "Prompt": "REQUIRED: Cube name", "Value": "", "Type": "String" }, { "Name": "pSrcDir", - "Prompt": "OPTIONAL: Source Directory (will default to error log path)", + "Prompt": "OPTIONAL: File directory (Default = GetProcessErrorFileDirectory)", "Value": "", "Type": "String" }, { "Name": "pSrcFile", - "Prompt": "OPTIONAL: Source File (will default to pCube_Export.csv )", + "Prompt": "OPTIONAL: File name (Default = pCube | '_Export.csv')", "Value": "", "Type": "String" }, { "Name": "pDim", - "Prompt": "OPTIONAL: Dimension", + "Prompt": "OPTIONAL: Dimension name for element substitution", "Value": "", "Type": "String" }, { "Name": "pSrcEle", - "Prompt": "OPTIONAL: Source Element ( Only required if a Dimension is used.)", + "Prompt": "OPTIONAL: Source element for element substitution", "Value": "", "Type": "String" }, { "Name": "pTgtEle", - "Prompt": "OPTIONAL: Target Element (Only required if Dimension is used.)", + "Prompt": "OPTIONAL: Target element for element substitution", "Value": "", "Type": "String" }, { "Name": "pTitleRows", - "Prompt": "REQUIRED: Number of Title Rows to Skip", + "Prompt": "OPTIONAL: Number of title rows to skip (Default = 1)", "Value": 1, "Type": "Numeric" }, { "Name": "pDelim", - "Prompt": "REQUIRED: AsciiOutput delimiter character (Default=comma, 2 or 3 digits = ASCII code)", - "Value": ",", + "Prompt": "OPTIONAL: AsciiOutput delimiter character (2 or 3 digits = ASCII code. Default = ',')", + "Value": "", "Type": "String" }, { "Name": "pQuote", - "Prompt": "REQUIRED: Quote (Accepts empty quote, 2 or 3 digits = ASCII code)", + "Prompt": "OPTIONAL: Quote character (2 or 3 digits = ASCII code. Default = '\"')", "Value": "\"", "Type": "String" }, { "Name": "pDecimalSeparator", - "Prompt": "OPTIONAL: Decimal separator for conversion of number to string and string to number (default = '.' exactly 3 digits = ASCII code)", + "Prompt": "OPTIONAL: Decimal separator for string/number conversion (Exactly 3 digits = ASCII code. Default ='.')", "Value": ".", "Type": "String" }, { "Name": "pThousandSeparator", - "Prompt": "OPTIONAL: Thousand separator for conversion of number to string and string to number (default = ',' exactly 3 digits = ASCII code)", + "Prompt": "OPTIONAL: Thousand separator for string/number conversion (Exactly 3 digits = ASCII code. Default = ',')", "Value": ",", "Type": "String" }, { "Name": "pCumulate", - "Prompt": "REQUIRED: Accumulate Amounts (0 = Overwrite values, 1 = Accumulate values)", + "Prompt": "OPTIONAL: Accumulate amounts (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { "Name": "pSandbox", - "Prompt": "OPTIONAL: To use sandbox not base data enter the sandbox name (invalid name will result in process error)", + "Prompt": "OPTIONAL: Use sandbox", "Value": "", "Type": "String" }, @@ -116,43 +104,55 @@ }, { "Name": "pMappingToNewDims", - "Prompt": "REQUIRED IF TARGET HAS DIMS NOT IN SOURCE: DimX\u00a6InputElementForDimX & DimY\u00a6InputElementForDimY (specify an N level element for each new dim)", + "Prompt": "OPTIONAL: Required if target has dims not in source. Format: 'dim_one\u00a6 el_one & dim_two\u00a6 el_two'", "Value": "", "Type": "String" }, { "Name": "pDimDelim", - "Prompt": "OPTIONAL. Delimiter for start of Dimension/Element set", + "Prompt": "OPTIONAL: Delimiter for start of dimension/element set in filter parameters (Default = '&')", "Value": "&", "Type": "String" }, { "Name": "pEleStartDelim", - "Prompt": "OPTIONAL: Delimiter for start of element list", + "Prompt": "OPTIONAL: Delimiter for start of element list in filter parameters (Default = '\u00a6')", "Value": "\u00a6", "Type": "String" }, { "Name": "pEleDelim", - "Prompt": "OPTIONAL: Delimiter between elements", + "Prompt": "OPTIONAL: Delimiter between elements in filter parameters (Default = '+')", "Value": "+", "Type": "String" }, { "Name": "pCharacterSet", - "Prompt": "OPTIONAL: The output character set (defaults to TM1CS_UTF8 if blank)", + "Prompt": "OPTIONAL: The output character set (Default = 'TM1CS_UTF8')", "Value": "TM1CS_UTF8", "Type": "String" }, { "Name": "pFileDelete", - "Prompt": "OPTIONAL: Delete the source file on conclusion of import (Boolean 1/0, default = 0)", + "Prompt": "OPTIONAL: Delete the file on conclusion of process (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { "Name": "pSkipInvalidRecords", - "Prompt": "OPTIONAL: Skip records with invalid elements rather than creating error log", + "Prompt": "OPTIONAL: Skip records with invalid elements rather than creating error log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, @@ -161,6 +161,12 @@ "Prompt": "OBSOLETE: This parameter does nothing and is only included for backwards compatability", "Value": 0, "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [ @@ -375,36 +381,5 @@ "EndByte": 0 } ], - "VariablesUIData": [ - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f" - ] + "VariablesUIData": [] } \ No newline at end of file diff --git a/bedrock_processes_json/}bedrock.cube.data.save.json b/bedrock_processes_json/}bedrock.cube.data.save.json index b0a4c59..38714be 100644 --- a/bedrock_processes_json/}bedrock.cube.data.save.json +++ b/bedrock_processes_json/}bedrock.cube.data.save.json @@ -10,28 +10,34 @@ "Type": "None" }, "Parameters": [ + { + "Name": "pCube", + "Prompt": "REQUIRED: Cube name", + "Value": "", + "Type": "String" + }, + { + "Name": "pDelim", + "Prompt": "OPTIONAL: Delimiter for list parameters (Default = '&')", + "Value": "&", + "Type": "String" + }, { "Name": "pLogOutput", - "Prompt": "OPTIONAL: write parameters and action summary to server message log (Boolean True = 1)", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { - "Name": "pCube", - "Prompt": "REQUIRED: Save data for this cube (Separated by Delimiter, Accepts Wild card)", - "Value": "", - "Type": "String" - }, - { - "Name": "pDelim", - "Prompt": "OPTIONAL: Delimiter", - "Value": "&", + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters.", + "Value": "{}", "Type": "String" } ], diff --git a/bedrock_processes_json/}bedrock.cube.delete.json b/bedrock_processes_json/}bedrock.cube.delete.json index 549d615..35418d3 100644 --- a/bedrock_processes_json/}bedrock.cube.delete.json +++ b/bedrock_processes_json/}bedrock.cube.delete.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.cube.delete", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.cube.delete', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pCube', '', 'pDelim', '&',\r\n \t'pCtrlObj', 0\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process deletes cube(s).\r\n\r\n# Use case: Intended for cleaning up after development/prototyping.\r\n# 1\\ Delete all cubes not needed after Go Live.\r\n\r\n# Note:\r\n# A list of cubes can be specified and/or wild cards can be used.\r\n# Naturally valid cube name(s) must be specified otherwise the process will abort.\r\n# By default (pCtrlObj) the process will not delete control cubes (i.e. attributes, security etc).\r\n#EndRegion @DOC\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\n\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pCube:%pCube%, pDelim:%pDelim%, pCtrlObj:%pCtrlObj%.' ; \r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\n\r\nnErrors = 0;\r\n\r\n# If blank delimiter specified then convert to default\r\nIf( pDelim @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\n# If no cubes have been specified, then log error message\r\nIf( Trim( pCube ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No cubes specified';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n# If no wildcard and no delimiter, log error message if cubename is invalid \r\nIf( Scan( pDelim, pCube ) = 0 & Scan( '*', pCube ) = 0 & Trim( pCube ) @<> '' & CubeExists( pCube ) = 0 ); \r\n nErrors = 1;\r\n sMessage = 'Cubename ' | pCube | ' is invalid';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### Split parameter into individual cubes and delete ###\r\nsCubes = pCube;\r\nnDelimiterIndex = 1;\r\nsMdx = '';\r\n\r\nWhile( nDelimiterIndex <> 0 );\r\n nDelimiterIndex = Scan( pDelim, sCubes );\r\n If( nDelimiterIndex = 0 );\r\n sCube = sCubes;\r\n Else;\r\n sCube = Trim( SubSt( sCubes, 1, nDelimiterIndex - 1 ) );\r\n sCubes = Trim( Subst( sCubes, nDelimiterIndex + Long(pDelim), Long( sCubes ) ) );\r\n EndIf;\r\n \r\n # Check if a wildcard has been used to specify the Cube name.\r\n # If it hasn't then just delete the Cube if it exists\r\n # If it has then create cubes subset using Wildcard expression in Mdx\r\n If( Scan( '*', sCube ) = 0 );\r\n If( CubeExists( sCube ) = 1 ); \r\n If(Subst(sCube,1,1) @= '}');\r\n If(pCtrlObj = 1);\r\n CubeDestroy( sCube );\r\n Endif;\r\n Else;\r\n CubeDestroy( sCube );\r\n Endif;\r\n Endif;\r\n Else;\r\n # Create subset of cubes using Wildcard\r\n sCubeExp = '\"'|sCube|'\"';\r\n IF( pCtrlObj = 1 );\r\n sMdxPart = '{TM1FILTERBYPATTERN( TM1SUBSETALL( [}Cubes] ) ,'| sCubeExp | ')}';\r\n ELSE;\r\n sMdxPart = '{TM1FILTERBYPATTERN( EXCEPT( TM1SUBSETALL( [}Cubes] ) , TM1FILTERBYPATTERN( TM1SUBSETALL( [}Cubes] ) , \"}*\" ) ) ,'| sCubeExp | ')}'; \r\n ENDIF;\r\n IF( sMdx @= ''); \r\n sMdx = sMdxPart; \r\n ELSE;\r\n sMdx = sMdx | ' + ' | sMdxPart;\r\n ENDIF;\r\n \r\n If( SubsetExists( '}Cubes' , cTempSub ) = 1 );\r\n # If a delimited list of cube names includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( '}Cubes' , cTempSub, sMDX );\r\n Else;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSub, sMDX, '}Cubes' , 1 );\r\n EndIf;\r\n \r\n # Loop through cubes in subset created based on wildcard\r\n nCountCubes = SubsetGetSize( '}Cubes' , cTempSub );\r\n While( nCountCubes >= 1 );\r\n sCurrCube = SubsetGetElementName( '}Cubes' , cTempSub, nCountCubes );\r\n # Validate cube name\r\n If( CubeExists( sCurrCube ) = 1 ); \r\n # Destroy Cube\r\n If(Subst(sCube,1,1) @= '}');\r\n If(pCtrlObj = 1);\r\n CubeDestroy( sCurrCube );\r\n Endif;\r\n Else;\r\n CubeDestroy( sCurrCube );\r\n Endif;\r\n Endif;\r\n nCountCubes = nCountCubes - 1;\r\n End;\r\n EndIf;\r\n\r\nEnd;\r\n\r\n\r\n### End Prolog ###", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.cube.delete', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pCube', '', 'pDelim', '&',\r\n \t'pCtrlObj', 0\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process deletes cube(s).\r\n\r\n# Use case: Intended for cleaning up after development/prototyping.\r\n# 1\\ Delete all cubes not needed after Go Live.\r\n\r\n# Note:\r\n# A list of cubes can be specified and/or wild cards can be used.\r\n# Naturally valid cube name(s) must be specified otherwise the process will abort.\r\n# By default (pCtrlObj) the process will not delete control cubes (i.e. attributes, security etc).\r\n#EndRegion @DOC\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\n\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pCube:%pCube%, pDelim:%pDelim%, pCtrlObj:%pCtrlObj%.' ; \r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pCube\": null,\r\n \"pDelim\": \"&\",\r\n \"pCtrlObj\": 0,\r\n \"pLogOutput\": 0,\r\n \"pStrictErrorHandling\": 0\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pCube\": '|StringToJson ( pCube )|',\r\n \"pDelim\": '|StringToJson ( pDelim )|',\r\n \"pCtrlObj\": '|NumberToString( pCtrlObj )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npCube = JsonToString( JsonGet( pJson, 'pCube' ) );\r\npDelim = JsonToString( JsonGet( pJson, 'pDelim' ) );\r\n# Numeric Parameters\r\npCtrlObj = StringToNumber( JsonToString( JsonGet( pJson, 'pCtrlObj' ) ) );\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\n\r\nnErrors = 0;\r\n\r\n# If blank delimiter specified then convert to default\r\nIf( pDelim @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\n# If no cubes have been specified, then log error message\r\nIf( Trim( pCube ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No cubes specified';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n# If no wildcard and no delimiter, log error message if cubename is invalid \r\nIf( Scan( pDelim, pCube ) = 0 & Scan( '*', pCube ) = 0 & Trim( pCube ) @<> '' & CubeExists( pCube ) = 0 ); \r\n nErrors = 1;\r\n sMessage = 'Cubename ' | pCube | ' is invalid';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### Split parameter into individual cubes and delete ###\r\nsCubes = pCube;\r\nnDelimiterIndex = 1;\r\nsMdx = '';\r\n\r\nWhile( nDelimiterIndex <> 0 );\r\n nDelimiterIndex = Scan( pDelim, sCubes );\r\n If( nDelimiterIndex = 0 );\r\n sCube = sCubes;\r\n Else;\r\n sCube = Trim( SubSt( sCubes, 1, nDelimiterIndex - 1 ) );\r\n sCubes = Trim( Subst( sCubes, nDelimiterIndex + Long(pDelim), Long( sCubes ) ) );\r\n EndIf;\r\n \r\n # Check if a wildcard has been used to specify the Cube name.\r\n # If it hasn't then just delete the Cube if it exists\r\n # If it has then create cubes subset using Wildcard expression in Mdx\r\n If( Scan( '*', sCube ) = 0 );\r\n If( CubeExists( sCube ) = 1 ); \r\n If(Subst(sCube,1,1) @= '}');\r\n If(pCtrlObj = 1);\r\n CubeDestroy( sCube );\r\n Endif;\r\n Else;\r\n CubeDestroy( sCube );\r\n Endif;\r\n Endif;\r\n Else;\r\n # Create subset of cubes using Wildcard\r\n sCubeExp = '\"'|sCube|'\"';\r\n IF( pCtrlObj = 1 );\r\n sMdxPart = '{TM1FILTERBYPATTERN( TM1SUBSETALL( [}Cubes] ) ,'| sCubeExp | ')}';\r\n ELSE;\r\n sMdxPart = '{TM1FILTERBYPATTERN( EXCEPT( TM1SUBSETALL( [}Cubes] ) , TM1FILTERBYPATTERN( TM1SUBSETALL( [}Cubes] ) , \"}*\" ) ) ,'| sCubeExp | ')}'; \r\n ENDIF;\r\n IF( sMdx @= ''); \r\n sMdx = sMdxPart; \r\n ELSE;\r\n sMdx = sMdx | ' + ' | sMdxPart;\r\n ENDIF;\r\n \r\n If( SubsetExists( '}Cubes' , cTempSub ) = 1 );\r\n # If a delimited list of cube names includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( '}Cubes' , cTempSub, sMDX );\r\n Else;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSub, sMDX, '}Cubes' , 1 );\r\n EndIf;\r\n \r\n # Loop through cubes in subset created based on wildcard\r\n nCountCubes = SubsetGetSize( '}Cubes' , cTempSub );\r\n While( nCountCubes >= 1 );\r\n sCurrCube = SubsetGetElementName( '}Cubes' , cTempSub, nCountCubes );\r\n # Validate cube name\r\n If( CubeExists( sCurrCube ) = 1 ); \r\n # Destroy Cube\r\n If(Subst(sCube,1,1) @= '}');\r\n If(pCtrlObj = 1);\r\n CubeDestroy( sCurrCube );\r\n Endif;\r\n Else;\r\n CubeDestroy( sCurrCube );\r\n Endif;\r\n Endif;\r\n nCountCubes = nCountCubes - 1;\r\n End;\r\n EndIf;\r\n\r\nEnd;\r\n\r\n\r\n### End Prolog ###", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully deleted cube %pCube%.' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n### End Epilog ###\r\n", @@ -10,35 +10,41 @@ "Type": "None" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pCube", - "Prompt": "REQUIRED: List of Cubes to Delete (Separated by Delimiter, Accepts wildcard)", + "Prompt": "REQUIRED: Cube name", "Value": "", "Type": "String" }, { "Name": "pDelim", - "Prompt": "OPTIONAL: Delimiter", + "Prompt": "OPTIONAL: Delimiter for list parameters (Default = '&')", "Value": "&", "Type": "String" }, { "Name": "pCtrlObj", - "Prompt": "OPTIONAL: To Delete control cube 1=Delete control objects, 0=Do not delete control objects, Default value 0", + "Prompt": "OPTIONAL: OPTIONAL: Allow modification of control objects (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [], diff --git a/bedrock_processes_json/}bedrock.cube.dimension.add.json b/bedrock_processes_json/}bedrock.cube.dimension.add.json index bb884d7..14cd811 100644 --- a/bedrock_processes_json/}bedrock.cube.dimension.add.json +++ b/bedrock_processes_json/}bedrock.cube.dimension.add.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.cube.dimension.add", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.cube.dimension.add', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pCube', '', 'pDim', '', 'pDimIndex', 1,\r\n \t'pIncludeData', 0, 'pEle', '', 'pIncludeRules', 2,\r\n \t'pCtrlObj', 0, 'pTemp', 1\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This TI adds a dimension to a cube that has already been built with the ability to preserve data.\r\n\r\n# Use case: Intended for development/prototyping.\r\n# 1/ Rebuild existing cube with extra dimension without losing data.\r\n\r\n# Note:\r\n# Naturally, a valid target cube name (pCube) is mandatory otherwise the process will abort.\r\n# Also, a valid new dimension name (pDim) is mandatory otherwise the process will abort.\r\n# When data needs to be kept (using pIncludeData) a valid element (pEle) must be specified where to store the data in new dimension.\r\n# Rule can be kept as backup file only or reloaded back.\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent= 'Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pCube:%pCube%, pDim:%pDim%, pDimIndex:%pDimIndex%, pIncludeData:%pIncludeData%, pEle:%pEle%, pIncludeRules:%pIncludeRules%, pCtrlObj:%pCtrlObj%, pTemp:%pTemp%.';\r\n\r\n## check operating system\r\nIf( SubSt( GetProcessErrorFileDirectory, 2, 1 ) @= ':' );\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nElseIf( Scan( '/', GetProcessErrorFileDirectory ) > 0 );\r\n sOS = 'Linux';\r\n sOSDelim = '/';\r\nElse;\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nEndIf;\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n# Validate cube\r\ncDimCount = 0;\r\nIf( Trim( pCube ) @= '' );\r\n nErrors = nErrors + 1;\r\n sMessage = 'No cube specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( CubeExists( pCube ) = 0 );\r\n nErrors = nErrors + 1;\r\n sMessage = Expand( 'Invalid cube specified: %pCube%.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElse;\r\n cDimCount = CubeDimensionCountGet(pCube);\r\nEndIf;\r\n\r\n# Don't allow system cubes to be modified\r\nIf( SubSt( pCube, 1, 1 ) @= '}' & pCtrlObj <= 0 );\r\n nErrors = nErrors + 1;\r\n sMessage = Expand( 'Do not modify system cubes: %pCube%.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate index\r\nIf( pDimIndex = 0 );\r\n nErrors = nErrors + 1;\r\n sMessage = Expand( 'Index for new dimension is a REQUIRED parameter!');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( pDimIndex > cDimCount + 1 );\r\n nErrors = nErrors + 1;\r\n sMessage = Expand( 'Cube %pCube% has %cDimCount% dimensions. %pDimIndex% is not valid for the new dimension index!');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate dimension\r\nIf( Trim( pDim ) @= '' );\r\n nErrors = nErrors + 1;\r\n sMessage = 'No dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( DimensionExists( pDim ) = 0 );\r\n nErrors = nErrors + 1;\r\n sMessage = Expand( 'New dimension: %pDim% does not exist');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# check element chosen in new dimension\r\nIf( pIncludeData = 1 & Trim(pEle)@='' );\r\n nErrors = nErrors + 1;\r\n sMessage = Expand( 'No element specified in new dimension %pDim% to store cube data.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nIf( pIncludeData = 1 & DIMIX(pDim, pEle)=0 );\r\n nErrors = nErrors + 1;\r\n sMessage = Expand( 'Invalid element %pEle% specified for the new dimension %pDim% to store cube data.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nIF(pIncludeRules = 1 % pIncludeRules = 2);\r\n sRule=CubeRuleGet( pCube );\r\n If( sRule@= '' );\r\n pIncludeRules = 0;\r\n LogOutput( 'INFO', Expand( 'No rule found for %pCube%.' ) );\r\n Endif;\r\nEndif; \r\n\r\n### Determine number of dims in source cube & create strings to check and recreate ###\r\nnCount = 1;\r\nsDimString = '';\r\nsDimCheck = '';\r\nsDelim = '+';\r\nnNewFound = 0;\r\nnIncrement = 1;\r\nWhile( TabDim( pCube, nCount ) @<> '' );\r\n sDim = TabDim( pCube, nCount );\r\n IF(nCount = pDimIndex & nNewFound = 0);\r\n sNewDim = pDim;\r\n nNewFound = 1;\r\n nIncrement = 0;\r\n else;\r\n sNewDim = sDim;\r\n nIncrement = 1;\r\n Endif; \r\n sDimCheck = sDimCheck|'+'|sDim|'+';\r\n sDimString = sDimString|'+'|sNewDim;\r\n nCount = nCount + nIncrement;\r\nEnd;\r\nnDimensionCount = nCount;\r\n\r\n# Cover case of new dimension in last position (pDimIndex = cDimCount+1)\r\nIf( nDimensionCount = pDimIndex & nNewFound = 0 );\r\n nNewFound = 1;\r\n sNewDim=pDim;\r\n sDimString = sDimString|'+'|sNewDim;\r\nEndIf;\r\n\r\n# Remove any leading +\r\nIF( Subst( sDimString , 1 , 1 ) @= '+' );\r\n sDimString = Subst ( sDimString , 2, Long(sDimString)-1 );\r\nEndIf;\r\n\r\nIF( Scan('+'|Lower(pDim)|'+', Lower(sDimCheck)) > 0 );\r\n nErrors = nErrors + 1;\r\n sMessage = Expand( 'The chosen new dimension %pDim% already exists in cube %pCube%.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndif;\r\n\r\n# Check if cube exceeds current max dimenions\r\nIf( nDimensionCount > 27 );\r\n sMessage = 'Process needs to be modified to handle cubes with more than 27 dimensions';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n###### CALLING THE STEP PROCESSES #####\r\n\r\n# Keep the rule\r\nIF(pIncludeRules = 1 % pIncludeRules = 2);\r\n \r\n sProc = '}bedrock.cube.rule.manage';\r\n nRet = ExecuteProcess( sProc,\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pCube', pCube,\r\n 'pMode', 'UNLOAD'\r\n );\r\n \r\n IF(nRet <> 0);\r\n sMessage = 'Error unloading the rule for %pCube%.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n ENDIF;\r\n \r\nEndif; \r\n\r\n# create clone cube with data\r\nIF(pIncludeData = 1);\r\n \r\n pCloneCube = pCube | '_Clone';\r\n nIncludeRules = IF(pIncludeRules = 1 % pIncludeRules = 2, 1, 0);\r\n nSuppressRules = IF(nIncludeRules = 1, 1, 0);\r\n \r\n sProc = '}bedrock.cube.clone';\r\n nRet = ExecuteProcess( sProc,\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pSrcCube', pCube,\r\n 'pTgtCube', pCloneCube,\r\n 'pIncludeRules', nIncludeRules,\r\n 'pIncludeData', pIncludeData,\r\n 'pSuppressRules', nSuppressRules,\r\n 'pTemp', pTemp,\r\n 'pCubeLogging', 0\r\n );\r\n\r\n IF(nRet <> 0);\r\n sMessage = 'Error creating cloned cube for keeping data.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n ENDIF;\r\nEndif;\r\n\r\n# recreate the cube\r\nsProc = '}bedrock.cube.create';\r\nnRet = ExecuteProcess( sProc,\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pCube', pCube,\r\n 'pDims', sDimString,\r\n 'pRecreate', 1,\r\n 'pDelim', sDelim\r\n );\r\n\r\nIF(nRet <> 0);\r\n sMessage = Expand('Error recreating the cube: %pCube%.');\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nENDIF;\r\n\r\n# copy back the data\r\nIF(pIncludeData = 1);\r\n sEleStartDelim = '\u00a6';\r\n sMappingToNewDims = pDim|sEleStartDelim|pEle;\r\n \r\n nRet = ExecuteProcess('}bedrock.cube.data.copy.intercube',\r\n \t'pLogOutput',pLogOutput,\r\n \t'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pSrcCube',pCloneCube,\r\n \t'pFilter','',\r\n \t'pTgtCube',pCube,\r\n \t'pMappingToNewDims',sMappingToNewDims,\r\n 'pSuppressConsol', 1,\r\n 'pSuppressRules', nSuppressRules,\r\n \t'pZeroTarget',0,\r\n \t'pZeroSource',0,\r\n \t'pFactor',1,\r\n \t'pDimDelim','&',\r\n \t'pEleStartDelim',sEleStartDelim,\r\n \t'pEleDelim','+',\r\n \t'pTemp',pTemp,\r\n \t'pCubeLogging',0);\r\n \r\n IF(nRet <> 0);\r\n sMessage = Expand('Error copying back the data from clone cube: %pCloneCube%.');\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n ENDIF;\r\n \r\n # destroy clone cube\r\n IF(pTemp=1);\r\n sProc = '}bedrock.cube.delete';\r\n nRet = ExecuteProcess( sProc,\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pCube', pCloneCube,\r\n 'pCtrlObj', 0\r\n );\r\n\r\n IF(nRet <> 0);\r\n sMessage = Expand('Error deleting the clone cube: %pCloneCube%.');\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n ENDIF;\r\n Endif;\r\n\r\nEndif; \r\n\r\n# reload the rule\r\nIF(pIncludeRules = 2);\r\n \r\n sProc = '}bedrock.cube.rule.manage';\r\n\r\n nRet = ExecuteProcess( sProc,\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pCube', pCube,\r\n 'pMode', 'LOAD'\r\n );\r\n \r\n IF(nRet <> 0);\r\n sMessage = Expand('Error reloading the rule for %pCube%.');\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n # Create error rule file \r\n cErrorRuleName = 'ErrorRuleFile.txt';\r\n \r\n IF(FileExists( Lower(cErrorRuleName) ) = 0 );\r\n sFile = '.' | sOSDelim | Lower(cErrorRuleName);\r\n LogOutput(cMsgErrorLevel, 'Rule could not be attached due to invalid !Dimension references. Please recover from the backup and fix manually.');\r\n ENDIF;\r\n \r\n ExecuteProcess( sProc,\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pCube', pCube,\r\n 'pFileName', Lower(cErrorRuleName),\r\n 'pMode', 'LOAD'\r\n );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n ENDIF;\r\n \r\nEndif; \r\n\r\n### End Prolog ###", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.cube.dimension.add', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pCube', '', 'pDim', '', 'pDimIndex', 1,\r\n \t'pIncludeData', 0, 'pEle', '', 'pIncludeRules', 2,\r\n \t'pCtrlObj', 0, 'pTemp', 1\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This TI adds a dimension to a cube that has already been built with the ability to preserve data.\r\n\r\n# Use case: Intended for development/prototyping.\r\n# 1/ Rebuild existing cube with extra dimension without losing data.\r\n\r\n# Note:\r\n# Naturally, a valid target cube name (pCube) is mandatory otherwise the process will abort.\r\n# Also, a valid new dimension name (pDim) is mandatory otherwise the process will abort.\r\n# When data needs to be kept (using pIncludeData) a valid element (pEle) must be specified where to store the data in new dimension.\r\n# Rule can be kept as backup file only or reloaded back.\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent= 'Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pCube:%pCube%, pDim:%pDim%, pDimIndex:%pDimIndex%, pIncludeData:%pIncludeData%, pEle:%pEle%, pIncludeRules:%pIncludeRules%, pCtrlObj:%pCtrlObj%, pTemp:%pTemp%.';\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pCube\": null,\r\n \"pDim\": null,\r\n \"pEle\": \"\",\r\n \"pCtrlObj\": 0,\r\n \"pDimIndex\": null,\r\n \"pIncludeData\": 0,\r\n \"pIncludeRules\": 1,\r\n \"pLogOutput\": 0,\r\n \"pStrictErrorHandling\": 0,\r\n \"pTemp\": 1\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pCube\": '|StringToJson ( pCube )|',\r\n \"pDim\": '|StringToJson ( pDim )|',\r\n \"pEle\": '|StringToJson ( pEle )|',\r\n \"pCtrlObj\": '|NumberToString( pCtrlObj )|',\r\n \"pDimIndex\": '|NumberToString( pDimIndex )|',\r\n \"pIncludeData\": '|NumberToString( pIncludeData )|',\r\n \"pIncludeRules\": '|NumberToString( pIncludeRules )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|',\r\n \"pTemp\": '|NumberToString( pTemp )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npCube = JsonToString( JsonGet( pJson, 'pCube' ) );\r\npDim = JsonToString( JsonGet( pJson, 'pDim' ) );\r\npEle = JsonToString( JsonGet( pJson, 'pEle' ) );\r\n# Numeric Parameters\r\npCtrlObj = StringToNumber( JsonToString( JsonGet( pJson, 'pCtrlObj' ) ) );\r\npDimIndex = StringToNumber( JsonToString( JsonGet( pJson, 'pDimIndex' ) ) );\r\npIncludeData = StringToNumber( JsonToString( JsonGet( pJson, 'pIncludeData' ) ) );\r\npIncludeRules = StringToNumber( JsonToString( JsonGet( pJson, 'pIncludeRules' ) ) );\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\npTemp = StringToNumber( JsonToString( JsonGet( pJson, 'pTemp' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n## check operating system\r\nIf( SubSt( GetProcessErrorFileDirectory, 2, 1 ) @= ':' );\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nElseIf( Scan( '/', GetProcessErrorFileDirectory ) > 0 );\r\n sOS = 'Linux';\r\n sOSDelim = '/';\r\nElse;\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nEndIf;\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n# Validate cube\r\ncDimCount = 0;\r\nIf( Trim( pCube ) @= '' );\r\n nErrors = nErrors + 1;\r\n sMessage = 'No cube specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( CubeExists( pCube ) = 0 );\r\n nErrors = nErrors + 1;\r\n sMessage = Expand( 'Invalid cube specified: %pCube%.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElse;\r\n cDimCount = CubeDimensionCountGet(pCube);\r\nEndIf;\r\n\r\n# Don't allow system cubes to be modified\r\nIf( SubSt( pCube, 1, 1 ) @= '}' & pCtrlObj <= 0 );\r\n nErrors = nErrors + 1;\r\n sMessage = Expand( 'Do not modify system cubes: %pCube%.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate index\r\nIf( pDimIndex = 0 );\r\n nErrors = nErrors + 1;\r\n sMessage = Expand( 'Index for new dimension is a REQUIRED parameter!');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( pDimIndex > cDimCount + 1 );\r\n nErrors = nErrors + 1;\r\n sMessage = Expand( 'Cube %pCube% has %cDimCount% dimensions. %pDimIndex% is not valid for the new dimension index!');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate dimension\r\nIf( Trim( pDim ) @= '' );\r\n nErrors = nErrors + 1;\r\n sMessage = 'No dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( DimensionExists( pDim ) = 0 );\r\n nErrors = nErrors + 1;\r\n sMessage = Expand( 'New dimension: %pDim% does not exist');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# check element chosen in new dimension\r\nIf( pIncludeData = 1 & Trim(pEle)@='' );\r\n nErrors = nErrors + 1;\r\n sMessage = Expand( 'No element specified in new dimension %pDim% to store cube data.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nIf( pIncludeData = 1 & DIMIX(pDim, pEle)=0 );\r\n nErrors = nErrors + 1;\r\n sMessage = Expand( 'Invalid element %pEle% specified for the new dimension %pDim% to store cube data.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nIF(pIncludeRules = 1 % pIncludeRules = 2);\r\n sRule=CubeRuleGet( pCube );\r\n If( sRule@= '' );\r\n pIncludeRules = 0;\r\n LogOutput( 'INFO', Expand( 'No rule found for %pCube%.' ) );\r\n Endif;\r\nEndif; \r\n\r\n### Determine number of dims in source cube & create strings to check and recreate ###\r\nnCount = 1;\r\nsDimString = '';\r\nsDimCheck = '';\r\nsDelim = '+';\r\nnNewFound = 0;\r\nnIncrement = 1;\r\nWhile( TabDim( pCube, nCount ) @<> '' );\r\n sDim = TabDim( pCube, nCount );\r\n IF(nCount = pDimIndex & nNewFound = 0);\r\n sNewDim = pDim;\r\n nNewFound = 1;\r\n nIncrement = 0;\r\n else;\r\n sNewDim = sDim;\r\n nIncrement = 1;\r\n Endif; \r\n sDimCheck = sDimCheck|'+'|sDim|'+';\r\n sDimString = sDimString|'+'|sNewDim;\r\n nCount = nCount + nIncrement;\r\nEnd;\r\nnDimensionCount = nCount;\r\n\r\n# Cover case of new dimension in last position (pDimIndex = cDimCount+1)\r\nIf( nDimensionCount = pDimIndex & nNewFound = 0 );\r\n nNewFound = 1;\r\n sNewDim=pDim;\r\n sDimString = sDimString|'+'|sNewDim;\r\nEndIf;\r\n\r\n# Remove any leading +\r\nIF( Subst( sDimString , 1 , 1 ) @= '+' );\r\n sDimString = Subst ( sDimString , 2, Long(sDimString)-1 );\r\nEndIf;\r\n\r\nIF( Scan('+'|Lower(pDim)|'+', Lower(sDimCheck)) > 0 );\r\n nErrors = nErrors + 1;\r\n sMessage = Expand( 'The chosen new dimension %pDim% already exists in cube %pCube%.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndif;\r\n\r\n# Check if cube exceeds current max dimenions\r\nIf( nDimensionCount > 27 );\r\n sMessage = 'Process needs to be modified to handle cubes with more than 27 dimensions';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n###### CALLING THE STEP PROCESSES #####\r\n\r\n# Keep the rule\r\nIF(pIncludeRules = 1 % pIncludeRules = 2);\r\n \r\n sProc = '}bedrock.cube.rule.manage';\r\n nRet = ExecuteProcess( sProc,\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pCube', pCube,\r\n 'pMode', 'UNLOAD'\r\n );\r\n \r\n IF(nRet <> 0);\r\n sMessage = 'Error unloading the rule for %pCube%.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n ENDIF;\r\n \r\nEndif; \r\n\r\n# create clone cube with data\r\nIF(pIncludeData = 1);\r\n \r\n pCloneCube = pCube | '_Clone';\r\n nIncludeRules = IF(pIncludeRules = 1 % pIncludeRules = 2, 1, 0);\r\n nSuppressRules = IF(nIncludeRules = 1, 1, 0);\r\n \r\n sProc = '}bedrock.cube.clone';\r\n nRet = ExecuteProcess( sProc,\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pSrcCube', pCube,\r\n 'pTgtCube', pCloneCube,\r\n 'pIncludeRules', nIncludeRules,\r\n 'pIncludeData', pIncludeData,\r\n 'pSuppressRules', nSuppressRules,\r\n 'pTemp', pTemp,\r\n 'pCubeLogging', 0\r\n );\r\n\r\n IF(nRet <> 0);\r\n sMessage = 'Error creating cloned cube for keeping data.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n ENDIF;\r\nEndif;\r\n\r\n# recreate the cube\r\nsProc = '}bedrock.cube.create';\r\nnRet = ExecuteProcess( sProc,\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pCube', pCube,\r\n 'pDims', sDimString,\r\n 'pRecreate', 1,\r\n 'pDelim', sDelim\r\n );\r\n\r\nIF(nRet <> 0);\r\n sMessage = Expand('Error recreating the cube: %pCube%.');\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nENDIF;\r\n\r\n# copy back the data\r\nIF(pIncludeData = 1);\r\n sEleStartDelim = '\u00a6';\r\n sMappingToNewDims = pDim|sEleStartDelim|pEle;\r\n \r\n nRet = ExecuteProcess('}bedrock.cube.data.copy.intercube',\r\n \t'pLogOutput',pLogOutput,\r\n \t'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pSrcCube',pCloneCube,\r\n \t'pFilter','',\r\n \t'pTgtCube',pCube,\r\n \t'pMappingToNewDims',sMappingToNewDims,\r\n 'pSuppressConsol', 1,\r\n 'pSuppressRules', nSuppressRules,\r\n \t'pZeroTarget',0,\r\n \t'pZeroSource',0,\r\n \t'pFactor',1,\r\n \t'pDimDelim','&',\r\n \t'pEleStartDelim',sEleStartDelim,\r\n \t'pEleDelim','+',\r\n \t'pTemp',pTemp,\r\n \t'pCubeLogging',0);\r\n \r\n IF(nRet <> 0);\r\n sMessage = Expand('Error copying back the data from clone cube: %pCloneCube%.');\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n ENDIF;\r\n \r\n # destroy clone cube\r\n IF(pTemp=1);\r\n sProc = '}bedrock.cube.delete';\r\n nRet = ExecuteProcess( sProc,\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pCube', pCloneCube,\r\n 'pCtrlObj', 0\r\n );\r\n\r\n IF(nRet <> 0);\r\n sMessage = Expand('Error deleting the clone cube: %pCloneCube%.');\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n ENDIF;\r\n Endif;\r\n\r\nEndif; \r\n\r\n# reload the rule\r\nIF(pIncludeRules = 2);\r\n \r\n sProc = '}bedrock.cube.rule.manage';\r\n\r\n nRet = ExecuteProcess( sProc,\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pCube', pCube,\r\n 'pMode', 'LOAD'\r\n );\r\n \r\n IF(nRet <> 0);\r\n sMessage = Expand('Error reloading the rule for %pCube%.');\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n # Create error rule file \r\n cErrorRuleName = 'ErrorRuleFile.txt';\r\n \r\n IF(FileExists( Lower(cErrorRuleName) ) = 0 );\r\n sFile = '.' | sOSDelim | Lower(cErrorRuleName);\r\n LogOutput(cMsgErrorLevel, 'Rule could not be attached due to invalid !Dimension references. Please recover from the backup and fix manually.');\r\n ENDIF;\r\n \r\n ExecuteProcess( sProc,\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pCube', pCube,\r\n 'pFileName', Lower(cErrorRuleName),\r\n 'pMode', 'LOAD'\r\n );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n ENDIF;\r\n \r\nEndif; \r\n\r\n### End Prolog ###", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully added dimension %pDim%.' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n### End Epilog ###", @@ -10,18 +10,6 @@ "Type": "None" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pCube", "Prompt": "REQUIRED: Cube name", @@ -36,39 +24,57 @@ }, { "Name": "pDimIndex", - "Prompt": "REQUIRED: Dimension number of the new dimension in the cube", - "Value": 1, + "Prompt": "REQUIRED: Index in dimension list where pDim will be inserted", + "Value": 0, "Type": "Numeric" }, { "Name": "pIncludeData", - "Prompt": "OPTIONAL: If 1 then data is kept (copied through clone cube)", + "Prompt": "OPTIONAL: Include cube data (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { "Name": "pEle", - "Prompt": "REQUIRED: if IncludeData flag =1: Element of new dimension where to store data", + "Prompt": "OPTIONAL: Required if IncludeData flag =1. Element of new dimension where the existing data will be stored", "Value": "", "Type": "String" }, { "Name": "pIncludeRules", - "Prompt": "Unload and reload the rule (0 = do not keep the rule, 1 = unload the rule, 2 = unload the rule and reload on new cube)", - "Value": 2, + "Prompt": "OPTIONAL: Include cube rules (Boolean. Default = 1)", + "Value": 1, "Type": "Numeric" }, { "Name": "pCtrlObj", - "Prompt": "OPTIONAL: Allow overwrite control cubes (default = 0)", + "Prompt": "OPTIONAL: OPTIONAL: Allow modification of control objects (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { "Name": "pTemp", - "Prompt": "OPTIONAL: Delete the clone cube (1 = delete, 0 = not delete)", + "Prompt": "OPTIONAL: Delete/create temporary objects (0 = Do not delete, 1 = Delete, 2 = if view and subsets are created, keep only subsets)", "Value": 1, "Type": "Numeric" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [], diff --git a/bedrock_processes_json/}bedrock.cube.dimension.delete.json b/bedrock_processes_json/}bedrock.cube.dimension.delete.json index 8983ae7..cbeaf87 100644 --- a/bedrock_processes_json/}bedrock.cube.dimension.delete.json +++ b/bedrock_processes_json/}bedrock.cube.dimension.delete.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.cube.dimension.delete", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.cube.dimension.delete', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pCube', '', 'pDim', '',\r\n \t'pIncludeData', 1, 'pIncludeRules', 2,\r\n \t'pCtrlObj', 0, 'pTemp', 1\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This TI deletes a dimension from a cube that has already been built with the ability to preserve data.\r\n\r\n# Use case: Intended for development/prototyping.\r\n# 1/ Rebuild existing cube with the removal of one dimension without losing all the data.\r\n\r\n# Note:\r\n# Naturally, a valid cube name (pCube) is mandatory otherwise the process will abort.\r\n# Also, a valid dimension name (pDim) is mandatory otherwise the process will abort.\r\n# If data needs to be kept (using pIncludeData), data from pDim will be summed.\r\n# Rule can be kept as backup file only or reloaded back.\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent= 'Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pCube:%pCube%, pDim:%pDim%, pIncludeData:%pIncludeData%, pIncludeRules:%pIncludeRules%, pCtrlObj:%pCtrlObj%, pTemp:%pTemp%.';\r\n\r\n## check operating system\r\nIf( SubSt( GetProcessErrorFileDirectory, 2, 1 ) @= ':' );\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nElseIf( Scan( '/', GetProcessErrorFileDirectory ) > 0 );\r\n sOS = 'Linux';\r\n sOSDelim = '/';\r\nElse;\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nEndIf;\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n# Validate cube\r\nIf( Trim( pCube ) @= '' );\r\n nErrors = nErrors + 1;\r\n sMessage = 'No cube specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( CubeExists( pCube ) = 0 );\r\n nErrors = nErrors + 1;\r\n sMessage = Expand( 'Invalid cube specified: %pCube%.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Don't allow system cubes to be modified\r\nIf( SubSt( pCube, 1, 1 ) @= '}' & pCtrlObj <= 0 );\r\n nErrors = nErrors + 1;\r\n sMessage = Expand( 'Do not modify system cubes: %pCube%.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate dimension\r\nIf( Trim( pDim ) @= '' );\r\n nErrors = nErrors + 1;\r\n sMessage = 'No dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( DimensionExists( pDim ) = 0 );\r\n nErrors = nErrors + 1;\r\n sMessage = Expand( 'New dimension: %pDim% does not exist');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nIF(pIncludeRules = 1 % pIncludeRules = 2);\r\n cCubeRule=CubeRuleGet( pCube );\r\n If(cCubeRule @= '');\r\n pIncludeRules = 0;\r\n LogOutput( 'INFO', Expand( 'No rule found for %pCube%.' ) );\r\n Endif;\r\nEndif; \r\n\r\n### Determine number of dims in source cube & create strings to check and recreate ###\r\nnCount = 1;\r\nsDimString = '';\r\nsDimCheck = '';\r\nsDelim = '+';\r\nnSkip=0;\r\nnIncrement = 1;\r\nWhile( TabDim( pCube, nCount ) @<> '' );\r\n sDim = TabDim( pCube, nCount );\r\n IF(sDim@=pDim);\r\n nSkip = 1;\r\n else;\r\n nSkip = 0;\r\n Endif; \r\n sDimCheck = sDimCheck|'+'|sDim|'+';\r\n IF(nSkip = 0);\r\n sDimString = sDimString|'+'|sDim;\r\n Endif;\r\n nCount = nCount + 1;\r\nEnd;\r\nnDimensionCount = nCount-1;\r\n\r\n#Remove any leading +\r\nIF( Subst( sDimString , 1 , 1 ) @= '+' );\r\n sDimString = Subst ( sDimString , 2 , Long(sDimString)-1 );\r\nEndIf;\r\n\r\nIF( Scan('+'|Lower(pDim)|'+', Lower(sDimCheck)) = 0);\r\n nErrors = nErrors + 1;\r\n sMessage = Expand( 'The chosen dimension %pDim% does not exists in cube %pCube%.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndif;\r\n\r\n# Check if cube exceeds current max dimenions\r\nIf( nDimensionCount > 27 );\r\n sMessage = 'Process needs to be modified to handle cubes with more than 27 dimensions';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n###### CALLING THE STEP PROCESSES #####\r\n\r\n# Keep the rule\r\nIF(pIncludeRules = 1 % pIncludeRules = 2);\r\n \r\n sProc = '}bedrock.cube.rule.manage';\r\n\r\n nRet = ExecuteProcess( sProc,\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pCube', pCube,\r\n 'pMode', 'UNLOAD'\r\n );\r\n \r\n IF(nRet <> 0);\r\n sMessage = 'Error unloading the rule for %pCube%.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n ENDIF;\r\n \r\nEndif; \r\n\r\n# create clone cube with data\r\nIF(pIncludeData = 1);\r\n pCloneCube = pCube | '_Clone';\r\n nIncludeRules = IF(pIncludeRules = 1 % pIncludeRules = 2, 1, 0);\r\n nSuppressRules = IF(nIncludeRules = 1, 1, 0);\r\n \r\n sProc = '}bedrock.cube.clone';\r\n nRet = ExecuteProcess( sProc,\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pSrcCube', pCube,\r\n 'pTgtCube', pCloneCube,\r\n 'pIncludeRules', nIncludeRules,\r\n 'pIncludeData', pIncludeData,\r\n 'pSuppressRules', nSuppressRules,\r\n 'pTemp', pTemp,\r\n 'pCubeLogging', 0\r\n );\r\n\r\n IF(nRet <> 0);\r\n sMessage = 'Error creating cloned cube for keeping data.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n ENDIF;\r\n \r\nEndif;\r\n\r\n#Processbreak;\r\n\r\n# recreate the cube\r\nsProc = '}bedrock.cube.create';\r\nnRet = ExecuteProcess( sProc,\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pCube', pCube,\r\n 'pDims', sDimString,\r\n 'pRecreate', 1,\r\n 'pDelim', sDelim\r\n );\r\n\r\nIF(nRet <> 0);\r\n sMessage = Expand('Error recreating the cube: %pCube%.');\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nENDIF;\r\n\r\n#Processbreak;\r\n\r\n# copy back the data\r\nIF(pIncludeData = 1);\r\n sProc = '}bedrock.cube.data.copy.intercube';\r\n nRet = ExecuteProcess( sProc,\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pSrcCube', pCloneCube,\r\n 'pFilter', '',\r\n 'pTgtCube', pCube,\r\n 'pMappingToNewDims', '',\r\n 'pSuppressConsol', 1,\r\n 'pSuppressRules', nSuppressRules,\r\n 'pZeroSource', 0,\r\n 'pZeroTarget', 0,\r\n 'pFactor', 1,\r\n 'pTemp', pTemp,\r\n 'pCubeLogging', 0\r\n ); \r\n \r\n IF(nRet <> 0);\r\n sMessage = Expand('Error copying back the data from clone cube: %pCloneCube%.');\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n ENDIF;\r\n \r\n # destroy clone cube\r\n IF(pTemp=1);\r\n sProc = '}bedrock.cube.delete';\r\n nRet = ExecuteProcess( sProc,\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pCube', pCloneCube,\r\n 'pCtrlObj', 0\r\n );\r\n\r\n IF(nRet <> 0);\r\n sMessage = Expand('Error deleting cloned cube: %pCloneCube%.');\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n ENDIF;\r\n Endif;\r\n \r\nEndif; \r\n\r\n# reload the rule\r\nIF(pIncludeRules = 2);\r\n \r\n sProc = '}bedrock.cube.rule.manage';\r\n\r\n nRet = ExecuteProcess( sProc,\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pCube', pCube,\r\n 'pMode', 'LOAD'\r\n );\r\n \r\n IF(nRet <> 0);\r\n sMessage = Expand('Error reloading the rule for %pCube%.');\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n # Create error rule file \r\n cErrorRuleName = 'ErrorRuleFile.rux';\r\n\r\n IF(FileExists( Lower(cErrorRuleName) ) = 0 );\r\n sFile = '.' | sOSDelim | Lower(cErrorRuleName);\r\n LogOutput(cMsgErrorLevel, 'Rule could not be attached due to invalid !Dimension references. Please recover from the backup and fix manually.');\r\n ENDIF;\r\n\r\n ExecuteProcess( sProc,\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pCube', pCube,\r\n 'pFileName', Lower(cErrorRuleName),\r\n 'pMode', 'LOAD'\r\n );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n ENDIF;\r\n \r\nEndif; \r\n\r\n### End Prolog ###", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.cube.dimension.delete', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pCube', '', 'pDim', '',\r\n \t'pIncludeData', 1, 'pIncludeRules', 2,\r\n \t'pCtrlObj', 0, 'pTemp', 1\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This TI deletes a dimension from a cube that has already been built with the ability to preserve data.\r\n\r\n# Use case: Intended for development/prototyping.\r\n# 1/ Rebuild existing cube with the removal of one dimension without losing all the data.\r\n\r\n# Note:\r\n# Naturally, a valid cube name (pCube) is mandatory otherwise the process will abort.\r\n# Also, a valid dimension name (pDim) is mandatory otherwise the process will abort.\r\n# If data needs to be kept (using pIncludeData), data from pDim will be summed.\r\n# Rule can be kept as backup file only or reloaded back.\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent= 'Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pCube:%pCube%, pDim:%pDim%, pIncludeData:%pIncludeData%, pIncludeRules:%pIncludeRules%, pCtrlObj:%pCtrlObj%, pTemp:%pTemp%.';\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pCube\": null,\r\n \"pDim\": null,\r\n \"pCtrlObj\": 0,\r\n \"pIncludeData\": 0,\r\n \"pIncludeRules\": 1,\r\n \"pLogOutput\": 0,\r\n \"pStrictErrorHandling\": 0,\r\n \"pTemp\": 1\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pCube\": '|StringToJson ( pCube )|',\r\n \"pDim\": '|StringToJson ( pDim )|',\r\n \"pCtrlObj\": '|NumberToString( pCtrlObj )|',\r\n \"pIncludeData\": '|NumberToString( pIncludeData )|',\r\n \"pIncludeRules\": '|NumberToString( pIncludeRules )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|',\r\n \"pTemp\": '|NumberToString( pTemp )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npCube = JsonToString( JsonGet( pJson, 'pCube' ) );\r\npDim = JsonToString( JsonGet( pJson, 'pDim' ) );\r\n# Numeric Parameters\r\npCtrlObj = StringToNumber( JsonToString( JsonGet( pJson, 'pCtrlObj' ) ) );\r\npIncludeData = StringToNumber( JsonToString( JsonGet( pJson, 'pIncludeData' ) ) );\r\npIncludeRules = StringToNumber( JsonToString( JsonGet( pJson, 'pIncludeRules' ) ) );\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\npTemp = StringToNumber( JsonToString( JsonGet( pJson, 'pTemp' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n## check operating system\r\nIf( SubSt( GetProcessErrorFileDirectory, 2, 1 ) @= ':' );\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nElseIf( Scan( '/', GetProcessErrorFileDirectory ) > 0 );\r\n sOS = 'Linux';\r\n sOSDelim = '/';\r\nElse;\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nEndIf;\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n# Validate cube\r\nIf( Trim( pCube ) @= '' );\r\n nErrors = nErrors + 1;\r\n sMessage = 'No cube specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( CubeExists( pCube ) = 0 );\r\n nErrors = nErrors + 1;\r\n sMessage = Expand( 'Invalid cube specified: %pCube%.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Don't allow system cubes to be modified\r\nIf( SubSt( pCube, 1, 1 ) @= '}' & pCtrlObj <= 0 );\r\n nErrors = nErrors + 1;\r\n sMessage = Expand( 'Do not modify system cubes: %pCube%.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate dimension\r\nIf( Trim( pDim ) @= '' );\r\n nErrors = nErrors + 1;\r\n sMessage = 'No dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( DimensionExists( pDim ) = 0 );\r\n nErrors = nErrors + 1;\r\n sMessage = Expand( 'New dimension: %pDim% does not exist');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nIF(pIncludeRules = 1 % pIncludeRules = 2);\r\n cCubeRule=CubeRuleGet( pCube );\r\n If(cCubeRule @= '');\r\n pIncludeRules = 0;\r\n LogOutput( 'INFO', Expand( 'No rule found for %pCube%.' ) );\r\n Endif;\r\nEndif; \r\n\r\n### Determine number of dims in source cube & create strings to check and recreate ###\r\nnCount = 1;\r\nsDimString = '';\r\nsDimCheck = '';\r\nsDelim = '+';\r\nnSkip=0;\r\nnIncrement = 1;\r\nWhile( TabDim( pCube, nCount ) @<> '' );\r\n sDim = TabDim( pCube, nCount );\r\n IF(sDim@=pDim);\r\n nSkip = 1;\r\n else;\r\n nSkip = 0;\r\n Endif; \r\n sDimCheck = sDimCheck|'+'|sDim|'+';\r\n IF(nSkip = 0);\r\n sDimString = sDimString|'+'|sDim;\r\n Endif;\r\n nCount = nCount + 1;\r\nEnd;\r\nnDimensionCount = nCount-1;\r\n\r\n#Remove any leading +\r\nIF( Subst( sDimString , 1 , 1 ) @= '+' );\r\n sDimString = Subst ( sDimString , 2 , Long(sDimString)-1 );\r\nEndIf;\r\n\r\nIF( Scan('+'|Lower(pDim)|'+', Lower(sDimCheck)) = 0);\r\n nErrors = nErrors + 1;\r\n sMessage = Expand( 'The chosen dimension %pDim% does not exists in cube %pCube%.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndif;\r\n\r\n# Check if cube exceeds current max dimenions\r\nIf( nDimensionCount > 27 );\r\n sMessage = 'Process needs to be modified to handle cubes with more than 27 dimensions';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n###### CALLING THE STEP PROCESSES #####\r\n\r\n# Keep the rule\r\nIF(pIncludeRules = 1 % pIncludeRules = 2);\r\n \r\n sProc = '}bedrock.cube.rule.manage';\r\n\r\n nRet = ExecuteProcess( sProc,\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pCube', pCube,\r\n 'pMode', 'UNLOAD'\r\n );\r\n \r\n IF(nRet <> 0);\r\n sMessage = 'Error unloading the rule for %pCube%.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n ENDIF;\r\n \r\nEndif; \r\n\r\n# create clone cube with data\r\nIF(pIncludeData = 1);\r\n pCloneCube = pCube | '_Clone';\r\n nIncludeRules = IF(pIncludeRules = 1 % pIncludeRules = 2, 1, 0);\r\n nSuppressRules = IF(nIncludeRules = 1, 1, 0);\r\n \r\n sProc = '}bedrock.cube.clone';\r\n nRet = ExecuteProcess( sProc,\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pSrcCube', pCube,\r\n 'pTgtCube', pCloneCube,\r\n 'pIncludeRules', nIncludeRules,\r\n 'pIncludeData', pIncludeData,\r\n 'pSuppressRules', nSuppressRules,\r\n 'pTemp', pTemp,\r\n 'pCubeLogging', 0\r\n );\r\n\r\n IF(nRet <> 0);\r\n sMessage = 'Error creating cloned cube for keeping data.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n ENDIF;\r\n \r\nEndif;\r\n\r\n#Processbreak;\r\n\r\n# recreate the cube\r\nsProc = '}bedrock.cube.create';\r\nnRet = ExecuteProcess( sProc,\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pCube', pCube,\r\n 'pDims', sDimString,\r\n 'pRecreate', 1,\r\n 'pDelim', sDelim\r\n );\r\n\r\nIF(nRet <> 0);\r\n sMessage = Expand('Error recreating the cube: %pCube%.');\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nENDIF;\r\n\r\n#Processbreak;\r\n\r\n# copy back the data\r\nIF(pIncludeData = 1);\r\n sProc = '}bedrock.cube.data.copy.intercube';\r\n nRet = ExecuteProcess( sProc,\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pSrcCube', pCloneCube,\r\n 'pFilter', '',\r\n 'pTgtCube', pCube,\r\n 'pMappingToNewDims', '',\r\n 'pSuppressConsol', 1,\r\n 'pSuppressRules', nSuppressRules,\r\n 'pZeroSource', 0,\r\n 'pZeroTarget', 0,\r\n 'pFactor', 1,\r\n 'pTemp', pTemp,\r\n 'pCubeLogging', 0\r\n ); \r\n \r\n IF(nRet <> 0);\r\n sMessage = Expand('Error copying back the data from clone cube: %pCloneCube%.');\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n ENDIF;\r\n \r\n # destroy clone cube\r\n IF(pTemp=1);\r\n sProc = '}bedrock.cube.delete';\r\n nRet = ExecuteProcess( sProc,\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pCube', pCloneCube,\r\n 'pCtrlObj', 0\r\n );\r\n\r\n IF(nRet <> 0);\r\n sMessage = Expand('Error deleting cloned cube: %pCloneCube%.');\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n ENDIF;\r\n Endif;\r\n \r\nEndif; \r\n\r\n# reload the rule\r\nIF(pIncludeRules = 2);\r\n \r\n sProc = '}bedrock.cube.rule.manage';\r\n\r\n nRet = ExecuteProcess( sProc,\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pCube', pCube,\r\n 'pMode', 'LOAD'\r\n );\r\n \r\n IF(nRet <> 0);\r\n sMessage = Expand('Error reloading the rule for %pCube%.');\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n # Create error rule file \r\n cErrorRuleName = 'ErrorRuleFile.rux';\r\n\r\n IF(FileExists( Lower(cErrorRuleName) ) = 0 );\r\n sFile = '.' | sOSDelim | Lower(cErrorRuleName);\r\n LogOutput(cMsgErrorLevel, 'Rule could not be attached due to invalid !Dimension references. Please recover from the backup and fix manually.');\r\n ENDIF;\r\n\r\n ExecuteProcess( sProc,\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pCube', pCube,\r\n 'pFileName', Lower(cErrorRuleName),\r\n 'pMode', 'LOAD'\r\n );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n ENDIF;\r\n \r\nEndif; \r\n\r\n### End Prolog ###", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully deleted dimension %pDim% from the %pCube% cube.' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n### End Epilog ###", @@ -10,21 +10,9 @@ "Type": "None" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "REQUIRED: Optional: write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pCube", - "Prompt": "REQUIRED: Cube", + "Prompt": "REQUIRED: Cube name", "Value": "", "Type": "String" }, @@ -36,27 +24,45 @@ }, { "Name": "pIncludeData", - "Prompt": "REQUIRED: If 1 then data is kept (copied through clone cube)", - "Value": 1, + "Prompt": "OPTIONAL: Include cube data (Boolean. Default = 0)", + "Value": 0, "Type": "Numeric" }, { "Name": "pIncludeRules", - "Prompt": "REQUIRED: Unload and reload the rule (0 = do not keep the rule, 1 = unload the rule, 2 = unload the rule and reload on new cube)", - "Value": 2, + "Prompt": "OPTIONAL: Include cube rules (Boolean. Default = 1)", + "Value": 1, "Type": "Numeric" }, { "Name": "pCtrlObj", - "Prompt": "REQUIRED: Allow overwrite control cubes", + "Prompt": "OPTIONAL: OPTIONAL: Allow modification of control objects (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { "Name": "pTemp", - "Prompt": "REQUIRED: Delete the clone cube (1 = delete, 0 = not delete)", + "Prompt": "OPTIONAL: Delete/create temporary objects (0 = Do not delete, 1 = Delete, 2 = if view and subsets are created, keep only subsets)", "Value": 1, "Type": "Numeric" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [], diff --git a/bedrock_processes_json/}bedrock.cube.dimension.replace.json b/bedrock_processes_json/}bedrock.cube.dimension.replace.json index 00eb990..ecb2d3f 100644 --- a/bedrock_processes_json/}bedrock.cube.dimension.replace.json +++ b/bedrock_processes_json/}bedrock.cube.dimension.replace.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.cube.dimension.replace", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.cube.dimension.replace', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pCube', '', 'pSrcDim', '', 'pTgtDim', '',\r\n \t'pIncludeData', 0, 'pEle', '',\r\n \t'pIncludeRules', 0,\r\n \t'pCtrlObj', 0, 'pTemp', 1\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This TI deletes a dimension and adds another one to an existing cube with the ability to preserve data.\r\n\r\n# Use case: Intended for development/prototyping.\r\n# 1/ Rebuild existing cube after removal of one dimension and adding anothr one without losing all the data.\r\n\r\n# Note:\r\n# Naturally, a valid cube name (pCube) is mandatory otherwise the process will abort.\r\n# Also, valid dimension names (pSrcDim & pTgtDim) are mandatory otherwise the process will abort.\r\n# When data needs to be kept (using pIncludeData) a valid element (pEle) in new dimension must be specified\r\n# where to store the data. Data is summed from original dimension.\r\n# Rule can be kept as backup file only or reloaded back.\r\n#EndRegion @DOC\r\n\r\n\r\n# This process selects the cube and replaces\r\n# the source dimensions from a specified target dimensions.\r\n# This process should only be run on an EMPTY cube or a cube that\r\n# has already had all data exported to a text file\r\n\r\n# Note:\r\n# - This process does not preserve any cube rules as they would likely no longer be\r\n# valid if a dimension is replaced\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pCube:%pCube%, pSrcDim:%pSrcDim%, pTgtDim:%pTgtDim%, pIncludeData:%pIncludeData%, pEle:%pEle%, pIncludeRules:%pIncludeRules%, pCtrlObj:%pCtrlObj%, pTemp:%pTemp%.' ; \r\ncDefaultView = Expand( '%cThisProcName%_%cTimeStamp%_%cRandomInt%' );\r\n\r\n## check operating system\r\nIf( SubSt( GetProcessErrorFileDirectory, 2, 1 ) @= ':' );\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nElseIf( Scan( '/', GetProcessErrorFileDirectory ) > 0 );\r\n sOS = 'Linux';\r\n sOSDelim = '/';\r\nElse;\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nEndIf;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n# Validate cube\r\nIf( Trim( pCube ) @= '' );\r\n sMessage = 'No cube specified.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( CubeExists( pCube ) = 0 );\r\n sMessage = Expand( 'Cube %pCube% does not exist.' );\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Don't allow system cubes to be modified\r\nIf( SubSt( pCube, 1, 1 ) @= '}' & pCtrlObj <= 0 );\r\n nErrors = nErrors + 1;\r\n sMessage = Expand( 'Do not modify system cubes: %pCube%.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate source dimension\r\nIf( Trim( pSrcDim ) @= '' );\r\n nErrors = nErrors + 1;\r\n sMessage = 'No source dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( DimensionExists( pSrcDim ) = 0 );\r\n nErrors = nErrors + 1;\r\n sMessage = Expand( 'Source dimension %pSrcDim% does not exist.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate target dimension\r\nIf( Trim( pTgtDim ) @= '' );\r\n nErrors = nErrors + 1;\r\n sMessage = 'No target dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( DimensionExists( pTgtDim ) = 0 );\r\n nErrors = nErrors + 1;\r\n sMessage = Expand( 'Target dimension %pTgtDim% does not exist.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Check that the source and target dimensions are different\r\nIf( pSrcDim @= pTgtDim );\r\n sMessage = Expand('Source and target dimensions are the same: %pSrcDim%');\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# check element chosen in new dimension\r\nIf( pIncludeData = 1 & Trim(pEle)@='' );\r\n nErrors = nErrors + 1;\r\n sMessage = Expand( 'No element specified in new dimension %pTgtDim% to store cube data.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nIf( pIncludeData = 1 & DIMIX(pTgtDim, pEle)=0 );\r\n nErrors = nErrors + 1;\r\n sMessage = Expand( 'Invalid element %pEle% specified for the new dimension %pTgtDim% to store cube data.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nIF(pIncludeRules = 1 % pIncludeRules = 2);\r\n sRule=CubeRuleGet( pCube );\r\n If(sRule@= '');\r\n pIncludeRules = 0;\r\n LogOutput( 'INFO', Expand( 'No rule found for %pCube%.' ) );\r\n Endif;\r\nEndif; \r\n\r\n### Determine number of dims in source cube & create strings to check and recreate ###\r\nnCount = 1;\r\nsDimString = '';\r\nsDimCheck = '';\r\nsDelim = '+';\r\nWhile( TabDim( pCube, nCount ) @<> '' );\r\n sDim = TabDim( pCube, nCount );\r\n IF(sDim@=pSrcDim);\r\n sNewDim=pTgtDim;\r\n else;\r\n sNewDim=sDim;\r\n Endif; \r\n IF(nCount = 1);\r\n sDimCheck = '+'|sDim|'+';\r\n sDimString = sNewDim;\r\n elseif(nCount > 1);\r\n sDimCheck = sDimCheck|'+'|sDim|'+';\r\n sDimString = sDimString|'+'|sNewDim;\r\n Endif;\r\n nCount = nCount + 1;\r\nEnd;\r\nnDimensionCount = nCount - 1;\r\n\r\n#Remove any leading +\r\nIF( Subst( sDimString , 1 , 1 ) @= '+' );\r\n sDimString = Subst ( sDimString , 2 , 999 );\r\nEndIf;\r\n\r\n#check source dimension\r\nIF(scan('+'|pSrcDim|'+', sDimCheck)=0);\r\n nErrors = nErrors + 1;\r\n sMessage = Expand( 'Source Dimension %pSrcDim% does not exist in %pCube%.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndif; \r\n\r\n#check target dimension\r\nIF(scan('+'|pTgtDim|'+', sDimCheck)>0);\r\n nErrors = nErrors + 1;\r\n sMessage = Expand( 'Target Dimension %pTgtDim% already exists in %pCube%.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndif;\r\n\r\n# Check if cube exceeds current max dimenions\r\nIf( nDimensionCount > 27 );\r\n sMessage = 'Process needs to be modified to handle cubes with more than 27 dimensions';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n###### CALLING THE STEP PROCESSES #####\r\n# Keep the rule\r\nIF(pIncludeRules = 1 % pIncludeRules = 2);\r\n sProc = '}bedrock.cube.rule.manage';\r\n\r\n nRet = ExecuteProcess( sProc,\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pCube', pCube,\r\n 'pMode', 'UNLOAD'\r\n );\r\n \r\n IF(nRet <> 0);\r\n sMessage = 'Error unloading the rule for %pCube%.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf; \r\n ENDIF;\r\n \r\nEndif; \r\n\r\n# create clone cube with data\r\nIF(pIncludeData = 1);\r\n \r\n pCloneCube = pCube | '_Clone';\r\n nIncludeRules = IF(pIncludeRules = 1 % pIncludeRules = 2, 1, 0);\r\n nSuppressRules = IF(nIncludeRules = 1, 1, 0);\r\n \r\n sProc = '}bedrock.cube.clone';\r\n nRet = ExecuteProcess( sProc,\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pSrcCube', pCube,\r\n 'pTgtCube', pCloneCube,\r\n 'pIncludeRules', nIncludeRules,\r\n 'pIncludeData', pIncludeData,\r\n 'pSuppressRules', nSuppressRules,\r\n 'pTemp', pTemp,\r\n 'pCubeLogging', 0\r\n );\r\n\r\n IF(nRet <> 0);\r\n sMessage = 'Error creating cloned cube for keeping data.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n ENDIF;\r\n \r\nEndif;\r\n\r\n# recreate the cube\r\nsProc = '}bedrock.cube.create';\r\nnRet = ExecuteProcess( sProc,\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pCube', pCube,\r\n 'pDims', sDimString,\r\n 'pRecreate', 1,\r\n 'pDelim', sDelim\r\n );\r\n\r\nIF(nRet <> 0);\r\n sMessage = Expand('Error recreating the cube: %pCube%.');\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nENDIF;\r\n\r\n\r\n# copy back the data\r\nIF(pIncludeData = 1);\r\n sEleStartDelim = '\u00a6';\r\n sMappingToNewDims = pTgtDim|sEleStartDelim|pEle;\r\n \r\n nRet = ExecuteProcess('}bedrock.cube.data.copy.intercube',\r\n\t 'pLogOutput',pLogOutput,\r\n\t 'pStrictErrorHandling', pStrictErrorHandling,\r\n\t 'pSrcCube',pCloneCube,\r\n\t 'pFilter','',\r\n\t 'pTgtCube',pCube,\r\n\t 'pMappingToNewDims',sMappingToNewDims,\r\n 'pSuppressConsol', 1,\r\n 'pSuppressRules', nSuppressRules,\r\n\t 'pZeroTarget',0,\r\n\t 'pZeroSource',0,\r\n\t 'pFactor',1,\r\n\t 'pDimDelim','&',\r\n\t 'pEleStartDelim',sEleStartDelim,\r\n\t 'pEleDelim','+',\r\n\t 'pTemp',pTemp,\r\n\t 'pCubeLogging',0);\r\n \r\n IF(nRet <> 0);\r\n sMessage = Expand('Error copying back the data from clone cube: %pCloneCube%.');\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n ENDIF;\r\n \r\n # destroy clone cube\r\n IF(pTemp=1);\r\n sProc = '}bedrock.cube.delete';\r\n nRet = ExecuteProcess( sProc,\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pCube', pCloneCube,\r\n 'pCtrlObj', 0\r\n );\r\n\r\n IF(nRet <> 0);\r\n sMessage = Expand('Error deleting the clone cube: %pCloneCube%.');\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n ENDIF;\r\n Endif;\r\n \r\nEndif; \r\n\r\n# reload the rule\r\nIF(pIncludeRules = 2);\r\n \r\n sProc = '}bedrock.cube.rule.manage';\r\n\r\n nRet = ExecuteProcess( sProc,\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pCube', pCube,\r\n 'pMode', 'LOAD'\r\n );\r\n \r\n IF(nRet <> 0);\r\n sMessage = Expand('Error reloading the rule for %pCube%.');\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n # Create error rule file \r\n cErrorRuleName = 'ErrorRuleFile.txt';\r\n\r\n IF(FileExists( cErrorRuleName ) = 0 );\r\n sFile = '.' | sOSDelim | cErrorRuleName;\r\n LogOutput(cMsgErrorLevel, 'Rule could not be attached due to invalid !Dimension references. Please recover from the backup and fix manually.');\r\n ENDIF;\r\n\r\n ExecuteProcess( sProc,\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pCube', pCube,\r\n 'pFileName', cErrorRuleName,\r\n 'pMode', 'LOAD'\r\n );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n ENDIF;\r\n \r\nEndif; \r\n\r\n### End Prolog ###", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.cube.dimension.replace', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pCube', '', 'pSrcDim', '', 'pTgtDim', '',\r\n \t'pIncludeData', 0, 'pEle', '',\r\n \t'pIncludeRules', 0,\r\n \t'pCtrlObj', 0, 'pTemp', 1\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This TI deletes a dimension and adds another one to an existing cube with the ability to preserve data.\r\n\r\n# Use case: Intended for development/prototyping.\r\n# 1/ Rebuild existing cube after removal of one dimension and adding anothr one without losing all the data.\r\n\r\n# Note:\r\n# Naturally, a valid cube name (pCube) is mandatory otherwise the process will abort.\r\n# Also, valid dimension names (pSrcDim & pTgtDim) are mandatory otherwise the process will abort.\r\n# When data needs to be kept (using pIncludeData) a valid element (pEle) in new dimension must be specified\r\n# where to store the data. Data is summed from original dimension.\r\n# Rule can be kept as backup file only or reloaded back.\r\n#EndRegion @DOC\r\n\r\n\r\n# This process selects the cube and replaces\r\n# the source dimensions from a specified target dimensions.\r\n# This process should only be run on an EMPTY cube or a cube that\r\n# has already had all data exported to a text file\r\n\r\n# Note:\r\n# - This process does not preserve any cube rules as they would likely no longer be\r\n# valid if a dimension is replaced\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pCube:%pCube%, pSrcDim:%pSrcDim%, pTgtDim:%pTgtDim%, pIncludeData:%pIncludeData%, pEle:%pEle%, pIncludeRules:%pIncludeRules%, pCtrlObj:%pCtrlObj%, pTemp:%pTemp%.' ; \r\ncDefaultView = Expand( '%cThisProcName%_%cTimeStamp%_%cRandomInt%' );\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pCube\": null,\r\n \"pEle\": \"\",\r\n \"pSrcDim\": null,\r\n \"pTgtDim\": null,\r\n \"pCtrlObj\": 0,\r\n \"pIncludeData\": 0,\r\n \"pIncludeRules\": 1,\r\n \"pLogOutput\": 0,\r\n \"pStrictErrorHandling\": 0,\r\n \"pTemp\": 1\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pCube\": '|StringToJson ( pCube )|',\r\n \"pEle\": '|StringToJson ( pEle )|',\r\n \"pSrcDim\": '|StringToJson ( pSrcDim )|',\r\n \"pTgtDim\": '|StringToJson ( pTgtDim )|',\r\n \"pCtrlObj\": '|NumberToString( pCtrlObj )|',\r\n \"pIncludeData\": '|NumberToString( pIncludeData )|',\r\n \"pIncludeRules\": '|NumberToString( pIncludeRules )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|',\r\n \"pTemp\": '|NumberToString( pTemp )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npCube = JsonToString( JsonGet( pJson, 'pCube' ) );\r\npEle = JsonToString( JsonGet( pJson, 'pEle' ) );\r\npSrcDim = JsonToString( JsonGet( pJson, 'pSrcDim' ) );\r\npTgtDim = JsonToString( JsonGet( pJson, 'pTgtDim' ) );\r\n# Numeric Parameters\r\npCtrlObj = StringToNumber( JsonToString( JsonGet( pJson, 'pCtrlObj' ) ) );\r\npIncludeData = StringToNumber( JsonToString( JsonGet( pJson, 'pIncludeData' ) ) );\r\npIncludeRules = StringToNumber( JsonToString( JsonGet( pJson, 'pIncludeRules' ) ) );\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\npTemp = StringToNumber( JsonToString( JsonGet( pJson, 'pTemp' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n## check operating system\r\nIf( SubSt( GetProcessErrorFileDirectory, 2, 1 ) @= ':' );\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nElseIf( Scan( '/', GetProcessErrorFileDirectory ) > 0 );\r\n sOS = 'Linux';\r\n sOSDelim = '/';\r\nElse;\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nEndIf;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n# Validate cube\r\nIf( Trim( pCube ) @= '' );\r\n sMessage = 'No cube specified.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( CubeExists( pCube ) = 0 );\r\n sMessage = Expand( 'Cube %pCube% does not exist.' );\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Don't allow system cubes to be modified\r\nIf( SubSt( pCube, 1, 1 ) @= '}' & pCtrlObj <= 0 );\r\n nErrors = nErrors + 1;\r\n sMessage = Expand( 'Do not modify system cubes: %pCube%.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate source dimension\r\nIf( Trim( pSrcDim ) @= '' );\r\n nErrors = nErrors + 1;\r\n sMessage = 'No source dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( DimensionExists( pSrcDim ) = 0 );\r\n nErrors = nErrors + 1;\r\n sMessage = Expand( 'Source dimension %pSrcDim% does not exist.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate target dimension\r\nIf( Trim( pTgtDim ) @= '' );\r\n nErrors = nErrors + 1;\r\n sMessage = 'No target dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( DimensionExists( pTgtDim ) = 0 );\r\n nErrors = nErrors + 1;\r\n sMessage = Expand( 'Target dimension %pTgtDim% does not exist.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Check that the source and target dimensions are different\r\nIf( pSrcDim @= pTgtDim );\r\n sMessage = Expand('Source and target dimensions are the same: %pSrcDim%');\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# check element chosen in new dimension\r\nIf( pIncludeData = 1 & Trim(pEle)@='' );\r\n nErrors = nErrors + 1;\r\n sMessage = Expand( 'No element specified in new dimension %pTgtDim% to store cube data.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nIf( pIncludeData = 1 & DIMIX(pTgtDim, pEle)=0 );\r\n nErrors = nErrors + 1;\r\n sMessage = Expand( 'Invalid element %pEle% specified for the new dimension %pTgtDim% to store cube data.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nIF(pIncludeRules = 1 % pIncludeRules = 2);\r\n sRule=CubeRuleGet( pCube );\r\n If(sRule@= '');\r\n pIncludeRules = 0;\r\n LogOutput( 'INFO', Expand( 'No rule found for %pCube%.' ) );\r\n Endif;\r\nEndif; \r\n\r\n### Determine number of dims in source cube & create strings to check and recreate ###\r\nnCount = 1;\r\nsDimString = '';\r\nsDimCheck = '';\r\nsDelim = '+';\r\nWhile( TabDim( pCube, nCount ) @<> '' );\r\n sDim = TabDim( pCube, nCount );\r\n IF(sDim@=pSrcDim);\r\n sNewDim=pTgtDim;\r\n else;\r\n sNewDim=sDim;\r\n Endif; \r\n IF(nCount = 1);\r\n sDimCheck = '+'|sDim|'+';\r\n sDimString = sNewDim;\r\n elseif(nCount > 1);\r\n sDimCheck = sDimCheck|'+'|sDim|'+';\r\n sDimString = sDimString|'+'|sNewDim;\r\n Endif;\r\n nCount = nCount + 1;\r\nEnd;\r\nnDimensionCount = nCount - 1;\r\n\r\n#Remove any leading +\r\nIF( Subst( sDimString , 1 , 1 ) @= '+' );\r\n sDimString = Subst ( sDimString , 2 , 999 );\r\nEndIf;\r\n\r\n#check source dimension\r\nIF(scan('+'|pSrcDim|'+', sDimCheck)=0);\r\n nErrors = nErrors + 1;\r\n sMessage = Expand( 'Source Dimension %pSrcDim% does not exist in %pCube%.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndif; \r\n\r\n#check target dimension\r\nIF(scan('+'|pTgtDim|'+', sDimCheck)>0);\r\n nErrors = nErrors + 1;\r\n sMessage = Expand( 'Target Dimension %pTgtDim% already exists in %pCube%.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndif;\r\n\r\n# Check if cube exceeds current max dimenions\r\nIf( nDimensionCount > 27 );\r\n sMessage = 'Process needs to be modified to handle cubes with more than 27 dimensions';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n###### CALLING THE STEP PROCESSES #####\r\n# Keep the rule\r\nIF(pIncludeRules = 1 % pIncludeRules = 2);\r\n sProc = '}bedrock.cube.rule.manage';\r\n\r\n nRet = ExecuteProcess( sProc,\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pCube', pCube,\r\n 'pMode', 'UNLOAD'\r\n );\r\n \r\n IF(nRet <> 0);\r\n sMessage = 'Error unloading the rule for %pCube%.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf; \r\n ENDIF;\r\n \r\nEndif; \r\n\r\n# create clone cube with data\r\nIF(pIncludeData = 1);\r\n \r\n pCloneCube = pCube | '_Clone';\r\n nIncludeRules = IF(pIncludeRules = 1 % pIncludeRules = 2, 1, 0);\r\n nSuppressRules = IF(nIncludeRules = 1, 1, 0);\r\n \r\n sProc = '}bedrock.cube.clone';\r\n nRet = ExecuteProcess( sProc,\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pSrcCube', pCube,\r\n 'pTgtCube', pCloneCube,\r\n 'pIncludeRules', nIncludeRules,\r\n 'pIncludeData', pIncludeData,\r\n 'pSuppressRules', nSuppressRules,\r\n 'pTemp', pTemp,\r\n 'pCubeLogging', 0\r\n );\r\n\r\n IF(nRet <> 0);\r\n sMessage = 'Error creating cloned cube for keeping data.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n ENDIF;\r\n \r\nEndif;\r\n\r\n# recreate the cube\r\nsProc = '}bedrock.cube.create';\r\nnRet = ExecuteProcess( sProc,\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pCube', pCube,\r\n 'pDims', sDimString,\r\n 'pRecreate', 1,\r\n 'pDelim', sDelim\r\n );\r\n\r\nIF(nRet <> 0);\r\n sMessage = Expand('Error recreating the cube: %pCube%.');\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nENDIF;\r\n\r\n\r\n# copy back the data\r\nIF(pIncludeData = 1);\r\n sEleStartDelim = '\u00a6';\r\n sMappingToNewDims = pTgtDim|sEleStartDelim|pEle;\r\n \r\n nRet = ExecuteProcess('}bedrock.cube.data.copy.intercube',\r\n\t 'pLogOutput',pLogOutput,\r\n\t 'pStrictErrorHandling', pStrictErrorHandling,\r\n\t 'pSrcCube',pCloneCube,\r\n\t 'pFilter','',\r\n\t 'pTgtCube',pCube,\r\n\t 'pMappingToNewDims',sMappingToNewDims,\r\n 'pSuppressConsol', 1,\r\n 'pSuppressRules', nSuppressRules,\r\n\t 'pZeroTarget',0,\r\n\t 'pZeroSource',0,\r\n\t 'pFactor',1,\r\n\t 'pDimDelim','&',\r\n\t 'pEleStartDelim',sEleStartDelim,\r\n\t 'pEleDelim','+',\r\n\t 'pTemp',pTemp,\r\n\t 'pCubeLogging',0);\r\n \r\n IF(nRet <> 0);\r\n sMessage = Expand('Error copying back the data from clone cube: %pCloneCube%.');\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n ENDIF;\r\n \r\n # destroy clone cube\r\n IF(pTemp=1);\r\n sProc = '}bedrock.cube.delete';\r\n nRet = ExecuteProcess( sProc,\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pCube', pCloneCube,\r\n 'pCtrlObj', 0\r\n );\r\n\r\n IF(nRet <> 0);\r\n sMessage = Expand('Error deleting the clone cube: %pCloneCube%.');\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n ENDIF;\r\n Endif;\r\n \r\nEndif; \r\n\r\n# reload the rule\r\nIF(pIncludeRules = 2);\r\n \r\n sProc = '}bedrock.cube.rule.manage';\r\n\r\n nRet = ExecuteProcess( sProc,\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pCube', pCube,\r\n 'pMode', 'LOAD'\r\n );\r\n \r\n IF(nRet <> 0);\r\n sMessage = Expand('Error reloading the rule for %pCube%.');\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n # Create error rule file \r\n cErrorRuleName = 'ErrorRuleFile.txt';\r\n\r\n IF(FileExists( cErrorRuleName ) = 0 );\r\n sFile = '.' | sOSDelim | cErrorRuleName;\r\n LogOutput(cMsgErrorLevel, 'Rule could not be attached due to invalid !Dimension references. Please recover from the backup and fix manually.');\r\n ENDIF;\r\n\r\n ExecuteProcess( sProc,\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pCube', pCube,\r\n 'pFileName', cErrorRuleName,\r\n 'pMode', 'LOAD'\r\n );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n ENDIF;\r\n \r\nEndif; \r\n\r\n### End Prolog ###", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully replaced the %pSrcDim% dimension with the %pTgtDim% in the %pCube% cube. Data was loaded to the %pEle% item.' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n \r\n### End Epilog ###", @@ -10,21 +10,9 @@ "Type": "None" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pCube", - "Prompt": "REQUIRED: Cube", + "Prompt": "REQUIRED: Cube name", "Value": "", "Type": "String" }, @@ -42,33 +30,51 @@ }, { "Name": "pIncludeData", - "Prompt": "REQUIRED: If 1 then data is kept (copied through clone cube)", + "Prompt": "OPTIONAL: Include cube data (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { "Name": "pEle", - "Prompt": "REQUIRED: If pIncludeData =1: Element in target dimension to load data to", + "Prompt": "OPTIONAL: Required if IncludeData flag =1. Element of new dimension where the existing data will be stored", "Value": "", "Type": "String" }, { "Name": "pIncludeRules", - "Prompt": "REQUIRED: Unload and reload the rule (0 = do not keep the rule, 1 = unload the rule, 2 = unload the rule and reload on new cube)", - "Value": 0, + "Prompt": "OPTIONAL: Include cube rules (Boolean. Default = 1)", + "Value": 1, "Type": "Numeric" }, { "Name": "pCtrlObj", - "Prompt": "REQUIRED: Allow overwrite control cubes", + "Prompt": "OPTIONAL: OPTIONAL: Allow modification of control objects (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { "Name": "pTemp", - "Prompt": "REQUIRED: Delete the clone cube (1 = delete, 0 = not delete)", + "Prompt": "OPTIONAL: Delete/create temporary objects (0 = Do not delete, 1 = Delete, 2 = if view and subsets are created, keep only subsets)", "Value": 1, "Type": "Numeric" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [], diff --git a/bedrock_processes_json/}bedrock.cube.rule.manage.json b/bedrock_processes_json/}bedrock.cube.rule.manage.json index 131ed33..1c2c22f 100644 --- a/bedrock_processes_json/}bedrock.cube.rule.manage.json +++ b/bedrock_processes_json/}bedrock.cube.rule.manage.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.cube.rule.manage", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.cube.rule.manage', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pCube', '', 'pMode', '',\r\n \t'pFileName', '', 'pDelim','&', \r\n \t'pPath', ''\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# ####################\r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will backup & remove **OR** re-attach the rule file to cube.\r\n\r\n# Use case: Intended to be used in production.\r\n# 1/ Remove rule file before data load to speed up data load.\r\n# 2/ Re-attach rule file after data load.\r\n\r\n# Note:\r\n# Naturally, a valid cube name (pCube) is mandatory otherwise the process will abort.\r\n# The mandatory pMode parameter must be set to 'Unload' to remove/unload the rule file.\r\n# The pMode parameter must be set to 'Load' to re-attach the rule file and apply the rules.\r\n#EndRegion @DOC\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\n\r\ncThisProcName = GetProcessName();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName | '_' | cTimeStamp | '_' | cRandomInt;\r\ncCubeDim = '}Cubes';\r\ncCubeHier = cCubeDim;\r\nsPath = '';\r\ncUserName = TM1User();\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pCube:%pCube%, pMode:%pMode%, pFileName:%pFileName%, pDelim:%pDelim%, pPath:%pPath%.' ; \r\ncDimCubes = '}Cubes';\r\n\r\n### check operating system\r\nIf( SubSt( GetProcessErrorFileDirectory, 2, 1 ) @= ':' );\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nElseIf( Scan( '/', GetProcessErrorFileDirectory ) > 0 );\r\n sOS = 'Linux';\r\n sOSDelim = '/';\r\nElse;\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nEndIf;\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\nnErrors = 0;\r\n\r\n### PROCESS PROPERTIES\r\nDatasourceASCIIDelimiter = '';\r\nDatasourceASCIIQuoteCharacter = '';\r\n\r\n##Validate Mode\r\nIf(upper(pMode) @<> 'LOAD' & upper(pMode) @<> 'UNLOAD');\r\n sMessage = Expand('Invalid Mode: %pMode%. Valid Modes are Load or Unload');\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndif;\r\n\r\n##Validate Cube\r\nIf( Trim(pCube) @= '' );\r\n sMessage = Expand('No cube specified');\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndif;\r\n\r\n## Default filter delimiters\r\nIf( pDelim @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\n# define backupdir\r\nIf(pPath @<> '');\r\n If(Subst(pPath,long(pPath),1) @= sOSDelim );\r\n sPath = pPath;\r\n Else;\r\n sPath = pPath | sOSDelim;\r\n Endif;\r\nElse;\r\n sPath = '.' | sOSDelim;\r\nEndif;\r\n\r\n## Default files names for storing rule and backups\r\nIF(pFileName@='' % Scan( pDelim, pCube )<>0);\r\n sRuleFileName = '%sCube%.txt';\r\n sBackupFileName = '%sCube%.rux.bkp_%cTimeStamp%.txt';\r\nElse;\r\n sRuleFileName = pFileName;\r\n sBackupFileName = '%pFileName%.bkp_%cTimeStamp%.txt';\r\nEndif; \r\n \r\n# Loop through list of Cubes\r\nsCubes = pCube;\r\nnCubeDelimIndex = 1;\r\n\r\nWhile( nCubeDelimIndex <> 0 );\r\n nCubeDelimIndex = Scan( pDelim, sCubes );\r\n If( nCubeDelimIndex = 0 );\r\n sCube = sCubes;\r\n Else;\r\n sCube = Trim( SubSt( sCubes, 1, nCubeDelimIndex - 1 ) );\r\n sCubes = Trim( Subst( sCubes, nCubeDelimIndex + Long(pDelim), Long( sCubes ) ) );\r\n EndIf;\r\n\r\n sMDX = Expand( '{TM1FILTERBYPATTERN(TM1SUBSETALL([}Cubes]), \"%sCube%\")}' );\r\n\r\n sProc = '}bedrock.hier.sub.create.bymdx';\r\n ExecuteProcess( sProc,\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pDim', cDimCubes,\r\n 'pHier', '',\r\n 'pSub', cTempSub,\r\n 'pMDXExpr', sMDX,\r\n 'pConvertToStatic', 1,\r\n 'pTemp', 1\r\n );\r\n\r\n nCube = 1;\r\n nCubes = SubsetGetSize( cDimCubes, cTempSub );\r\n While( nCube <= nCubes );\r\n sCube = SubsetGetElementName( cDimCubes, cTempSub, nCube );\r\n nCube = nCube + 1;\r\n \r\n cCubeRuleFileName = '.' | sOSDelim | sCube | '.txt';\r\n cStoreDirFile = sPath | Expand(sRuleFileName);\r\n\r\n ##Unloading the Rule###\r\n If(Upper(pMode) @= 'UNLOAD');\r\n ##Before unloading, backup the existing rule (saved as .bkp.txt in data directory or with the suffix parameter)\r\n ##and drop current rule\r\n sRule=CubeRuleGet( sCube );\r\n ASCIIOutput(cStoreDirFile, sRule);\r\n ## Check if the saved rule file exists\r\n If( sRule@<>'' );\r\n CubeRuleDestroy( sCube );\r\n Else;\r\n sMessage = Expand('Copy of rule file (%cCubeRuleFileName%) has failed, rule was not unloaded.');\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n EndIf;\r\n\r\n ##Loading the Rule###\r\n ElseIf(Upper(pMode) @= 'LOAD');\r\n ##Backup the existing rule (saved as .bkp.txt in given path or data directory) \r\n ##and load the new rule file. New Rule file should available in the given path or in data directory\r\n ## Check if the backup file exists\r\n If( FileExists( cCubeRuleFileName ) <> 0 );\r\n RuleLoadFromFile( sCube, cCubeRuleFileName);\r\n Else;\r\n nErrors = nErrors + 1;\r\n sMessage = 'No Rule file found for cube: ' | sCube;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n EndIf;\r\n\r\n Endif;\r\n End;\r\nEnd;\r\n\r\n### end Prolog ###", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.cube.rule.manage', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pCube', '', 'pMode', '',\r\n \t'pFileName', '', 'pDelim','&', \r\n \t'pPath', ''\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# ####################\r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will backup & remove **OR** re-attach the rule file to cube.\r\n\r\n# Use case: Intended to be used in production.\r\n# 1/ Remove rule file before data load to speed up data load.\r\n# 2/ Re-attach rule file after data load.\r\n\r\n# Note:\r\n# Naturally, a valid cube name (pCube) is mandatory otherwise the process will abort.\r\n# The mandatory pMode parameter must be set to 'Unload' to remove/unload the rule file.\r\n# The pMode parameter must be set to 'Load' to re-attach the rule file and apply the rules.\r\n#EndRegion @DOC\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\n\r\ncThisProcName = GetProcessName();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName | '_' | cTimeStamp | '_' | cRandomInt;\r\ncCubeDim = '}Cubes';\r\ncCubeHier = cCubeDim;\r\nsPath = '';\r\ncUserName = TM1User();\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pCube:%pCube%, pMode:%pMode%, pFileName:%pFileName%, pDelim:%pDelim%, pPath:%pPath%.' ; \r\ncDimCubes = '}Cubes';\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pCube\": null,\r\n \"pDelim\": \"&\",\r\n \"pFileName\": \"\",\r\n \"pMode\": null,\r\n \"pPath\": \"\",\r\n \"pLogOutput\": 0,\r\n \"pStrictErrorHandling\": 0\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pCube\": '|StringToJson ( pCube )|',\r\n \"pDelim\": '|StringToJson ( pDelim )|',\r\n \"pFileName\": '|StringToJson ( pFileName )|',\r\n \"pMode\": '|StringToJson ( pMode )|',\r\n \"pPath\": '|StringToJson ( pPath )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npCube = JsonToString( JsonGet( pJson, 'pCube' ) );\r\npDelim = JsonToString( JsonGet( pJson, 'pDelim' ) );\r\npFileName = JsonToString( JsonGet( pJson, 'pFileName' ) );\r\npMode = JsonToString( JsonGet( pJson, 'pMode' ) );\r\npPath = JsonToString( JsonGet( pJson, 'pPath' ) );\r\n# Numeric Parameters\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n### check operating system\r\nIf( SubSt( GetProcessErrorFileDirectory, 2, 1 ) @= ':' );\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nElseIf( Scan( '/', GetProcessErrorFileDirectory ) > 0 );\r\n sOS = 'Linux';\r\n sOSDelim = '/';\r\nElse;\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nEndIf;\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\nnErrors = 0;\r\n\r\n### PROCESS PROPERTIES\r\nDatasourceASCIIDelimiter = '';\r\nDatasourceASCIIQuoteCharacter = '';\r\n\r\n##Validate Mode\r\nIf(upper(pMode) @<> 'LOAD' & upper(pMode) @<> 'UNLOAD');\r\n sMessage = Expand('Invalid Mode: %pMode%. Valid Modes are Load or Unload');\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndif;\r\n\r\n##Validate Cube\r\nIf( Trim(pCube) @= '' );\r\n sMessage = Expand('No cube specified');\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndif;\r\n\r\n## Default filter delimiters\r\nIf( pDelim @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\n# define backupdir\r\nIf(pPath @<> '');\r\n If(Subst(pPath,long(pPath),1) @= sOSDelim );\r\n sPath = pPath;\r\n Else;\r\n sPath = pPath | sOSDelim;\r\n Endif;\r\nElse;\r\n sPath = '.' | sOSDelim;\r\nEndif;\r\n\r\n## Default files names for storing rule and backups\r\nIF(pFileName@='' % Scan( pDelim, pCube )<>0);\r\n sRuleFileName = '%sCube%.txt';\r\n sBackupFileName = '%sCube%.rux.bkp_%cTimeStamp%.txt';\r\nElse;\r\n sRuleFileName = pFileName;\r\n sBackupFileName = '%pFileName%.bkp_%cTimeStamp%.txt';\r\nEndif; \r\n \r\n# Loop through list of Cubes\r\nsCubes = pCube;\r\nnCubeDelimIndex = 1;\r\n\r\nWhile( nCubeDelimIndex <> 0 );\r\n nCubeDelimIndex = Scan( pDelim, sCubes );\r\n If( nCubeDelimIndex = 0 );\r\n sCube = sCubes;\r\n Else;\r\n sCube = Trim( SubSt( sCubes, 1, nCubeDelimIndex - 1 ) );\r\n sCubes = Trim( Subst( sCubes, nCubeDelimIndex + Long(pDelim), Long( sCubes ) ) );\r\n EndIf;\r\n\r\n sMDX = Expand( '{TM1FILTERBYPATTERN(TM1SUBSETALL([}Cubes]), \"%sCube%\")}' );\r\n\r\n sProc = '}bedrock.hier.sub.create.bymdx';\r\n ExecuteProcess( sProc,\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pDim', cDimCubes,\r\n 'pHier', '',\r\n 'pSub', cTempSub,\r\n 'pMDXExpr', sMDX,\r\n 'pConvertToStatic', 1,\r\n 'pTemp', 1\r\n );\r\n\r\n nCube = 1;\r\n nCubes = SubsetGetSize( cDimCubes, cTempSub );\r\n While( nCube <= nCubes );\r\n sCube = SubsetGetElementName( cDimCubes, cTempSub, nCube );\r\n nCube = nCube + 1;\r\n \r\n cCubeRuleFileName = '.' | sOSDelim | sCube | '.txt';\r\n cStoreDirFile = sPath | Expand(sRuleFileName);\r\n\r\n ##Unloading the Rule###\r\n If(Upper(pMode) @= 'UNLOAD');\r\n ##Before unloading, backup the existing rule (saved as .bkp.txt in data directory or with the suffix parameter)\r\n ##and drop current rule\r\n sRule=CubeRuleGet( sCube );\r\n ASCIIOutput(cStoreDirFile, sRule);\r\n ## Check if the saved rule file exists\r\n If( sRule@<>'' );\r\n CubeRuleDestroy( sCube );\r\n Else;\r\n sMessage = Expand('Copy of rule file (%cCubeRuleFileName%) has failed, rule was not unloaded.');\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n EndIf;\r\n\r\n ##Loading the Rule###\r\n ElseIf(Upper(pMode) @= 'LOAD');\r\n ##Backup the existing rule (saved as .bkp.txt in given path or data directory) \r\n ##and load the new rule file. New Rule file should available in the given path or in data directory\r\n ## Check if the backup file exists\r\n If( FileExists( cCubeRuleFileName ) <> 0 );\r\n RuleLoadFromFile( sCube, cCubeRuleFileName);\r\n Else;\r\n nErrors = nErrors + 1;\r\n sMessage = 'No Rule file found for cube: ' | sCube;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n EndIf;\r\n\r\n Endif;\r\n End;\r\nEnd;\r\n\r\n### end Prolog ###", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# ####################\r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully %pMode% cube rule from cube %pCube% .' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n### End Epilog ###", @@ -10,21 +10,9 @@ "Type": "None" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pCube", - "Prompt": "REQUIRED: Cube Name to Load/Unload rule (Separated by Delimiter, Accepts Wild card)", + "Prompt": "REQUIRED: Cube name", "Value": "", "Type": "String" }, @@ -36,21 +24,39 @@ }, { "Name": "pFileName", - "Prompt": "OPTIONAL: Full file name for storing the rule (if empty = cube name.txt)", + "Prompt": "OPTIONAL: File name (Default = pCube | '_Export.csv')", "Value": "", "Type": "String" }, { "Name": "pDelim", - "Prompt": "OPTIONAL: Delimiter (default value if blank = '&')", + "Prompt": "OPTIONAL: Delimiter for list parameters (Default = '&')", "Value": "&", "Type": "String" }, { "Name": "pPath", - "Prompt": "OPTIONAL: Saves the file and the backup of the existing rule in this location. If Null, backup will be saved in Data Directory. Default value Null", + "Prompt": "OPTIONAL: File directory (Default = GetProcessErrorFileDirectory)", "Value": "", "Type": "String" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [], diff --git a/bedrock_processes_json/}bedrock.cube.rule.processfeeders.json b/bedrock_processes_json/}bedrock.cube.rule.processfeeders.json index fd02d4b..d85f008 100644 --- a/bedrock_processes_json/}bedrock.cube.rule.processfeeders.json +++ b/bedrock_processes_json/}bedrock.cube.rule.processfeeders.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.cube.rule.processfeeders", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.cube.rule.processfeeders', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n\t 'pCube', '', 'pDelim', '&'\r\n );\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# ####################\r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process reprocesses feeders when consolidated totals are not adding up.\r\n\r\n# Use case: Intended for Deveopment or production.\r\n#1/ This process would be used any time feeders need to be reprocessed (e.g. when new elements are added to any of the dimensions).\r\n\r\n# Note:\r\n# Naturally, a valid cube name (pCube) is mandatory otherwise the process will abort. Wildcards and lists are acceptable.\r\n# This process will process feeders for a cube.\r\n#EndRegion @DOC\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\n\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\nsMessage = \t'';\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pCube:%pCube%, pDelim:%pDelim%.' ; \r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\nnErrors = 0;\r\n\r\n### Validate Parameters ###\r\n# If blank delimiter specified then convert to default\r\nIf( pDelim @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\n# If no cubes have been specified then terminate process\r\nIf( Trim( pCube ) @= '' );\r\n sMessage = 'No cubes specified';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n\r\n### SET DATA SOURCE ###\r\n\r\nDatasourceType = 'NULL';\r\n\r\n\r\n### Split parameter into individual cubes and delete ###\r\n\r\nsCubes = pCube;\r\nnDelimiterIndex = 1;\r\nsMdx = '';\r\n\r\nWhile( nDelimiterIndex <> 0 );\r\n nDelimiterIndex = Scan( pDelim, sCubes );\r\n If( nDelimiterIndex = 0 );\r\n sCube = sCubes;\r\n Else;\r\n sCube = Trim( SubSt( sCubes, 1, nDelimiterIndex - 1 ) );\r\n sCubes = Trim( Subst( sCubes, nDelimiterIndex + Long(pDelim), Long( sCubes ) ) );\r\n EndIf;\r\n \r\n # Check if a wildcard has been used to specify the Cube name.\r\n # If it hasn't then just delete the Cube if it exists\r\n # If it has then search the relevant Cube folder to find the matches\r\n If( Scan( '*', sCube ) = 0 );\r\n If( CubeExists( sCube ) = 1 ); \r\n CubeProcessFeeders( sCube );\r\n Endif;\r\n Else;\r\n # Create subset of cubes using Wildcard\r\n sCubeExp = '\"'|sCube|'\"';\r\n sMdxPart = '{TM1FILTERBYPATTERN( TM1SUBSETALL( [}Cubes] ) ,'| sCubeExp | ')}';\r\n IF( sMdx @= ''); \r\n sMdx = sMdxPart; \r\n ELSE;\r\n sMdx = sMdx | ' + ' | sMdxPart;\r\n ENDIF;\r\n \r\n If( SubsetExists( '}Cubes' , cTempSub ) = 1 );\r\n # If a delimited list of cube names includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( '}Cubes' , cTempSub, sMDX );\r\n Else;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSub, sMDX, '}Cubes' , 1 );\r\n EndIf;\r\n \r\n # Loop through cubes in subset created based on wildcard\r\n nCountCubes = SubsetGetSize( '}Cubes' , cTempSub );\r\n While( nCountCubes >= 1 );\r\n sCurrCube = SubsetGetElementName( '}Cubes' , cTempSub, nCountCubes );\r\n # Validate cube name\r\n If( CubeExists( sCurrCube ) = 1 ); \r\n # Process Feeders\r\n CubeProcessFeeders( sCurrCube );\r\n Endif;\r\n nCountCubes = nCountCubes - 1;\r\n End;\r\n EndIf;\r\n\r\nEnd;\r\n\r\n", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.cube.rule.processfeeders', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n\t 'pCube', '', 'pDelim', '&'\r\n );\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# ####################\r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process reprocesses feeders when consolidated totals are not adding up.\r\n\r\n# Use case: Intended for Deveopment or production.\r\n#1/ This process would be used any time feeders need to be reprocessed (e.g. when new elements are added to any of the dimensions).\r\n\r\n# Note:\r\n# Naturally, a valid cube name (pCube) is mandatory otherwise the process will abort. Wildcards and lists are acceptable.\r\n# This process will process feeders for a cube.\r\n#EndRegion @DOC\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\n\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\nsMessage = \t'';\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pCube:%pCube%, pDelim:%pDelim%.' ; \r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pCube\": null,\r\n \"pDelim\": \"&\",\r\n \"pLogOutput\": 0,\r\n \"pStrictErrorHandling\": 0\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pCube\": '|StringToJson ( pCube )|',\r\n \"pDelim\": '|StringToJson ( pDelim )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npCube = JsonToString( JsonGet( pJson, 'pCube' ) );\r\npDelim = JsonToString( JsonGet( pJson, 'pDelim' ) );\r\n# Numeric Parameters\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\nnErrors = 0;\r\n\r\n### Validate Parameters ###\r\n# If blank delimiter specified then convert to default\r\nIf( pDelim @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\n# If no cubes have been specified then terminate process\r\nIf( Trim( pCube ) @= '' );\r\n sMessage = 'No cubes specified';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n\r\n### SET DATA SOURCE ###\r\n\r\nDatasourceType = 'NULL';\r\n\r\n\r\n### Split parameter into individual cubes and delete ###\r\n\r\nsCubes = pCube;\r\nnDelimiterIndex = 1;\r\nsMdx = '';\r\n\r\nWhile( nDelimiterIndex <> 0 );\r\n nDelimiterIndex = Scan( pDelim, sCubes );\r\n If( nDelimiterIndex = 0 );\r\n sCube = sCubes;\r\n Else;\r\n sCube = Trim( SubSt( sCubes, 1, nDelimiterIndex - 1 ) );\r\n sCubes = Trim( Subst( sCubes, nDelimiterIndex + Long(pDelim), Long( sCubes ) ) );\r\n EndIf;\r\n \r\n # Check if a wildcard has been used to specify the Cube name.\r\n # If it hasn't then just delete the Cube if it exists\r\n # If it has then search the relevant Cube folder to find the matches\r\n If( Scan( '*', sCube ) = 0 );\r\n If( CubeExists( sCube ) = 1 ); \r\n CubeProcessFeeders( sCube );\r\n Endif;\r\n Else;\r\n # Create subset of cubes using Wildcard\r\n sCubeExp = '\"'|sCube|'\"';\r\n sMdxPart = '{TM1FILTERBYPATTERN( TM1SUBSETALL( [}Cubes] ) ,'| sCubeExp | ')}';\r\n IF( sMdx @= ''); \r\n sMdx = sMdxPart; \r\n ELSE;\r\n sMdx = sMdx | ' + ' | sMdxPart;\r\n ENDIF;\r\n \r\n If( SubsetExists( '}Cubes' , cTempSub ) = 1 );\r\n # If a delimited list of cube names includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( '}Cubes' , cTempSub, sMDX );\r\n Else;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSub, sMDX, '}Cubes' , 1 );\r\n EndIf;\r\n \r\n # Loop through cubes in subset created based on wildcard\r\n nCountCubes = SubsetGetSize( '}Cubes' , cTempSub );\r\n While( nCountCubes >= 1 );\r\n sCurrCube = SubsetGetElementName( '}Cubes' , cTempSub, nCountCubes );\r\n # Validate cube name\r\n If( CubeExists( sCurrCube ) = 1 ); \r\n # Process Feeders\r\n CubeProcessFeeders( sCurrCube );\r\n Endif;\r\n nCountCubes = nCountCubes - 1;\r\n End;\r\n EndIf;\r\n\r\nEnd;\r\n\r\n", "MetadataProcedure": "#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n", "DataProcedure": "#****Begin: Generated Statements***\r\n#****End: Generated Statements****", "EpilogProcedure": "#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully processed feeders for cube %pCube% .' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n\r\n### End Epilog ###", @@ -10,28 +10,34 @@ "Type": "None" }, "Parameters": [ + { + "Name": "pCube", + "Prompt": "REQUIRED: Cube name", + "Value": "", + "Type": "String" + }, + { + "Name": "pDelim", + "Prompt": "OPTIONAL: Delimiter for list parameters (Default = '&')", + "Value": "&", + "Type": "String" + }, { "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { - "Name": "pCube", - "Prompt": "REQUIRED: Process feeders for this cube (Separated by Delimiter, Accepts Wild card)", - "Value": "", - "Type": "String" - }, - { - "Name": "pDelim", - "Prompt": "OPTIONAL: Delimiter (default value if blank = '&')", - "Value": "&", + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", "Type": "String" } ], diff --git a/bedrock_processes_json/}bedrock.cube.view.create.bymdx.json b/bedrock_processes_json/}bedrock.cube.view.create.bymdx.json index b498687..d36865a 100644 --- a/bedrock_processes_json/}bedrock.cube.view.create.bymdx.json +++ b/bedrock_processes_json/}bedrock.cube.view.create.bymdx.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.cube.view.create.bymdx", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.cube.view.create.bymdx', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pCube', '', 'pView', '',\r\n \t'pMDXExpr', '',\r\n \t'pTemp', 1\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock Ver 4.0.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description: \r\n# This process will Create a dynamic view from an MDX expression that evaluates to a non-empty set in the specified dimension.\r\n\r\n# Use case: Intended for development/prototyping or production.\r\n# 1/ Create a view to zero out data.\r\n# 2/ Create a view to use as a source for exporting or copying.\r\n\r\n# Note:\r\n# Naturally, a valid cube name (pCube) is mandatory otherwise the process will abort.\r\n# If the MDX does not compile or produces an empty set the process will error.\r\n# pTemp: This parameter will control whether to make the view temporary (value 1) or if the\r\n# view will be permanently retained (value 0).\r\n#EndRegion @DOC\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\n\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSubset = cThisProcName | '_' | cTimeStamp | '_' | cRandomInt;\r\ncTempFile = GetProcessErrorFileDirectory | cTempSubset | '.csv';\r\nsMessage = \t'';\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pCube:%pCube%, pView:%pView%, pMDXExpr:%pMDXExpr%, pTemp:%pTemp%.' ; \r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\nsMDXExpr = TRIM( pMDXExpr );\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\n# Validate Cube\r\nIf( Trim( pCube ) @= '' );\r\n sMessage = 'No cube specified.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( CubeExists( pCube ) = 0 );\r\n sMessage = Expand('Cube %pCube% does not exist') ;\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate View\r\nIf( Trim( pView ) @= '' );\r\n sMessage = 'No view specified';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate MDX\r\nIf( Trim( sMDXExpr ) @= '' );\r\n sMessage = 'No MDX expression specified';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate MDX. Checking Cube name mentioned in MDX\r\nIf( SCAN ( pCube , sMDXExpr ) = 0 );\r\n sMessage = 'No Cube Name mentioned in MDX. Not a valid MDX expression';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n## Validate pTemp\r\nIF( pTemp<> 0 & pTemp<> 1 );\r\n nErrors = 1;\r\n sMessage = 'Invalid value for pTemp' | NumberToString( pTemp ) | '. Valid values are 0 and 1';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### Create View ###\r\nIf( ViewExists( pCube , pView ) = 1 );\r\n ViewDestroy( pCube , pView );\r\nEndIf;\r\n\r\nViewCreatebyMDX ( pCube , pView , sMDXExpr, pTemp ) ; \r\n\r\n### End Prolog ###", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.cube.view.create.bymdx', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pCube', '', 'pView', '',\r\n \t'pMDXExpr', '',\r\n \t'pTemp', 1\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock Ver 4.0.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description: \r\n# This process will Create a dynamic view from an MDX expression that evaluates to a non-empty set in the specified dimension.\r\n\r\n# Use case: Intended for development/prototyping or production.\r\n# 1/ Create a view to zero out data.\r\n# 2/ Create a view to use as a source for exporting or copying.\r\n\r\n# Note:\r\n# Naturally, a valid cube name (pCube) is mandatory otherwise the process will abort.\r\n# If the MDX does not compile or produces an empty set the process will error.\r\n# pTemp: This parameter will control whether to make the view temporary (value 1) or if the\r\n# view will be permanently retained (value 0).\r\n#EndRegion @DOC\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\n\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSubset = cThisProcName | '_' | cTimeStamp | '_' | cRandomInt;\r\ncTempFile = GetProcessErrorFileDirectory | cTempSubset | '.csv';\r\nsMessage = \t'';\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pCube:%pCube%, pView:%pView%, pMDXExpr:%pMDXExpr%, pTemp:%pTemp%.' ; \r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pCube\": null,\r\n \"pMDXExpr\": null,\r\n \"pView\": null,\r\n \"pLogOutput\": 0,\r\n \"pStrictErrorHandling\": 0,\r\n \"pTemp\": 1\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pCube\": '|StringToJson ( pCube )|',\r\n \"pMDXExpr\": '|StringToJson ( pMDXExpr )|',\r\n \"pView\": '|StringToJson ( pView )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|',\r\n \"pTemp\": '|NumberToString( pTemp )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npCube = JsonToString( JsonGet( pJson, 'pCube' ) );\r\npMDXExpr = JsonToString( JsonGet( pJson, 'pMDXExpr' ) );\r\npView = JsonToString( JsonGet( pJson, 'pView' ) );\r\n# Numeric Parameters\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\npTemp = StringToNumber( JsonToString( JsonGet( pJson, 'pTemp' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\nsMDXExpr = TRIM( pMDXExpr );\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\n# Validate Cube\r\nIf( Trim( pCube ) @= '' );\r\n sMessage = 'No cube specified.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( CubeExists( pCube ) = 0 );\r\n sMessage = Expand('Cube %pCube% does not exist') ;\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate View\r\nIf( Trim( pView ) @= '' );\r\n sMessage = 'No view specified';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate MDX\r\nIf( Trim( sMDXExpr ) @= '' );\r\n sMessage = 'No MDX expression specified';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate MDX. Checking Cube name mentioned in MDX\r\nIf( SCAN ( pCube , sMDXExpr ) = 0 );\r\n sMessage = 'No Cube Name mentioned in MDX. Not a valid MDX expression';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n## Validate pTemp\r\nIF( pTemp<> 0 & pTemp<> 1 );\r\n nErrors = 1;\r\n sMessage = 'Invalid value for pTemp' | NumberToString( pTemp ) | '. Valid values are 0 and 1';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### Create View ###\r\nIf( ViewExists( pCube , pView ) = 1 );\r\n ViewDestroy( pCube , pView );\r\nEndIf;\r\n\r\nViewCreatebyMDX ( pCube , pView , sMDXExpr, pTemp ) ; \r\n\r\n### End Prolog ###", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully created view %pView% in cube %pCube%.' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n### End Epilog ###", @@ -10,27 +10,15 @@ "Type": "None" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pCube", - "Prompt": "REQUIRED: Cube Name", + "Prompt": "REQUIRED: Cube name", "Value": "", "Type": "String" }, { "Name": "pView", - "Prompt": "REQUIRED: View Name", + "Prompt": "REQUIRED: Name of the view", "Value": "", "Type": "String" }, @@ -42,9 +30,27 @@ }, { "Name": "pTemp", - "Prompt": "OPTIONAL: Make View Temporary (1=Temporary)", + "Prompt": "OPTIONAL: Delete/create temporary objects (0 = Do not delete, 1 = Delete, 2 = if view and subsets are created, keep only subsets)", "Value": 1, "Type": "Numeric" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [], diff --git a/bedrock_processes_json/}bedrock.cube.view.create.json b/bedrock_processes_json/}bedrock.cube.view.create.json index c8b695a..2d1000b 100644 --- a/bedrock_processes_json/}bedrock.cube.view.create.json +++ b/bedrock_processes_json/}bedrock.cube.view.create.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.cube.view.create", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.cube.view.create', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pCube', '', 'pView', '', 'pFilter', '',\r\n \t'pSuppressZero', 1, 'pSuppressConsol', 1, 'pSuppressRules', 1, 'pSuppressConsolStrings', 1, 'pIncludeDescendants',0,\r\n \t'pDimDelim', '&', 'pEleStartDelim', '\u00a6', 'pEleDelim', '+',\r\n \t'pTemp', 1,'pSandbox', pSandbox,'pSubN', 0\r\n );\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***s\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock Ver 4.0.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process creates a view that can be used for exporting, copying or zeroing out numbers.\r\n\r\n# Use case: Intended for development/prototyping or production.\r\n# 1/ Create a view to zero out data.\r\n# 2/ Create a view to use as a source for exporting or copying.\r\n\r\n# Note:\r\n# Naturally, a valid cube name (pCube) is mandatory otherwise the process will abort.\r\n# The pFilter parameter contains the dimenson and elements to be used for filtering:\r\n# - The format of the pFilter parameter is as follows delimiters of :, & and +: Dim1: Elem1 + Elem2 & Dim2: Elem3 + Elem4.\r\n# - The dimension parameters do not need to be given in the index order of dimensions in the cube.\r\n# - The dimension name is specified as the first member of the delimited string of elements.\r\n# - If consols are skipped the N level children of any consolidated filter elements will be used.\r\n# - Spaces are ignored so use them to make your filter more readable.\r\n# - pTemp: This parameter will control whether to make the view temporary (value 1) or if the\r\n# view will be permanently retained (value 0).\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable ('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nStringGlobalVariable('sBedrockViewCreateParsedFilter');\r\nsProcessReturnCode = '';\r\nnProcessReturnCode = 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSubset = cThisProcName | '_' | cTimeStamp | '_' | cRandomInt;\r\ncTempFile = GetProcessErrorFileDirectory | cTempSubset | '.csv';\r\nsMessage = '';\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncMsgInfoLevel = 'INFO';\r\ncMsgInfoContent = '%cThisProcName% : %sMessage% : %cUserName%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pCube:%pCube%, pView:%pView%, pFilter:%pFilter%, pSuppressZero:%pSuppressZero%, pSuppressConsol:%pSuppressConsol%, pSuppressRules:%pSuppressRules%, pDimDelim:%pDimDelim%, pEleStartDelim:%pEleStartDelim%, pEleDelim:%pEleDelim%, pTemp:%pTemp%, pSandbox:%pSandbox%, pSuppressConsolStrings:%pSuppressConsolStrings% pIncludeDescendants %pIncludeDescendants%.' ; \r\n\r\n\r\nsSubset = pView;\r\nsDelimDim = TRIM(pDimDelim);\r\nsElementStartDelim= TRIM(pEleStartDelim);\r\nsDelimElem = TRIM(pEleDelim);\r\n\r\n## LogOutput parameters\r\nIF ( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\nnErrors = 0;\r\n\r\n### Validate Parameters ###\r\n\r\n## Default filter delimiters\r\nIf( pDimDelim @= '' );\r\n pDimDelim = '&';\r\nEndIf;\r\nIf( pEleStartDelim@= '' );\r\n pEleStartDelim= '\u00a6';\r\nEndIf;\r\nIf( pEleDelim @= '' );\r\n pEleDelim = '+';\r\nEndIf;\r\n\r\n# If specified cube does not exist then terminate process\r\nIf( Trim( pCube ) @= '' );\r\n sMessage = 'A cube name must be provided.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( CubeExists( pCube ) = 0 );\r\n sMessage = 'Cube: ' | pCube | ' does not exist.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n## Validate the View parameter\r\nIf( Trim( pView ) @= '' );\r\n sMessage = 'A view name must be provided.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Check the delimiters\r\nIf( sDelimDim @= sElementStartDelim % sDelimDim @= sDelimElem % sElementStartDelim @= sDelimElem );\r\n sMessage = 'The delimiters cannot be the same';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n## Validate pTemp\r\nIF( pTemp<> 0 & pTemp<> 1 );\r\n nErrors = 1;\r\n sMessage = 'Invalid value for pTemp' | NumberToString( pTemp ) | '. Valid values are 0 and 1';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### If errors occurred terminate process with a major error status ###\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n# Validate Sandbox\r\nIf( TRIM( pSandbox ) @<> '' );\r\n If( ServerSandboxExists( pSandbox ) = 0 );\r\n SetUseActiveSandboxProperty( 0 );\r\n nErrors = nErrors + 1;\r\n sMessage = Expand('Sandbox %pSandbox% is invalid for the current user.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n Else;\r\n ServerActiveSandboxSet( pSandbox );\r\n SetUseActiveSandboxProperty( 1 );\r\n EndIf;\r\nElse;\r\n SetUseActiveSandboxProperty( 0 );\r\nEndIf;\r\n \r\n# Reset all of the subsets that may be attached to the view in the case that dimensions not in the filter\r\nIf( ViewExists( pCube, pView ) = 1 );\r\n ### Reset View ###\r\n sMessage = 'Resetting view ' | pView | ' on cube ' | pCube;\r\n IF ( pLogoutput = 1 );\r\n LogOutput( cMsgInfoLevel, Expand( cMsgInfoContent ) );\r\n EndIf;\r\n nCount = 1;\r\n While( TabDim( pCube, nCount ) @<> '' );\r\n sCubeDimName = TabDim( pCube, nCount );\r\n # Subset is the same name as the view (no way to test if subset assigned, assume it is if same name)\r\n If( SubsetExists( sCubeDimName, sSubset ) = 1 );\r\n # Add all elements\r\n If( SubsetIsAllSet(sCubeDimName, sSubset, 1) <> 1 );\r\n sMessage = Expand('Unable to add all elements on subset %sSubset% in dimension %sCubeDimName%');\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n EndIf;\r\n EndIf;\r\n nCount = nCount + 1;\r\n End;\r\nElse;\r\n ### Create View ###\r\n sMessage = Expand('Creating view %pView% in cube %pCube%');\r\n IF ( pLogoutput = 1 );\r\n LogOutput( cMsgInfoLevel, Expand( cMsgInfoContent ) );\r\n EndIf;\r\n ViewCreate( pCube, pView, pTemp );\r\nEndIf;\r\n\r\nViewExtractSkipCalcsSet( pCube, pView, pSuppressConsol );\r\nViewExtractSkipZeroesSet( pCube, pView, pSuppressZero );\r\nViewExtractSkipRuleValuesSet( pCube, pView, pSuppressRules );\r\n# Fix of issue #141, https://github.com/cubewise-code/bedrock/issues/141\r\nIf( pSuppressConsolStrings <> -1 );\r\n ViewExtractSkipConsolidatedStringsSet( pCube, pView, pSuppressConsolStrings );\r\nEndIf;\r\n\r\n### Split filter and create subsets ###\r\nsFilter = TRIM( pFilter );\r\nsParsedFilter = '';\r\nnChar = 1;\r\nnCharCount = LONG( sFilter );\r\nsWord = '';\r\nsLastDelim = '';\r\nnIndex = 1;\r\n# Add a trailing element delimiter so that the last element is picked up\r\nIf( nCharCount > 0 );\r\n sFilter = sFilter | sDelimElem;\r\n nCharCount = nCharCount + LONG(sDelimElem);\r\nEndIf;\r\n\r\nWHILE (nChar <= nCharCount);\r\n sChar = SUBST( sFilter, nChar, 1);\r\n\r\n # Used for delimiters, required for multiple character delimiters\r\n sDelim = '';\r\n nAddExtra = 0;\r\n\r\n # Ignore spaces\r\n IF (TRIM(sChar) @<> '' );\r\n\r\n ### Dimension Name ###\r\n\r\n # If the delimiter is more than 1 character peek ahead the same amount\r\n # Ignore the first character\r\n sDelim = sChar;\r\n nCount = LONG(sElementStartDelim) - 1;\r\n If( nCount > 0 & nChar + nCount <= nCharCount );\r\n # Add the extra characters\r\n sDelim = sDelim | SUBST( sFilter, nChar + 1, nCount);\r\n # Move to the end of the delimter\r\n nAddExtra = nCount;\r\n EndIf;\r\n\r\n If( sDelim @= sElementStartDelim );\r\n\r\n sChar = sDelim;\r\n\r\n If( sLastDelim @<> '' & sLastDelim @<> sDelimDim );\r\n sMessage = 'The name of a dimension must follow a dimension delimiter (' | sDelimDim | ')';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n EndIf;\r\n\r\n sDimension = sWord;\r\n nOneDimEleAdded = 0;\r\n \r\n If( DimensionExists( sDimension ) = 0 );\r\n # The dimension does not exist in the model. Cancel process\r\n sMessage = 'Dimension: ' | sDimension | ' does not exist';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n EndIf;\r\n\r\n ### Determine the dimension is a member of the cube ###\r\n nCount = 1;\r\n nDimensionIndex = 0;\r\n While( TabDim( pCube, nCount ) @<> '' );\r\n sCubeDimName = TabDim( pCube, nCount );\r\n If( sDimension @= sCubeDimName );\r\n nDimensionIndex = nCount;\r\n EndIf;\r\n nCount = nCount + 1;\r\n End;\r\n\r\n If( nDimensionIndex = 0 );\r\n # The dimension does not exist in the cube. Cancel process\r\n sMessage = 'Dimension: ' | sDimension | ' is not a member of: '| pCube | 'cube.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n EndIf;\r\n\r\n # Create the subset\r\n If( SubsetExists( sDimension, sSubset ) = 1 );\r\n SubsetDeleteAllElements( sDimension, sSubset );\r\n Else;\r\n SubsetCreate( sDimension, sSubset, pTemp ); \r\n EndIf;\r\n\r\n # Attach to the view\r\n ViewSubsetAssign( pCube, pView, sDimension, sSubset );\r\n \r\n #Add to the Parsed filter\r\n IF(sParsedFilter@='');\r\n sParsedFilter=sDimension; \r\n Else;\r\n sParsedFilter=sParsedFilter|sDelimDim|sDimension;\r\n Endif; \r\n\r\n nIndex = 1;\r\n sLastDelim = sChar;\r\n # Clear the word\r\n sWord = '';\r\n Else;\r\n\r\n # Reset extra chars\r\n nAddExtra = 0;\r\n\r\n ### Check both both dim delimiter and element delimiter ###\r\n nIsDelimiter = 0;\r\n\r\n ## Check dimension delimiter first\r\n # If the delimiter is more than 1 character peek ahead the same amount\r\n # Ignore the first character\r\n sDelim = sChar;\r\n nCount = LONG(sDelimDim) - 1;\r\n If( nCount > 0 & nChar + nCount <= nCharCount );\r\n # Add the extra characters\r\n sDelim = sDelim | SUBST( sFilter, nChar + 1, nCount);\r\n # Move to the end of the delimter\r\n nAddExtra = nCount;\r\n EndIf;\r\n\r\n If( sDelim @= sDelimDim );\r\n nIsDelimiter = 1;\r\n sChar = sDelim;\r\n Else;\r\n # Reset extra chars\r\n nAddExtra = 0;\r\n\r\n ## Check element delimiter\r\n\r\n # If the delimiter is more than 1 character peek ahead the same amount\r\n # Ignore the first character\r\n sDelim = sChar;\r\n nCount = LONG(sDelimElem) - 1;\r\n If( nCount > 0 & nChar + nCount <= nCharCount );\r\n # Add the extra characters\r\n sDelim = sDelim | SUBST( sFilter, nChar + 1, nCount);\r\n # Move to the end of the delimter\r\n nAddExtra = nCount;\r\n EndIf;\r\n\r\n If( sDelim @= sDelimElem );\r\n nIsDelimiter = 1;\r\n sChar = sDelim;\r\n Else;\r\n # Reset extra chars\r\n nAddExtra = 0;\r\n EndIf;\r\n\r\n EndIf;\r\n\r\n If ( nIsDelimiter = 1 );\r\n\r\n If( sLastDelim @= '' % sLastDelim @= sDelimDim );\r\n sMessage = 'An element delimiter must follow a dimension name: ' | sChar | ' (' | NumberToString(nChar) | ')';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n #ProcessError();\r\n EndIf;\r\n\r\n sElement = sWord;\r\n\r\n If( DIMIX( sDimension, sElement ) = 0 );\r\n # The element does not exist in the dimension. Cancel process\r\n sMessage = 'Element: ' | sElement | ' in dimension ' | sDimension | ' does not exist';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n #ProcessError();\r\n EndIf;\r\n \r\n sElement = DimensionElementPrincipalName(sDimension,sElement);\r\n\r\n If ( (pSuppressConsol = 1 % pIncludeDescendants=1) & DTYPE( sDimension, sElement) @= 'C' );\r\n # Add all N level elements to the subset\r\n # Loop through all elements and check if it is an ancestor\r\n sMessage = 'Element ' | sElement | ' is consolidated' ;\r\n IF ( pLogoutput = 1 );\r\n LogOutput( cMsgInfoLevel, Expand( cMsgInfoContent ) );\r\n EndIf;\r\n nElCount = DIMSIZ ( sDimension );\r\n n = 1;\r\n WHILE ( n <= nElCount );\r\n sEl = DIMNM( sDimension, n );\r\n If( ElIsAnc(sDimension, sElement, sEL) = 1 );\r\n If( pSuppressConsolStrings = 0 );\r\n SubsetElementInsert(sDimension, sSubset, sEl, 0);\r\n ElseIf( DType(sDimension, sEl) @<> 'C' );\r\n SubsetElementInsert(sDimension, sSubset, sEl, 0);\r\n EndIf;\r\n EndIf;\r\n n = n + 1;\r\n END;\r\n \r\n # Add the consolidated element to the subset as well to export strings, if necessary\r\n If ( pSuppressConsolStrings = 0 );\r\n SubsetElementInsert( sDimension, sSubset, sElement, 0 );\r\n EndIf;\r\n\r\n Else;\r\n # Add the element to the subset\r\n SubsetElementInsert( sDimension, sSubset, sElement, 0 );\r\n EndIf;\r\n \r\n #Add to the Parsed filter\r\n If( nOneDimEleAdded = 0 );\r\n sParsedFilter=sParsedFilter|pEleStartDelim|sElement;\r\n nOneDimEleAdded = nOneDimEleAdded + 1;\r\n Else;\r\n sParsedFilter=sParsedFilter|sDelimElem|sElement;\r\n EndIf;\r\n\r\n nIndex = nIndex + 1;\r\n sLastDelim = sChar;\r\n\r\n # Clear the word\r\n sWord = '';\r\n Else;\r\n sWord = sWord | sChar;\r\n EndIf;\r\n\r\n EndIf;\r\n\r\n EndIf;\r\n\r\n nChar = nChar + nAddExtra + 1;\r\n\r\nEND;\r\nsBedrockViewCreateParsedFilter = sParsedFilter;\r\n\r\n# creating N level subset for all dim not included in pFilter \r\n# useful when suppress consolidation is not on\r\nIf(pSubN = 1);\r\n \r\n nCountDimC = 1;\r\n While( TabDim( pCube, nCountDimC ) @<> '' );\r\n sDimC = TabDim( pCube, nCountDimC );\r\n sDimString = lower(sDimC);\r\n \r\n # filters created by other bedrock processes skip spaces from dim names and between separators\r\n While(Scan(' ',sDimString)>0);\r\n sDimString = subst(sDimString, 1, Scan(' ',sDimString)-1)|subst(sDimString,Scan(' ',sDimString)+1,long(sDimString));\r\n End; \r\n sTFilter = lower(sFilter);\r\n While(Scan(' ',sTFilter)>0);\r\n sTFilter = subst(sTFilter, 1, Scan(' ',sTFilter)-1)|subst(sTFilter,Scan(' ',sTFilter)+1,long(sTFilter));\r\n End;\r\n \r\n # to make sure that the name of the dim is not part of the name of another dim\r\n If(Scan(pDimDelim|sDimString|pEleStartDelim, sTFilter)=0 & Scan(sDimString|pEleStartDelim, sTFilter)<>1);\r\n sProc = '}bedrock.hier.sub.create';\r\n nRet = ExecuteProcess( sProc,\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pDim', sDimC,\r\n 'pHier', '',\r\n 'pSub', sSubset,\r\n 'pConsol', '',\r\n 'pAttr', '',\r\n 'pAttrValue', '',\r\n 'pLevelFrom', 0,\r\n 'pLevelTo', 0,\r\n 'pExclusions', '',\r\n 'pDelim', pEleDelim,\r\n 'pAddToSubset', 0,\r\n 'pAlias', '',\r\n 'pTemp', pTemp\r\n );\r\n \r\n IF(nRet <> 0);\r\n sMessage = 'Error creating the view from the filter.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n ENDIF;\r\n \r\n ViewSubsetAssign( pCube, pView, sDimC, sSubset );\r\n \r\n EndIf;\r\n \r\n nCountDimC = nCountDimC + 1;\r\n End;\r\n\r\n EndIf; \r\n### End Prolog ###", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.cube.view.create', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pCube', '', 'pView', '', 'pFilter', '',\r\n \t'pSuppressZero', 1, 'pSuppressConsol', 1, 'pSuppressRules', 1, 'pSuppressConsolStrings', 1, 'pIncludeDescendants',0,\r\n \t'pDimDelim', '&', 'pEleStartDelim', '\u00a6', 'pEleDelim', '+',\r\n \t'pTemp', 1,'pSandbox', pSandbox,'pSubN', 0\r\n );\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***s\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock Ver 4.0.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process creates a view that can be used for exporting, copying or zeroing out numbers.\r\n\r\n# Use case: Intended for development/prototyping or production.\r\n# 1/ Create a view to zero out data.\r\n# 2/ Create a view to use as a source for exporting or copying.\r\n\r\n# Note:\r\n# Naturally, a valid cube name (pCube) is mandatory otherwise the process will abort.\r\n# The pFilter parameter contains the dimenson and elements to be used for filtering:\r\n# - The format of the pFilter parameter is as follows delimiters of :, & and +: Dim1: Elem1 + Elem2 & Dim2: Elem3 + Elem4.\r\n# - The dimension parameters do not need to be given in the index order of dimensions in the cube.\r\n# - The dimension name is specified as the first member of the delimited string of elements.\r\n# - If consols are skipped the N level children of any consolidated filter elements will be used.\r\n# - Spaces are ignored so use them to make your filter more readable.\r\n# - pTemp: This parameter will control whether to make the view temporary (value 1) or if the\r\n# view will be permanently retained (value 0).\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable ('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nStringGlobalVariable('sBedrockViewCreateParsedFilter');\r\nsProcessReturnCode = '';\r\nnProcessReturnCode = 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSubset = cThisProcName | '_' | cTimeStamp | '_' | cRandomInt;\r\ncTempFile = GetProcessErrorFileDirectory | cTempSubset | '.csv';\r\nsMessage = '';\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncMsgInfoLevel = 'INFO';\r\ncMsgInfoContent = '%cThisProcName% : %sMessage% : %cUserName%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pCube:%pCube%, pView:%pView%, pFilter:%pFilter%, pSuppressZero:%pSuppressZero%, pSuppressConsol:%pSuppressConsol%, pSuppressRules:%pSuppressRules%, pDimDelim:%pDimDelim%, pEleStartDelim:%pEleStartDelim%, pEleDelim:%pEleDelim%, pTemp:%pTemp%, pSandbox:%pSandbox%, pSuppressConsolStrings:%pSuppressConsolStrings% pIncludeDescendants %pIncludeDescendants%.' ;\r\n\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pCube\": null,\r\n \"pDimDelim\": \"&\",\r\n \"pEleDelim\": \"+\",\r\n \"pEleStartDelim\": \"\u00a6\",\r\n \"pFilter\": \"\",\r\n \"pSandBox\": \"\",\r\n \"pView\": null,\r\n \"pIncludeDescendants\": 0,\r\n \"pLogOutput\": 0,\r\n \"pStrictErrorHandling\": 0,\r\n \"pSubN\": 0,\r\n \"pSuppressConsol\": 1,\r\n \"pSuppressConsolStrings\": 1,\r\n \"pSuppressRules\": 1,\r\n \"pSuppressZero\": 1,\r\n \"pTemp\": 1\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pCube\": '|StringToJson ( pCube )|',\r\n \"pDimDelim\": '|StringToJson ( pDimDelim )|',\r\n \"pEleDelim\": '|StringToJson ( pEleDelim )|',\r\n \"pEleStartDelim\": '|StringToJson ( pEleStartDelim )|',\r\n \"pFilter\": '|StringToJson ( pFilter )|',\r\n \"pSandBox\": '|StringToJson ( pSandBox )|',\r\n \"pView\": '|StringToJson ( pView )|',\r\n \"pIncludeDescendants\": '|NumberToString( pIncludeDescendants )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|',\r\n \"pSubN\": '|NumberToString( pSubN )|',\r\n \"pSuppressConsol\": '|NumberToString( pSuppressConsol )|',\r\n \"pSuppressConsolStrings\": '|NumberToString( pSuppressConsolStrings )|',\r\n \"pSuppressRules\": '|NumberToString( pSuppressRules )|',\r\n \"pSuppressZero\": '|NumberToString( pSuppressZero )|',\r\n \"pTemp\": '|NumberToString( pTemp )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npCube = JsonToString( JsonGet( pJson, 'pCube' ) );\r\npDimDelim = JsonToString( JsonGet( pJson, 'pDimDelim' ) );\r\npEleDelim = JsonToString( JsonGet( pJson, 'pEleDelim' ) );\r\npEleStartDelim = JsonToString( JsonGet( pJson, 'pEleStartDelim' ) );\r\npFilter = JsonToString( JsonGet( pJson, 'pFilter' ) );\r\npSandBox = JsonToString( JsonGet( pJson, 'pSandBox' ) );\r\npView = JsonToString( JsonGet( pJson, 'pView' ) );\r\n# Numeric Parameters\r\npIncludeDescendants = StringToNumber( JsonToString( JsonGet( pJson, 'pIncludeDescendants' ) ) );\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\npSubN = StringToNumber( JsonToString( JsonGet( pJson, 'pSubN' ) ) );\r\npSuppressConsol = StringToNumber( JsonToString( JsonGet( pJson, 'pSuppressConsol' ) ) );\r\npSuppressConsolStrings = StringToNumber( JsonToString( JsonGet( pJson, 'pSuppressConsolStrings' ) ) );\r\npSuppressRules = StringToNumber( JsonToString( JsonGet( pJson, 'pSuppressRules' ) ) );\r\npSuppressZero = StringToNumber( JsonToString( JsonGet( pJson, 'pSuppressZero' ) ) );\r\npTemp = StringToNumber( JsonToString( JsonGet( pJson, 'pTemp' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\nsSubset = pView;\r\nsDelimDim = TRIM(pDimDelim);\r\nsElementStartDelim= TRIM(pEleStartDelim);\r\nsDelimElem = TRIM(pEleDelim);\r\n\r\n## LogOutput parameters\r\nIF ( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\nnErrors = 0;\r\n\r\n### Validate Parameters ###\r\n\r\n## Default filter delimiters\r\nIf( pDimDelim @= '' );\r\n pDimDelim = '&';\r\nEndIf;\r\nIf( pEleStartDelim@= '' );\r\n pEleStartDelim= '\u00a6';\r\nEndIf;\r\nIf( pEleDelim @= '' );\r\n pEleDelim = '+';\r\nEndIf;\r\n\r\n# If specified cube does not exist then terminate process\r\nIf( Trim( pCube ) @= '' );\r\n sMessage = 'A cube name must be provided.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( CubeExists( pCube ) = 0 );\r\n sMessage = 'Cube: ' | pCube | ' does not exist.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n## Validate the View parameter\r\nIf( Trim( pView ) @= '' );\r\n sMessage = 'A view name must be provided.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Check the delimiters\r\nIf( sDelimDim @= sElementStartDelim % sDelimDim @= sDelimElem % sElementStartDelim @= sDelimElem );\r\n sMessage = 'The delimiters cannot be the same';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n## Validate pTemp\r\nIF( pTemp<> 0 & pTemp<> 1 );\r\n nErrors = 1;\r\n sMessage = 'Invalid value for pTemp' | NumberToString( pTemp ) | '. Valid values are 0 and 1';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### If errors occurred terminate process with a major error status ###\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n# Validate Sandbox\r\nIf( TRIM( pSandbox ) @<> '' );\r\n If( ServerSandboxExists( pSandbox ) = 0 );\r\n SetUseActiveSandboxProperty( 0 );\r\n nErrors = nErrors + 1;\r\n sMessage = Expand('Sandbox %pSandbox% is invalid for the current user.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n Else;\r\n ServerActiveSandboxSet( pSandbox );\r\n SetUseActiveSandboxProperty( 1 );\r\n EndIf;\r\nElse;\r\n SetUseActiveSandboxProperty( 0 );\r\nEndIf;\r\n \r\n# Reset all of the subsets that may be attached to the view in the case that dimensions not in the filter\r\nIf( ViewExists( pCube, pView ) = 1 );\r\n ### Reset View ###\r\n sMessage = 'Resetting view ' | pView | ' on cube ' | pCube;\r\n IF ( pLogoutput = 1 );\r\n LogOutput( cMsgInfoLevel, Expand( cMsgInfoContent ) );\r\n EndIf;\r\n nCount = 1;\r\n While( TabDim( pCube, nCount ) @<> '' );\r\n sCubeDimName = TabDim( pCube, nCount );\r\n # Subset is the same name as the view (no way to test if subset assigned, assume it is if same name)\r\n If( SubsetExists( sCubeDimName, sSubset ) = 1 );\r\n # Add all elements\r\n If( SubsetIsAllSet(sCubeDimName, sSubset, 1) <> 1 );\r\n sMessage = Expand('Unable to add all elements on subset %sSubset% in dimension %sCubeDimName%');\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n EndIf;\r\n EndIf;\r\n nCount = nCount + 1;\r\n End;\r\nElse;\r\n ### Create View ###\r\n sMessage = Expand('Creating view %pView% in cube %pCube%');\r\n IF ( pLogoutput = 1 );\r\n LogOutput( cMsgInfoLevel, Expand( cMsgInfoContent ) );\r\n EndIf;\r\n ViewCreate( pCube, pView, pTemp );\r\nEndIf;\r\n\r\nViewExtractSkipCalcsSet( pCube, pView, pSuppressConsol );\r\nViewExtractSkipZeroesSet( pCube, pView, pSuppressZero );\r\nViewExtractSkipRuleValuesSet( pCube, pView, pSuppressRules );\r\n# Fix of issue #141, https://github.com/cubewise-code/bedrock/issues/141\r\nIf( pSuppressConsolStrings <> -1 );\r\n ViewExtractSkipConsolidatedStringsSet( pCube, pView, pSuppressConsolStrings );\r\nEndIf;\r\n\r\n### Split filter and create subsets ###\r\nsFilter = TRIM( pFilter );\r\nsParsedFilter = '';\r\nnChar = 1;\r\nnCharCount = LONG( sFilter );\r\nsWord = '';\r\nsLastDelim = '';\r\nnIndex = 1;\r\n# Add a trailing element delimiter so that the last element is picked up\r\nIf( nCharCount > 0 );\r\n sFilter = sFilter | sDelimElem;\r\n nCharCount = nCharCount + LONG(sDelimElem);\r\nEndIf;\r\n\r\nWHILE (nChar <= nCharCount);\r\n sChar = SUBST( sFilter, nChar, 1);\r\n\r\n # Used for delimiters, required for multiple character delimiters\r\n sDelim = '';\r\n nAddExtra = 0;\r\n\r\n # Ignore spaces\r\n IF (TRIM(sChar) @<> '' );\r\n\r\n ### Dimension Name ###\r\n\r\n # If the delimiter is more than 1 character peek ahead the same amount\r\n # Ignore the first character\r\n sDelim = sChar;\r\n nCount = LONG(sElementStartDelim) - 1;\r\n If( nCount > 0 & nChar + nCount <= nCharCount );\r\n # Add the extra characters\r\n sDelim = sDelim | SUBST( sFilter, nChar + 1, nCount);\r\n # Move to the end of the delimter\r\n nAddExtra = nCount;\r\n EndIf;\r\n\r\n If( sDelim @= sElementStartDelim );\r\n\r\n sChar = sDelim;\r\n\r\n If( sLastDelim @<> '' & sLastDelim @<> sDelimDim );\r\n sMessage = 'The name of a dimension must follow a dimension delimiter (' | sDelimDim | ')';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n EndIf;\r\n\r\n sDimension = sWord;\r\n nOneDimEleAdded = 0;\r\n \r\n If( DimensionExists( sDimension ) = 0 );\r\n # The dimension does not exist in the model. Cancel process\r\n sMessage = 'Dimension: ' | sDimension | ' does not exist';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n EndIf;\r\n\r\n ### Determine the dimension is a member of the cube ###\r\n nCount = 1;\r\n nDimensionIndex = 0;\r\n While( TabDim( pCube, nCount ) @<> '' );\r\n sCubeDimName = TabDim( pCube, nCount );\r\n If( sDimension @= sCubeDimName );\r\n nDimensionIndex = nCount;\r\n EndIf;\r\n nCount = nCount + 1;\r\n End;\r\n\r\n If( nDimensionIndex = 0 );\r\n # The dimension does not exist in the cube. Cancel process\r\n sMessage = 'Dimension: ' | sDimension | ' is not a member of: '| pCube | 'cube.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n EndIf;\r\n\r\n # Create the subset\r\n If( SubsetExists( sDimension, sSubset ) = 1 );\r\n SubsetDeleteAllElements( sDimension, sSubset );\r\n Else;\r\n SubsetCreate( sDimension, sSubset, pTemp ); \r\n EndIf;\r\n\r\n # Attach to the view\r\n ViewSubsetAssign( pCube, pView, sDimension, sSubset );\r\n \r\n #Add to the Parsed filter\r\n IF(sParsedFilter@='');\r\n sParsedFilter=sDimension; \r\n Else;\r\n sParsedFilter=sParsedFilter|sDelimDim|sDimension;\r\n Endif; \r\n\r\n nIndex = 1;\r\n sLastDelim = sChar;\r\n # Clear the word\r\n sWord = '';\r\n Else;\r\n\r\n # Reset extra chars\r\n nAddExtra = 0;\r\n\r\n ### Check both both dim delimiter and element delimiter ###\r\n nIsDelimiter = 0;\r\n\r\n ## Check dimension delimiter first\r\n # If the delimiter is more than 1 character peek ahead the same amount\r\n # Ignore the first character\r\n sDelim = sChar;\r\n nCount = LONG(sDelimDim) - 1;\r\n If( nCount > 0 & nChar + nCount <= nCharCount );\r\n # Add the extra characters\r\n sDelim = sDelim | SUBST( sFilter, nChar + 1, nCount);\r\n # Move to the end of the delimter\r\n nAddExtra = nCount;\r\n EndIf;\r\n\r\n If( sDelim @= sDelimDim );\r\n nIsDelimiter = 1;\r\n sChar = sDelim;\r\n Else;\r\n # Reset extra chars\r\n nAddExtra = 0;\r\n\r\n ## Check element delimiter\r\n\r\n # If the delimiter is more than 1 character peek ahead the same amount\r\n # Ignore the first character\r\n sDelim = sChar;\r\n nCount = LONG(sDelimElem) - 1;\r\n If( nCount > 0 & nChar + nCount <= nCharCount );\r\n # Add the extra characters\r\n sDelim = sDelim | SUBST( sFilter, nChar + 1, nCount);\r\n # Move to the end of the delimter\r\n nAddExtra = nCount;\r\n EndIf;\r\n\r\n If( sDelim @= sDelimElem );\r\n nIsDelimiter = 1;\r\n sChar = sDelim;\r\n Else;\r\n # Reset extra chars\r\n nAddExtra = 0;\r\n EndIf;\r\n\r\n EndIf;\r\n\r\n If ( nIsDelimiter = 1 );\r\n\r\n If( sLastDelim @= '' % sLastDelim @= sDelimDim );\r\n sMessage = 'An element delimiter must follow a dimension name: ' | sChar | ' (' | NumberToString(nChar) | ')';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n #ProcessError();\r\n EndIf;\r\n\r\n sElement = sWord;\r\n\r\n If( DIMIX( sDimension, sElement ) = 0 );\r\n # The element does not exist in the dimension. Cancel process\r\n sMessage = 'Element: ' | sElement | ' in dimension ' | sDimension | ' does not exist';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n #ProcessError();\r\n EndIf;\r\n \r\n sElement = DimensionElementPrincipalName(sDimension,sElement);\r\n\r\n If ( (pSuppressConsol = 1 % pIncludeDescendants=1) & DTYPE( sDimension, sElement) @= 'C' );\r\n # Add all N level elements to the subset\r\n # Loop through all elements and check if it is an ancestor\r\n sMessage = 'Element ' | sElement | ' is consolidated' ;\r\n IF ( pLogoutput = 1 );\r\n LogOutput( cMsgInfoLevel, Expand( cMsgInfoContent ) );\r\n EndIf;\r\n nElCount = DIMSIZ ( sDimension );\r\n n = 1;\r\n WHILE ( n <= nElCount );\r\n sEl = DIMNM( sDimension, n );\r\n If( ElIsAnc(sDimension, sElement, sEL) = 1 );\r\n If( pSuppressConsolStrings = 0 );\r\n SubsetElementInsert(sDimension, sSubset, sEl, 0);\r\n ElseIf( DType(sDimension, sEl) @<> 'C' );\r\n SubsetElementInsert(sDimension, sSubset, sEl, 0);\r\n EndIf;\r\n EndIf;\r\n n = n + 1;\r\n END;\r\n \r\n # Add the consolidated element to the subset as well to export strings, if necessary\r\n If ( pSuppressConsolStrings = 0 );\r\n SubsetElementInsert( sDimension, sSubset, sElement, 0 );\r\n EndIf;\r\n\r\n Else;\r\n # Add the element to the subset\r\n SubsetElementInsert( sDimension, sSubset, sElement, 0 );\r\n EndIf;\r\n \r\n #Add to the Parsed filter\r\n If( nOneDimEleAdded = 0 );\r\n sParsedFilter=sParsedFilter|pEleStartDelim|sElement;\r\n nOneDimEleAdded = nOneDimEleAdded + 1;\r\n Else;\r\n sParsedFilter=sParsedFilter|sDelimElem|sElement;\r\n EndIf;\r\n\r\n nIndex = nIndex + 1;\r\n sLastDelim = sChar;\r\n\r\n # Clear the word\r\n sWord = '';\r\n Else;\r\n sWord = sWord | sChar;\r\n EndIf;\r\n\r\n EndIf;\r\n\r\n EndIf;\r\n\r\n nChar = nChar + nAddExtra + 1;\r\n\r\nEND;\r\nsBedrockViewCreateParsedFilter = sParsedFilter;\r\n\r\n# creating N level subset for all dim not included in pFilter \r\n# useful when suppress consolidation is not on\r\nIf(pSubN = 1);\r\n \r\n nCountDimC = 1;\r\n While( TabDim( pCube, nCountDimC ) @<> '' );\r\n sDimC = TabDim( pCube, nCountDimC );\r\n sDimString = lower(sDimC);\r\n \r\n # filters created by other bedrock processes skip spaces from dim names and between separators\r\n While(Scan(' ',sDimString)>0);\r\n sDimString = subst(sDimString, 1, Scan(' ',sDimString)-1)|subst(sDimString,Scan(' ',sDimString)+1,long(sDimString));\r\n End; \r\n sTFilter = lower(sFilter);\r\n While(Scan(' ',sTFilter)>0);\r\n sTFilter = subst(sTFilter, 1, Scan(' ',sTFilter)-1)|subst(sTFilter,Scan(' ',sTFilter)+1,long(sTFilter));\r\n End;\r\n \r\n # to make sure that the name of the dim is not part of the name of another dim\r\n If(Scan(pDimDelim|sDimString|pEleStartDelim, sTFilter)=0 & Scan(sDimString|pEleStartDelim, sTFilter)<>1);\r\n sProc = '}bedrock.hier.sub.create';\r\n nRet = ExecuteProcess( sProc,\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pDim', sDimC,\r\n 'pHier', '',\r\n 'pSub', sSubset,\r\n 'pConsol', '',\r\n 'pAttr', '',\r\n 'pAttrValue', '',\r\n 'pLevelFrom', 0,\r\n 'pLevelTo', 0,\r\n 'pExclusions', '',\r\n 'pDelim', pEleDelim,\r\n 'pAddToSubset', 0,\r\n 'pAlias', '',\r\n 'pTemp', pTemp\r\n );\r\n \r\n IF(nRet <> 0);\r\n sMessage = 'Error creating the view from the filter.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n ENDIF;\r\n \r\n ViewSubsetAssign( pCube, pView, sDimC, sSubset );\r\n \r\n EndIf;\r\n \r\n nCountDimC = nCountDimC + 1;\r\n End;\r\n\r\n EndIf; \r\n### End Prolog ###", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n### Return code & final error message handling ###\r\nIf( nErrors <> 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( 'ERROR' , Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nElse; \r\n\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully created View %pView% in Cube %pCube%.' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n \r\n### End Epilog ###", @@ -10,101 +10,107 @@ "Type": "None" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pCube", - "Prompt": "REQUIRED: Cube Name", + "Prompt": "REQUIRED: Cube name", "Value": "", "Type": "String" }, { "Name": "pView", - "Prompt": "REQUIRED: Name of the View", + "Prompt": "REQUIRED: Name of the view", "Value": "", "Type": "String" }, { "Name": "pFilter", - "Prompt": "OPTIONAL: Filter: Year\u00a6 2006 + 2007 & Scenario\u00a6 Actual + Budget & Organization\u00a6 North America Operations", + "Prompt": "OPTIONAL: Filter on cube in format: 'dim_one\u00a6 el_one + el_two & dim_two\u00a6 el_one + el_two'", "Value": "", "Type": "String" }, { "Name": "pSuppressZero", - "Prompt": "REQUIRED: Suppress Zero Data (Skip = 1)", + "Prompt": "OPTIONAL: Suppress zeroes (Boolean. Default = 1)", "Value": 1, "Type": "Numeric" }, { "Name": "pSuppressConsol", - "Prompt": "REQUIRED: Suppress Consolidations (Skip = 1)", + "Prompt": "OPTIONAL: Suppress consolidated values (Boolean. Default = 1)", "Value": 1, "Type": "Numeric" }, { "Name": "pSuppressRules", - "Prompt": "REQUIRED: Suppress Rules (Skip = 1)", + "Prompt": "OPTIONAL: Suppress rules (Boolean. Default = 1)", "Value": 1, "Type": "Numeric" }, { "Name": "pSuppressConsolStrings", - "Prompt": "REQUIRED: Suppress Strings on Consolidations (Skip = 1, Include = 0) (Default [Skip] = -1 for backward compatibility)", - "Value": -1, + "Prompt": "OPTIONAL: Suppress consolidated string cells (Boolean. Default = 1)", + "Value": 1, "Type": "Numeric" }, { "Name": "pIncludeDescendants", - "Prompt": "OPTIONAL: Include all descendants when copying consolidated values", + "Prompt": "OPTIONAL: Include all descendants when source has consolidations (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { "Name": "pDimDelim", - "Prompt": "REQUIRED: Delimiter for start of Dimension/Element set", + "Prompt": "OPTIONAL: Delimiter for start of dimension/element set in filter parameters (Default = '&')", "Value": "&", "Type": "String" }, { "Name": "pEleStartDelim", - "Prompt": "REQUIRED: Delimiter for start of element list", + "Prompt": "OPTIONAL: Delimiter for start of element list in filter parameters (Default = '\u00a6')", "Value": "\u00a6", "Type": "String" }, { "Name": "pEleDelim", - "Prompt": "REQUIRED: Delimiter between elements", + "Prompt": "OPTIONAL: Delimiter between elements in filter parameters (Default = '+')", "Value": "+", "Type": "String" }, { "Name": "pTemp", - "Prompt": "OPTIONAL: Make View Temporary (1=Temporary)", + "Prompt": "OPTIONAL: Delete/create temporary objects (0 = Do not delete, 1 = Delete, 2 = if view and subsets are created, keep only subsets)", "Value": 1, "Type": "Numeric" }, { "Name": "pSandBox", - "Prompt": "OPTIONAL: To use sandbox not base data enter the sandbox name (invalid name will result in process error)", + "Prompt": "OPTIONAL: Use sandbox", "Value": "", "Type": "String" }, { "Name": "pSubN", - "Prompt": "OPTIONAL: Create N level subset for all dims not mentioned in pFilter", + "Prompt": "OPTIONAL: Create N level subset for all dims not specified (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [], diff --git a/bedrock_processes_json/}bedrock.cube.view.delete.json b/bedrock_processes_json/}bedrock.cube.view.delete.json index ba5ad16..0153cd0 100644 --- a/bedrock_processes_json/}bedrock.cube.view.delete.json +++ b/bedrock_processes_json/}bedrock.cube.view.delete.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.cube.view.delete", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.cube.view.delete', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n\t 'pCube', '', 'pView', '', 'pDelim', '&'\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock Ver 4.0.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process deletes public views.\r\n\r\n# Use case: Intended for development/prototyping or production.\r\n# 1/ After a view has been created to zero or as a data source it needs to be deleted.\r\n# 2/ Clean up public views after Go Live.\r\n\r\n# Note:\r\n# This process can work on a single cubes or multiple cubes.\r\n# This process can work on a single view or multiple views.\r\n# When specifying view names wildcards can be included by using the * character. \r\n# **Parameter pCube**.\r\n# - To specify which cubes to delete views from use the pCubes parameter.\r\n# - To delete views from a single cube only just specify that cube name e.g. Sales.\r\n# - To delete views from multiple cubes specify each cube name separated by a delimiter e.g. Sales&Inventory&Cashflow.\r\n# - To delete views from all cubes then set pCubes as *.\r\n# - If any invalid cubes are specified they will be skipped but the process will continue to process the other cubes.\r\n# **Parameter pView**.\r\n# - To specify which views to delete use the pViews parameter.\r\n# - This parameter must be specified, a blank value will cause the process to terminate.\r\n# - To delete a single view only just specify that view name e.g. SalesByProduct.\r\n# - To delete multiple views specify each view name separated by a delimiter e.g. SalesByProduct&SalesByManager&SalesByStore.\r\n# - When specifying view names wildcards are permitted and all views that match the wildcard search string will be deleted.\r\n# - The wildcard search string follows the same format as windows based file wildcards.\r\n# - To delete all views that \"start\" with a specific string use a trailing * e.g. Bedrock*.\r\n# - To delete all views that \"end\" in a specific string use a leading * e.g. *Bedrock.\r\n# - To delete all views that \"contain\" a specific string use leading and trailing *'s e.g. *Bedrock*.\r\n# - To delete a single specific view only don't use *'s at all e.g. Bedrock.\r\n# - To specify multiple search stings list them all separated by a delimiter e.g. Bedrock*;*Temp;*Test*.\r\n# - Specific view names and wildcard based names can both be used together e.g. SalesByProduct;Bedrock*.\r\n# **Parameter pDelim**.\r\n# - The delimiter can be used when specifying multiple cubes and/or multiple views.\r\n# - The default delimiter is &.\r\n# - Any delimiter can be used by specifying a value for pDelimiter.\r\n# - Choose a delimiter that won't be used in either the wildcard search strings or cube names.\r\n#EndRegion @DOC\r\n\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSubset = cThisProcName | '_' | cTimeStamp | '_' | cRandomInt;\r\ncTempFile = GetProcessErrorFileDirectory | cTempSubset | '.csv';\r\nsMessage = \t'';\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pCube:%pCube%, pView:%pView%, pDelim:%pDelim%.' ; \r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\nnErrors = 0;\r\ncDimension = '}Cubes';\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\n# Validate views\r\nIf( Trim( pView ) @= '' );\r\n sMessage = 'No views specified.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate delimiter\r\nIf( Trim( pDelim ) @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\n### Iterate through cubes ###\r\n\r\n# If no cube has been specified then process all cubes\r\nIf( Trim( pCube ) @= '' );\r\n sMessage = 'No cube specified.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors > 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n# Work through all cubes specified in pCube\r\nsCubes = pCube;\r\nnCubeDelimIndex = 1;\r\nsDelimiter = pDelim;\r\nsMdx = '';\r\nWhile( nCubeDelimIndex <> 0 );\r\n nCubeDelimIndex = Scan( sDelimiter, sCubes );\r\n If( nCubeDelimIndex = 0 );\r\n sCube = Trim( sCubes );\r\n Else;\r\n sCube = Trim( SubSt( sCubes, 1, nCubeDelimIndex - 1 ) );\r\n sCubes = Trim( SubSt( sCubes, nCubeDelimIndex + Long( sDelimiter ), Long( sCubes ) ) );\r\n EndIf;\r\n\r\n # Create subset of cubes using Wildcard to loop through cubes in pCube with wildcard\r\n sCubeExp = '\"'|sCube|'\"';\r\n sMdxPart = Expand('{TM1FILTERBYPATTERN( TM1SUBSETALL( [}Cubes] ), %sCubeExp% )}');\r\n IF( sMdx @= ''); \r\n sMdx = sMdxPart; \r\n ELSE;\r\n sMdx = sMdx | ' + ' | sMdxPart;\r\n ENDIF;\r\nEnd;\r\n \r\nIf( SubsetExists( '}Cubes' , cTempSubset ) = 1 );\r\n # If a delimited list of cube names includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( '}Cubes' , cTempSubset, sMDX );\r\nElse;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSubset, sMDX, '}Cubes' , 1 );\r\nEndIf;\r\n \r\n \r\n # Loop through cubess in subset created based on wildcard\r\n nCountCubes = SubsetGetSize( '}Cubes' , cTempSubset );\r\n While( nCountCubes >= 1 );\r\n sCurrentCube = SubsetGetElementName( '}Cubes' , cTempSubset, nCountCubes );\r\n # If a valid cube has been specified then delete specified views from it\r\n If( CubeExists( sCurrentCube ) = 1 );\r\n If( pLogOutput = 1 );\r\n LogOutput( 'INFO', Expand( 'Processing cube %sCurrentCube%.' ) );\r\n EndIf;\r\n # Work through all views specified in pViews\r\n sViews = pView;\r\n nViewDelimIndex = 1;\r\n sMdxView = '';\r\n \r\n While( nViewDelimIndex <> 0 );\r\n nViewDelimIndex = Scan( sDelimiter, sViews );\r\n If( nViewDelimIndex = 0 );\r\n sView = Trim( sViews );\r\n Else;\r\n sView = Trim( SubSt( sViews, 1, nViewDelimIndex - 1 ) );\r\n sViews = Trim( SubSt( sViews, nViewDelimIndex + Long( sDelimiter ), Long( sViews ) ) );\r\n EndIf;\r\n \r\n # Check if a wildcard has been used to specify the view name.\r\n # If it hasn't then just delete the view if it exists\r\n If( Scan( '*', sView ) = 0 );\r\n If( ViewExists( sCurrentCube, sView ) = 1 );\r\n If( pLogOutput = 1 );\r\n LogOutput( 'INFO', Expand( ' Destroying view %sView% in cube %sCurrentCube%.' ) );\r\n EndIf;\r\n ViewDestroy( sCurrentCube, sView );\r\n EndIf;\r\n # If it has then iterate through '}Views_CubeName' dimension\r\n Else;\r\n sDimViews = '}Views_' | sCurrentCube ;\r\n If( DimensionExists( sDimViews ) = 1 );\r\n # Create subset of views using Wildcard to loop through views in current cube\r\n sViewExp = '\"'|sView|'\"';\r\n sMdxViewPart = Expand('{TM1FILTERBYPATTERN( {TM1SUBSETALL([%sDimViews%])}, %sViewExp% )}');\r\n IF( sMdxView @= ''); \r\n sMdxview = sMdxViewPart; \r\n ELSE;\r\n sMdxView = sMdxView | ' + ' | sMdxViewPart;\r\n ENDIF;\r\n If( SubsetExists( sDimViews, cTempSubset ) = 1 );\r\n # If a delimited list of attr names includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( sDimViews, cTempSubset, sMdxView );\r\n Else;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSubset, sMdxView, sDimViews, 1 );\r\n EndIf;\r\n \r\n # Loop through subset of views created based on wildcard\r\n nCountView = SubsetGetSize( sDimViews, cTempSubset );\r\n While( nCountView >= 1 );\r\n sViewEle = SubsetGetElementName( sDimViews, cTempSubset, nCountView );\r\n # Validate attribute name in sDim\r\n If( ViewExists( sCurrentCube, sViewEle ) = 1 );\r\n If( pLogOutput = 1 );\r\n LogOutput( 'INFO', Expand( 'Destroying view %sViewEle% in cube %sCurrentCube%.' ) );\r\n EndIf;\r\n ViewDestroy( sCurrentCube, sViewEle );\r\n Endif;\r\n nCountView = nCountView - 1;\r\n End;\r\n EndIf;\r\n EndIf;\r\n \r\n End;\r\n \r\n # Cube does not exist\r\n Else;\r\n sMessage = Expand('Cube %sCurrentCube% does not exist.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n EndIf;\r\n \r\n nCountCubes = nCountCubes - 1;\r\n End;\r\n\r\n### End Prolog ###", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.cube.view.delete', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n\t 'pCube', '', 'pView', '', 'pDelim', '&'\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock Ver 4.0.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process deletes public views.\r\n\r\n# Use case: Intended for development/prototyping or production.\r\n# 1/ After a view has been created to zero or as a data source it needs to be deleted.\r\n# 2/ Clean up public views after Go Live.\r\n\r\n# Note:\r\n# This process can work on a single cubes or multiple cubes.\r\n# This process can work on a single view or multiple views.\r\n# When specifying view names wildcards can be included by using the * character. \r\n# **Parameter pCube**.\r\n# - To specify which cubes to delete views from use the pCubes parameter.\r\n# - To delete views from a single cube only just specify that cube name e.g. Sales.\r\n# - To delete views from multiple cubes specify each cube name separated by a delimiter e.g. Sales&Inventory&Cashflow.\r\n# - To delete views from all cubes then set pCubes as *.\r\n# - If any invalid cubes are specified they will be skipped but the process will continue to process the other cubes.\r\n# **Parameter pView**.\r\n# - To specify which views to delete use the pViews parameter.\r\n# - This parameter must be specified, a blank value will cause the process to terminate.\r\n# - To delete a single view only just specify that view name e.g. SalesByProduct.\r\n# - To delete multiple views specify each view name separated by a delimiter e.g. SalesByProduct&SalesByManager&SalesByStore.\r\n# - When specifying view names wildcards are permitted and all views that match the wildcard search string will be deleted.\r\n# - The wildcard search string follows the same format as windows based file wildcards.\r\n# - To delete all views that \"start\" with a specific string use a trailing * e.g. Bedrock*.\r\n# - To delete all views that \"end\" in a specific string use a leading * e.g. *Bedrock.\r\n# - To delete all views that \"contain\" a specific string use leading and trailing *'s e.g. *Bedrock*.\r\n# - To delete a single specific view only don't use *'s at all e.g. Bedrock.\r\n# - To specify multiple search stings list them all separated by a delimiter e.g. Bedrock*;*Temp;*Test*.\r\n# - Specific view names and wildcard based names can both be used together e.g. SalesByProduct;Bedrock*.\r\n# **Parameter pDelim**.\r\n# - The delimiter can be used when specifying multiple cubes and/or multiple views.\r\n# - The default delimiter is &.\r\n# - Any delimiter can be used by specifying a value for pDelimiter.\r\n# - Choose a delimiter that won't be used in either the wildcard search strings or cube names.\r\n#EndRegion @DOC\r\n\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSubset = cThisProcName | '_' | cTimeStamp | '_' | cRandomInt;\r\ncTempFile = GetProcessErrorFileDirectory | cTempSubset | '.csv';\r\nsMessage = \t'';\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pCube:%pCube%, pView:%pView%, pDelim:%pDelim%.' ;\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pCube\": null,\r\n \"pDelim\": \"&\",\r\n \"pView\": null,\r\n \"pLogOutput\": 0,\r\n \"pStrictErrorHandling\": 0\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pCube\": '|StringToJson ( pCube )|',\r\n \"pDelim\": '|StringToJson ( pDelim )|',\r\n \"pView\": '|StringToJson ( pView )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npCube = JsonToString( JsonGet( pJson, 'pCube' ) );\r\npDelim = JsonToString( JsonGet( pJson, 'pDelim' ) );\r\npView = JsonToString( JsonGet( pJson, 'pView' ) );\r\n# Numeric Parameters\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\nnErrors = 0;\r\ncDimension = '}Cubes';\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\n# Validate views\r\nIf( Trim( pView ) @= '' );\r\n sMessage = 'No views specified.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate delimiter\r\nIf( Trim( pDelim ) @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\n### Iterate through cubes ###\r\n\r\n# If no cube has been specified then process all cubes\r\nIf( Trim( pCube ) @= '' );\r\n sMessage = 'No cube specified.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors > 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n# Work through all cubes specified in pCube\r\nsCubes = pCube;\r\nnCubeDelimIndex = 1;\r\nsDelimiter = pDelim;\r\nsMdx = '';\r\nWhile( nCubeDelimIndex <> 0 );\r\n nCubeDelimIndex = Scan( sDelimiter, sCubes );\r\n If( nCubeDelimIndex = 0 );\r\n sCube = Trim( sCubes );\r\n Else;\r\n sCube = Trim( SubSt( sCubes, 1, nCubeDelimIndex - 1 ) );\r\n sCubes = Trim( SubSt( sCubes, nCubeDelimIndex + Long( sDelimiter ), Long( sCubes ) ) );\r\n EndIf;\r\n\r\n # Create subset of cubes using Wildcard to loop through cubes in pCube with wildcard\r\n sCubeExp = '\"'|sCube|'\"';\r\n sMdxPart = Expand('{TM1FILTERBYPATTERN( TM1SUBSETALL( [}Cubes] ), %sCubeExp% )}');\r\n IF( sMdx @= ''); \r\n sMdx = sMdxPart; \r\n ELSE;\r\n sMdx = sMdx | ' + ' | sMdxPart;\r\n ENDIF;\r\nEnd;\r\n \r\nIf( SubsetExists( '}Cubes' , cTempSubset ) = 1 );\r\n # If a delimited list of cube names includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( '}Cubes' , cTempSubset, sMDX );\r\nElse;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSubset, sMDX, '}Cubes' , 1 );\r\nEndIf;\r\n \r\n \r\n # Loop through cubess in subset created based on wildcard\r\n nCountCubes = SubsetGetSize( '}Cubes' , cTempSubset );\r\n While( nCountCubes >= 1 );\r\n sCurrentCube = SubsetGetElementName( '}Cubes' , cTempSubset, nCountCubes );\r\n # If a valid cube has been specified then delete specified views from it\r\n If( CubeExists( sCurrentCube ) = 1 );\r\n If( pLogOutput = 1 );\r\n LogOutput( 'INFO', Expand( 'Processing cube %sCurrentCube%.' ) );\r\n EndIf;\r\n # Work through all views specified in pViews\r\n sViews = pView;\r\n nViewDelimIndex = 1;\r\n sMdxView = '';\r\n \r\n While( nViewDelimIndex <> 0 );\r\n nViewDelimIndex = Scan( sDelimiter, sViews );\r\n If( nViewDelimIndex = 0 );\r\n sView = Trim( sViews );\r\n Else;\r\n sView = Trim( SubSt( sViews, 1, nViewDelimIndex - 1 ) );\r\n sViews = Trim( SubSt( sViews, nViewDelimIndex + Long( sDelimiter ), Long( sViews ) ) );\r\n EndIf;\r\n \r\n # Check if a wildcard has been used to specify the view name.\r\n # If it hasn't then just delete the view if it exists\r\n If( Scan( '*', sView ) = 0 );\r\n If( ViewExists( sCurrentCube, sView ) = 1 );\r\n If( pLogOutput = 1 );\r\n LogOutput( 'INFO', Expand( ' Destroying view %sView% in cube %sCurrentCube%.' ) );\r\n EndIf;\r\n ViewDestroy( sCurrentCube, sView );\r\n EndIf;\r\n # If it has then iterate through '}Views_CubeName' dimension\r\n Else;\r\n sDimViews = '}Views_' | sCurrentCube ;\r\n If( DimensionExists( sDimViews ) = 1 );\r\n # Create subset of views using Wildcard to loop through views in current cube\r\n sViewExp = '\"'|sView|'\"';\r\n sMdxViewPart = Expand('{TM1FILTERBYPATTERN( {TM1SUBSETALL([%sDimViews%])}, %sViewExp% )}');\r\n IF( sMdxView @= ''); \r\n sMdxview = sMdxViewPart; \r\n ELSE;\r\n sMdxView = sMdxView | ' + ' | sMdxViewPart;\r\n ENDIF;\r\n If( SubsetExists( sDimViews, cTempSubset ) = 1 );\r\n # If a delimited list of attr names includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( sDimViews, cTempSubset, sMdxView );\r\n Else;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSubset, sMdxView, sDimViews, 1 );\r\n EndIf;\r\n \r\n # Loop through subset of views created based on wildcard\r\n nCountView = SubsetGetSize( sDimViews, cTempSubset );\r\n While( nCountView >= 1 );\r\n sViewEle = SubsetGetElementName( sDimViews, cTempSubset, nCountView );\r\n # Validate attribute name in sDim\r\n If( ViewExists( sCurrentCube, sViewEle ) = 1 );\r\n If( pLogOutput = 1 );\r\n LogOutput( 'INFO', Expand( 'Destroying view %sViewEle% in cube %sCurrentCube%.' ) );\r\n EndIf;\r\n ViewDestroy( sCurrentCube, sViewEle );\r\n Endif;\r\n nCountView = nCountView - 1;\r\n End;\r\n EndIf;\r\n EndIf;\r\n \r\n End;\r\n \r\n # Cube does not exist\r\n Else;\r\n sMessage = Expand('Cube %sCurrentCube% does not exist.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n EndIf;\r\n \r\n nCountCubes = nCountCubes - 1;\r\n End;\r\n\r\n### End Prolog ###", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully deleted view %pView% from cube %pCube%.' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n\r\n### End Epilog ###", @@ -10,35 +10,41 @@ "Type": "None" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pCube", - "Prompt": "REQUIRED: List of Cubes Separated by Delimiter (For all cubes just the wildcard character alone i.e. *)", + "Prompt": "REQUIRED: Cube name", "Value": "", "Type": "String" }, { "Name": "pView", - "Prompt": "REQUIRED: List of Views Separated by Delimiter. Wildcards Permitted on View Names.", - "Value": "}bedrock*", + "Prompt": "REQUIRED: Delimited list of views", + "Value": "", "Type": "String" }, { "Name": "pDelim", - "Prompt": "OPTIONAL: Delimiter Character (default value if blank = '&')", + "Prompt": "OPTIONAL: Delimiter for list parameters (Default = '&')", "Value": "&", "Type": "String" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [], diff --git a/bedrock_processes_json/}bedrock.cube.view.publish.json b/bedrock_processes_json/}bedrock.cube.view.publish.json index 0a802a9..c7bf1d5 100644 --- a/bedrock_processes_json/}bedrock.cube.view.publish.json +++ b/bedrock_processes_json/}bedrock.cube.view.publish.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.cube.view.publish", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.cube.view.publish', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pCube', '', 'pView', '',\r\n \t'pSubPublish', 1, 'pOverwrite', 0\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock Ver 4.0.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process converts a private view to a public view for the named client.\r\n#\r\n# Use case: Intended for development/prototyping or production.\r\n# 1. Make private view public to enable public consumption.\r\n#\r\n# Note:\r\n# * A valid cube name pCube is mandatory otherwise the process will abort.\r\n# * Also, a valid view name pView is mandatory otherwise the process will abort.\r\n# * This process must be run by the user owning the private view; it canot be run by another user.\r\n# * If the view contains private subsets they must also be made public or the view publish will fail.\r\n#EndRegion @DOC\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSubset = cThisProcName | '_' | cTimeStamp | '_' | cRandomInt;\r\ncTempFile = GetProcessErrorFileDirectory | cTempSubset | '.csv';\r\nsMessage = \t'';\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pCube:%pCube%, pView:%pView%, pSubPublish:%pSubPublish%, pOverwrite:%pOverwrite%.' ;\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\n# create friendly name for user handle\r\nIf( DimIx( '}ElementAttributes_}Clients', '}TM1_DefaultDisplayValue' ) > 0 );\r\n pClient = AttrS( '}Clients', cUserName, '}TM1_DefaultDisplayValue' );\r\n If( pClient @= '' );\r\n pClient = cUserName;\r\n EndIf;\r\nElse;\r\n pClient = cUserName;\r\nEndIf;\r\n\r\n# Validate Cube\r\nIf( Trim( pCube ) @= '' );\r\n sMessage = 'No cube specified';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( CubeExists( pCube ) = 0 );\r\n sMessage = Expand('Cube %pCube% does not exist on server');\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate view\r\nIf( Trim( pView ) @= '' );\r\n sMessage = 'No view specified';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# No way to check if private view exists except via file system.\r\n# Could include data directory param and concatenate with user, cube and view to check\r\n# if private view exists to handle error in the case that private view does not exist\r\n\r\n# Check for valid view name, subset publish and overwrite parameters\r\nIf( pSubPublish <> 0 & pSubPublish <> 1 );\r\n sMessage = 'Invalid publish private subsets selection: ' | NumberToString( pSubPublish );\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nIf( pOverwrite <> 0 & pOverwrite <> 1 );\r\n sMessage = 'Invalid overwrite existing public view selection: ' | NumberToString( pOverwrite );\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nIf( pOverwrite = 0 & ViewExists( pCube, pView ) = 1 );\r\n # If NOT overwriting current public view AND view of the same name exists then cause minor error ( major error if not handled )\r\n sMessage = 'Public view of same name already exists and Overwrite=0 specified';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### Publish the view ( and any private subsets ) ###\r\nPublishView( pCube, pView, pSubPublish, pOverwrite );\r\n\r\n### End Prolog ###", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.cube.view.publish', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pCube', '', 'pView', '',\r\n \t'pSubPublish', 1, 'pOverwrite', 0\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock Ver 4.0.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process converts a private view to a public view for the named client.\r\n#\r\n# Use case: Intended for development/prototyping or production.\r\n# 1. Make private view public to enable public consumption.\r\n#\r\n# Note:\r\n# * A valid cube name pCube is mandatory otherwise the process will abort.\r\n# * Also, a valid view name pView is mandatory otherwise the process will abort.\r\n# * This process must be run by the user owning the private view; it canot be run by another user.\r\n# * If the view contains private subsets they must also be made public or the view publish will fail.\r\n#EndRegion @DOC\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSubset = cThisProcName | '_' | cTimeStamp | '_' | cRandomInt;\r\ncTempFile = GetProcessErrorFileDirectory | cTempSubset | '.csv';\r\nsMessage = \t'';\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pCube:%pCube%, pView:%pView%, pSubPublish:%pSubPublish%, pOverwrite:%pOverwrite%.' ;\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pCube\": null,\r\n \"pView\": null,\r\n \"pLogOutput\": 0,\r\n \"pOverwrite\": 0,\r\n \"pStrictErrorHandling\": 0,\r\n \"pSubPublish\": 1\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pCube\": '|StringToJson ( pCube )|',\r\n \"pView\": '|StringToJson ( pView )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pOverwrite\": '|NumberToString( pOverwrite )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|',\r\n \"pSubPublish\": '|NumberToString( pSubPublish )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npCube = JsonToString( JsonGet( pJson, 'pCube' ) );\r\npView = JsonToString( JsonGet( pJson, 'pView' ) );\r\n# Numeric Parameters\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npOverwrite = StringToNumber( JsonToString( JsonGet( pJson, 'pOverwrite' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\npSubPublish = StringToNumber( JsonToString( JsonGet( pJson, 'pSubPublish' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\n# create friendly name for user handle\r\nIf( DimIx( '}ElementAttributes_}Clients', '}TM1_DefaultDisplayValue' ) > 0 );\r\n pClient = AttrS( '}Clients', cUserName, '}TM1_DefaultDisplayValue' );\r\n If( pClient @= '' );\r\n pClient = cUserName;\r\n EndIf;\r\nElse;\r\n pClient = cUserName;\r\nEndIf;\r\n\r\n# Validate Cube\r\nIf( Trim( pCube ) @= '' );\r\n sMessage = 'No cube specified';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( CubeExists( pCube ) = 0 );\r\n sMessage = Expand('Cube %pCube% does not exist on server');\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate view\r\nIf( Trim( pView ) @= '' );\r\n sMessage = 'No view specified';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# No way to check if private view exists except via file system.\r\n# Could include data directory param and concatenate with user, cube and view to check\r\n# if private view exists to handle error in the case that private view does not exist\r\n\r\n# Check for valid view name, subset publish and overwrite parameters\r\nIf( pSubPublish <> 0 & pSubPublish <> 1 );\r\n sMessage = 'Invalid publish private subsets selection: ' | NumberToString( pSubPublish );\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nIf( pOverwrite <> 0 & pOverwrite <> 1 );\r\n sMessage = 'Invalid overwrite existing public view selection: ' | NumberToString( pOverwrite );\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nIf( pOverwrite = 0 & ViewExists( pCube, pView ) = 1 );\r\n # If NOT overwriting current public view AND view of the same name exists then cause minor error ( major error if not handled )\r\n sMessage = 'Public view of same name already exists and Overwrite=0 specified';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### Publish the view ( and any private subsets ) ###\r\nPublishView( pCube, pView, pSubPublish, pOverwrite );\r\n\r\n### End Prolog ###", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully published view %pView% in cube %pCube% created by cient %pClient%.' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n### End Epilog ###", @@ -10,41 +10,47 @@ "Type": "None" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pCube", - "Prompt": "REQUIRED: Cube Name", + "Prompt": "REQUIRED: Cube name", "Value": "", "Type": "String" }, { "Name": "pView", - "Prompt": "REQUIRED: Private View Name", + "Prompt": "REQUIRED: Name of the view", "Value": "", "Type": "String" }, { "Name": "pSubPublish", - "Prompt": "OPTIONAL: Publish Private Subsets? (Boolean 1=Yes)", + "Prompt": "OPTIONAL: Publish private subsets (Boolean. Default = 1)", "Value": 1, "Type": "Numeric" }, { "Name": "pOverwrite", - "Prompt": "OPTIONAL: Overwrite Existing Named View? (Boolean 1=Yes)", + "Prompt": "OPTIONAL: Overwrite existing named objects (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [], diff --git a/bedrock_processes_json/}bedrock.cube.viewandsubsets.create.json b/bedrock_processes_json/}bedrock.cube.viewandsubsets.create.json index 5559d84..9492665 100644 --- a/bedrock_processes_json/}bedrock.cube.viewandsubsets.create.json +++ b/bedrock_processes_json/}bedrock.cube.viewandsubsets.create.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.cube.viewandsubsets.create", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.cube.viewandsubsets.create', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pCube', '', 'pView', '', 'pSub', '', \r\n \t'pDim', '*', 'pDelim', '&',\r\n \t'pSuppressZero', 1, 'pSuppressConsol', 1, 'pSuppressRules', 1,\r\n \t'pTemp', 1, 'pSubN', 0\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock Ver 4.0.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process creates a processing view for the cube and for specified dimensions of the cube. \r\n\r\n# Use case: Intended for development/prototyping or in Production environment.\r\n# 1. Create a view with subsets of the same name that are empty.\r\n\r\n# Note:\r\n# Creates empty subsets and assigns the empty subsets to the view. \r\n# A subsequent process is required to insert elements into subsets otherwise the views will not contain any data.\r\n# Naturally, a valid cube name (pCube) is mandatory otherwise the process will abort.\r\n#EndRegion @DOC\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = '%cThisProcName% : %sMessage% : %cUserName%';\r\ncMsgInfoLevel = 'INFO';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pCube:%pCube%, pView:%pView%, pSubset:%pSub%, pDim:%pDim%, pDelim:%pDelim%, pSuppressZero:%pSuppressZero%, pSuppressConsol:%pSuppressConsol%, pSuppressRules:%pSuppressRules%.'; \r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSubset = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\nsMessage = '';\r\ncDimCubes = '}Cubes';\r\ncDimDimensions = '}Dimensions';\r\ncAll = 'ALL';\r\ncTemp = If( pTemp >= 1, 1, 0 );\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\n\r\nnErrors = 0;\r\n\r\n# Validate cube\r\nIf( Trim( pCube ) @= '' );\r\n sMessage = 'No cube specified.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate dimensions\r\nIf( Trim( pDim ) @= '' );\r\n sMessage = 'No dimensions specified.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate suppression parameters\r\nIf( pSuppressZero <> 0 & pSuppressZero <> 1 );\r\n sMessage = 'Invalid value for suppress zero parameter.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nIf( pSuppressConsol <> 0 & pSuppressConsol <> 1 );\r\n sMessage = 'Invalid value for suppress consol parameter.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nIf( pSuppressRules <> 0 & pSuppressRules <> 1 );\r\n sMessage = 'Invalid value for suppress rules parameter.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate view and subsets\r\nIf( pView @= '' & pSub @= '' );\r\n ## Use standard view name.\r\n cView = cTempSubset;\r\n cSubset = cView;\r\nElseIf( pView @<> '' & pSub @= '' );\r\n ## Use the nominated view name for the subset name.\r\n cView = pView;\r\n cSubset = pView;\r\nElseIf( pView @= '' & pSub @<> '' );\r\n ## Use the nominated subset name for the view name.\r\n cView = pSub;\r\n cSubset = pSub;\r\nElse;\r\n cView = pView;\r\n cSubset = pSub;\r\nEndIf;\r\n\r\n\r\n# Validate delimiter\r\nIf( pDelim @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### Handle All cubes or a cubes list\r\nIf ( TRIM( pCube ) @= cAll );\r\n sMDX = Expand( '{TM1SUBSETALL([%cDimCubes%])}' );\r\nElse;\r\n sCubeTokenizer = TRIM( pCube );\r\n sMDX = '';\r\n ### Loop and tokenize Cube list\r\n While ( sCubeTokenizer @<> '' );\r\n nPos = SCAN( pDelim, sCubeTokenizer );\r\n If ( nPos = 0 );\r\n nPos = LONG( sCubeTokenizer ) + 1;\r\n EndIf;\r\n sSearchCube = TRIM( SUBST( sCubeTokenizer, 1, nPos - 1 ) );\r\n If ( SCAN( '*', sSearchCube ) <> 0 % SCAN( '?', sSearchCube ) <> 0 );\r\n If( sMDX @= '' );\r\n sMDX = Expand( '{TM1FILTERBYPATTERN({TM1SUBSETALL([%cDimCubes%])}, \"%sSearchCube%\")}' );\r\n Else;\r\n sMDX = Expand( '%sMDX% + {TM1FILTERBYPATTERN({TM1SUBSETALL([%cDimCubes%])}, \"%sSearchCube%\")}' );\r\n EndIf;\r\n Else;\r\n If ( CubeExists( sSearchCube ) = 0 );\r\n sMessage = Expand( 'Cube: %sSearchCube% does not exist.' );\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n Else;\r\n If( sMDX @= '' );\r\n sMDX = Expand( '{[%cDimCubes%].[%sSearchCube%]}' );\r\n Else;\r\n sMDX = Expand( '%sMDX% + {[%cDimCubes%].[%sSearchCube%]}' );\r\n EndIf;\r\n EndIf;\r\n EndIf;\r\n ### Consume dimension and delimiter\r\n sCubeTokenizer = TRIM( DELET( sCubeTokenizer, 1, nPos + LONG( pDelim ) - 1 ) );\r\n End;\r\n sMDX = Expand( '{%sMDX%}' );\r\nEndIf;\r\n\r\nIf (SubsetExists( cDimCubes, cTempSubset ) = 1 );\r\n SubsetDestroy( cDimCubes, cTempSubset );\r\nEndIf;\r\nSubsetCreateByMDX( cTempSubset, sMDX, cDimCubes, 1 );\r\n\r\n### Handle All dimensions or a dimension list\r\n### We must exclude hierarchies\r\nIf ( TRIM( pDim ) @= cAll );\r\n sMDX = Expand( '{FILTER(TM1SUBSETALL([%cDimDimensions%]), INSTR([%cDimDimensions%].CurrentMember.Name, '':'' ) = 0 )}' );\r\nElse;\r\n sDimTokenizer = TRIM( pDim );\r\n sMDX = '';\r\n ### Loop and tokenize dimension list\r\n While ( sDimTokenizer @<> '' );\r\n nPos = SCAN( pDelim, sDimTokenizer );\r\n If ( nPos = 0 );\r\n nPos = LONG( sDimTokenizer ) + 1;\r\n EndIf;\r\n sSearchDim = TRIM( SUBST( sDimTokenizer, 1, nPos - 1 ) );\r\n If ( SCAN( ':', sSearchDim ) <> 0 );\r\n sMessage = Expand( 'Dimension: The process is not accepting hierarchies: %sSearchDim%' );\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n ElseIf ( SCAN( '*', sSearchDim ) <> 0 % SCAN( '?', sSearchDim ) <> 0 );\r\n If( sMDX @= '' );\r\n sMDX = Expand( '{TM1FILTERBYPATTERN({FILTER(TM1SUBSETALL([%cDimDimensions%]), INSTR([%cDimDimensions%].CurrentMember.Name, '':'' ) = 0 )}, \"%sSearchDim%\")}' );\r\n Else;\r\n sMDX = Expand( '%sMDX% + {TM1FILTERBYPATTERN({FILTER(TM1SUBSETALL([%cDimDimensions%]), INSTR([%cDimDimensions%].CurrentMember.Name, '':'' ) = 0 )}, \"%sSearchDim%\")}' );\r\n EndIf;\r\n Else;\r\n If ( DimensionExists( sSearchDim ) = 0 );\r\n sMessage = Expand( 'Dimension: %sSearchDim% does not exist.' );\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n Else;\r\n If( sMDX @= '' );\r\n sMDX = Expand( '{[%cDimDimensions%].[%sSearchDim%]}' );\r\n Else;\r\n sMDX = Expand( '%sMDX% + {[%cDimDimensions%].[%sSearchDim%]}' );\r\n EndIf;\r\n EndIf;\r\n EndIf;\r\n ### Consume dimension and delimiter\r\n sDimTokenizer = TRIM( DELET( sDimTokenizer, 1, nPos + LONG( pDelim ) - 1 ) );\r\n End;\r\n sMDX = Expand( '{%sMDX%}' );\r\nEndIf;\r\n\r\nIf (SubsetExists( cDimDimensions, cTempSubset ) = 1 );\r\n SubsetDestroy( cDimDimensions, cTempSubset );\r\nEndIf;\r\nSubsetCreateByMDX( cTempSubset, sMDX, cDimDimensions, 1 );\r\n\r\n### Build Subsets and assign to View ###\r\nnCube = 1;\r\nWhile ( nCube <= SubsetGetSize( cDimCubes, cTempSubset ) );\r\n sCube = SubsetGetElementName( cDimCubes, cTempSubset, nCube );\r\n ### Build View ###\r\n If( ViewExists( sCube, cView ) = 1 );\r\n ViewDestroy( sCube, cView );\r\n EndIf;\r\n nDim = 1;\r\n sDim = TABDIM( sCube, nDim );\r\n While ( sDim @<> '' );\r\n # filter selection has non-empty intersect with current cube dimensions\r\n #If ( SubsetElementExists( cDimDimensions, cTempSubset, sDim ) = 1 ); - bug does not work\r\n IF( SubsetElementGetIndex( cDimDimensions, cTempSubset, sDim, 1 ) > 0 );\r\n # create view if and only if there is at least one match with dimensions\r\n If( ViewExists( sCube, cView ) = 0 );\r\n ViewCreate( sCube, cView, cTemp );\r\n ViewExtractSkipZeroesSet( sCube, cView, pSuppressZero );\r\n ViewExtractSkipCalcsSet( sCube, cView, pSuppressConsol );\r\n ViewExtractSkipRuleValuesSet( sCube, cView, pSuppressRules );\r\n EndIf;\r\n If ( SubsetExists ( sDim, cSubset ) = 1 );\r\n If ( SubsetGetSize( sDim, cSubset ) > 0 );\r\n SubsetDeleteAllElements( sDim, cSubset );\r\n EndIf;\r\n Else;\r\n SubsetCreate( sDim, cSubset, cTemp );\r\n EndIf;\r\n ViewSubsetAssign( sCube, cView, sDim, cSubset );\r\n EndIf;\r\n nDim = nDim + 1;\r\n sDim = TABDIM( sCube, nDim );\r\n End;\r\n \r\n # creating N level subset for all dim not included in pDim for the cube\r\n If(pSubN = 1);\r\n nCountDimC = 1;\r\n While( TabDim( sCube, nCountDimC ) @<> '' );\r\n sDimC = TabDim( sCube, nCountDimC );\r\n If ( ViewExists( sCube, cView ) = 1 & SubsetElementGetIndex( cDimDimensions, cTempSubset, sDimC, 1 ) = 0 );\r\n If ( SubsetExists ( sDimC, cSubset ) = 1 );\r\n If ( SubsetGetSize( sDimC, cSubset ) > 0 );\r\n SubsetDeleteAllElements( sDimC, cSubset );\r\n EndIf;\r\n Else;\r\n SubsetCreate( sDimC, cSubset, cTemp );\r\n Endif; \r\n nElCount = DIMSIZ ( sDimC );\r\n nElC = 1;\r\n WHILE ( nElC <= nElCount );\r\n sEl = DIMNM( sDimC, nElC );\r\n IF(ElementLevel( sDimC, sDimC, sEl )= 0 );\r\n SubsetElementInsert( sDimC, cSubset, sEl, 0 );\r\n EndIf;\r\n nElC = nElC + 1;\r\n END;\r\n ViewSubsetAssign( sCube, cView, sDimC, cSubset );\r\n Endif;\r\n nCountDimC = nCountDimC + 1;\r\n End;\r\n Endif;\r\n\r\n\r\n nCube = nCube + 1;\r\nEnd;\r\n\r\n\r\n### End Prolog ###\r\n\r\n", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.cube.viewandsubsets.create', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pCube', '', 'pView', '', 'pSub', '', \r\n \t'pDim', '*', 'pDelim', '&',\r\n \t'pSuppressZero', 1, 'pSuppressConsol', 1, 'pSuppressRules', 1,\r\n \t'pTemp', 1, 'pSubN', 0\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock Ver 4.0.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process creates a processing view for the cube and for specified dimensions of the cube. \r\n\r\n# Use case: Intended for development/prototyping or in Production environment.\r\n# 1. Create a view with subsets of the same name that are empty.\r\n\r\n# Note:\r\n# Creates empty subsets and assigns the empty subsets to the view. \r\n# A subsequent process is required to insert elements into subsets otherwise the views will not contain any data.\r\n# Naturally, a valid cube name (pCube) is mandatory otherwise the process will abort.\r\n#EndRegion @DOC\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = '%cThisProcName% : %sMessage% : %cUserName%';\r\ncMsgInfoLevel = 'INFO';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pCube:%pCube%, pView:%pView%, pSubset:%pSub%, pDim:%pDim%, pDelim:%pDelim%, pSuppressZero:%pSuppressZero%, pSuppressConsol:%pSuppressConsol%, pSuppressRules:%pSuppressRules%.'; \r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSubset = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\nsMessage = '';\r\ncDimCubes = '}Cubes';\r\ncDimDimensions = '}Dimensions';\r\ncAll = 'ALL';\r\ncTemp = If( pTemp >= 1, 1, 0 );\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pCube\": null,\r\n \"pDelim\": \"&\",\r\n \"pDim\": \"*\",\r\n \"pSub\": \"*\",\r\n \"pView\": \"\",\r\n \"pLogOutput\": 0,\r\n \"pStrictErrorHandling\": 0,\r\n \"pSubN\": 0,\r\n \"pSuppressConsol\": 1,\r\n \"pSuppressRules\": 1,\r\n \"pSuppressZero\": 1,\r\n \"pTemp\": 1\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pCube\": '|StringToJson ( pCube )|',\r\n \"pDelim\": '|StringToJson ( pDelim )|',\r\n \"pDim\": '|StringToJson ( pDim )|',\r\n \"pSub\": '|StringToJson ( pSub )|',\r\n \"pView\": '|StringToJson ( pView )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|',\r\n \"pSubN\": '|NumberToString( pSubN )|',\r\n \"pSuppressConsol\": '|NumberToString( pSuppressConsol )|',\r\n \"pSuppressRules\": '|NumberToString( pSuppressRules )|',\r\n \"pSuppressZero\": '|NumberToString( pSuppressZero )|',\r\n \"pTemp\": '|NumberToString( pTemp )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npCube = JsonToString( JsonGet( pJson, 'pCube' ) );\r\npDelim = JsonToString( JsonGet( pJson, 'pDelim' ) );\r\npDim = JsonToString( JsonGet( pJson, 'pDim' ) );\r\npSub = JsonToString( JsonGet( pJson, 'pSub' ) );\r\npView = JsonToString( JsonGet( pJson, 'pView' ) );\r\n# Numeric Parameters\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\npSubN = StringToNumber( JsonToString( JsonGet( pJson, 'pSubN' ) ) );\r\npSuppressConsol = StringToNumber( JsonToString( JsonGet( pJson, 'pSuppressConsol' ) ) );\r\npSuppressRules = StringToNumber( JsonToString( JsonGet( pJson, 'pSuppressRules' ) ) );\r\npSuppressZero = StringToNumber( JsonToString( JsonGet( pJson, 'pSuppressZero' ) ) );\r\npTemp = StringToNumber( JsonToString( JsonGet( pJson, 'pTemp' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\n\r\nnErrors = 0;\r\n\r\n# Validate cube\r\nIf( Trim( pCube ) @= '' );\r\n sMessage = 'No cube specified.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate dimensions\r\nIf( Trim( pDim ) @= '' );\r\n sMessage = 'No dimensions specified.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate suppression parameters\r\nIf( pSuppressZero <> 0 & pSuppressZero <> 1 );\r\n sMessage = 'Invalid value for suppress zero parameter.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nIf( pSuppressConsol <> 0 & pSuppressConsol <> 1 );\r\n sMessage = 'Invalid value for suppress consol parameter.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nIf( pSuppressRules <> 0 & pSuppressRules <> 1 );\r\n sMessage = 'Invalid value for suppress rules parameter.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate view and subsets\r\nIf( pView @= '' & pSub @= '' );\r\n ## Use standard view name.\r\n cView = cTempSubset;\r\n cSubset = cView;\r\nElseIf( pView @<> '' & pSub @= '' );\r\n ## Use the nominated view name for the subset name.\r\n cView = pView;\r\n cSubset = pView;\r\nElseIf( pView @= '' & pSub @<> '' );\r\n ## Use the nominated subset name for the view name.\r\n cView = pSub;\r\n cSubset = pSub;\r\nElse;\r\n cView = pView;\r\n cSubset = pSub;\r\nEndIf;\r\n\r\n\r\n# Validate delimiter\r\nIf( pDelim @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### Handle All cubes or a cubes list\r\nIf ( TRIM( pCube ) @= cAll );\r\n sMDX = Expand( '{TM1SUBSETALL([%cDimCubes%])}' );\r\nElse;\r\n sCubeTokenizer = TRIM( pCube );\r\n sMDX = '';\r\n ### Loop and tokenize Cube list\r\n While ( sCubeTokenizer @<> '' );\r\n nPos = SCAN( pDelim, sCubeTokenizer );\r\n If ( nPos = 0 );\r\n nPos = LONG( sCubeTokenizer ) + 1;\r\n EndIf;\r\n sSearchCube = TRIM( SUBST( sCubeTokenizer, 1, nPos - 1 ) );\r\n If ( SCAN( '*', sSearchCube ) <> 0 % SCAN( '?', sSearchCube ) <> 0 );\r\n If( sMDX @= '' );\r\n sMDX = Expand( '{TM1FILTERBYPATTERN({TM1SUBSETALL([%cDimCubes%])}, \"%sSearchCube%\")}' );\r\n Else;\r\n sMDX = Expand( '%sMDX% + {TM1FILTERBYPATTERN({TM1SUBSETALL([%cDimCubes%])}, \"%sSearchCube%\")}' );\r\n EndIf;\r\n Else;\r\n If ( CubeExists( sSearchCube ) = 0 );\r\n sMessage = Expand( 'Cube: %sSearchCube% does not exist.' );\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n Else;\r\n If( sMDX @= '' );\r\n sMDX = Expand( '{[%cDimCubes%].[%sSearchCube%]}' );\r\n Else;\r\n sMDX = Expand( '%sMDX% + {[%cDimCubes%].[%sSearchCube%]}' );\r\n EndIf;\r\n EndIf;\r\n EndIf;\r\n ### Consume dimension and delimiter\r\n sCubeTokenizer = TRIM( DELET( sCubeTokenizer, 1, nPos + LONG( pDelim ) - 1 ) );\r\n End;\r\n sMDX = Expand( '{%sMDX%}' );\r\nEndIf;\r\n\r\nIf (SubsetExists( cDimCubes, cTempSubset ) = 1 );\r\n SubsetDestroy( cDimCubes, cTempSubset );\r\nEndIf;\r\nSubsetCreateByMDX( cTempSubset, sMDX, cDimCubes, 1 );\r\n\r\n### Handle All dimensions or a dimension list\r\n### We must exclude hierarchies\r\nIf ( TRIM( pDim ) @= cAll );\r\n sMDX = Expand( '{FILTER(TM1SUBSETALL([%cDimDimensions%]), INSTR([%cDimDimensions%].CurrentMember.Name, '':'' ) = 0 )}' );\r\nElse;\r\n sDimTokenizer = TRIM( pDim );\r\n sMDX = '';\r\n ### Loop and tokenize dimension list\r\n While ( sDimTokenizer @<> '' );\r\n nPos = SCAN( pDelim, sDimTokenizer );\r\n If ( nPos = 0 );\r\n nPos = LONG( sDimTokenizer ) + 1;\r\n EndIf;\r\n sSearchDim = TRIM( SUBST( sDimTokenizer, 1, nPos - 1 ) );\r\n If ( SCAN( ':', sSearchDim ) <> 0 );\r\n sMessage = Expand( 'Dimension: The process is not accepting hierarchies: %sSearchDim%' );\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n ElseIf ( SCAN( '*', sSearchDim ) <> 0 % SCAN( '?', sSearchDim ) <> 0 );\r\n If( sMDX @= '' );\r\n sMDX = Expand( '{TM1FILTERBYPATTERN({FILTER(TM1SUBSETALL([%cDimDimensions%]), INSTR([%cDimDimensions%].CurrentMember.Name, '':'' ) = 0 )}, \"%sSearchDim%\")}' );\r\n Else;\r\n sMDX = Expand( '%sMDX% + {TM1FILTERBYPATTERN({FILTER(TM1SUBSETALL([%cDimDimensions%]), INSTR([%cDimDimensions%].CurrentMember.Name, '':'' ) = 0 )}, \"%sSearchDim%\")}' );\r\n EndIf;\r\n Else;\r\n If ( DimensionExists( sSearchDim ) = 0 );\r\n sMessage = Expand( 'Dimension: %sSearchDim% does not exist.' );\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n Else;\r\n If( sMDX @= '' );\r\n sMDX = Expand( '{[%cDimDimensions%].[%sSearchDim%]}' );\r\n Else;\r\n sMDX = Expand( '%sMDX% + {[%cDimDimensions%].[%sSearchDim%]}' );\r\n EndIf;\r\n EndIf;\r\n EndIf;\r\n ### Consume dimension and delimiter\r\n sDimTokenizer = TRIM( DELET( sDimTokenizer, 1, nPos + LONG( pDelim ) - 1 ) );\r\n End;\r\n sMDX = Expand( '{%sMDX%}' );\r\nEndIf;\r\n\r\nIf (SubsetExists( cDimDimensions, cTempSubset ) = 1 );\r\n SubsetDestroy( cDimDimensions, cTempSubset );\r\nEndIf;\r\nSubsetCreateByMDX( cTempSubset, sMDX, cDimDimensions, 1 );\r\n\r\n### Build Subsets and assign to View ###\r\nnCube = 1;\r\nWhile ( nCube <= SubsetGetSize( cDimCubes, cTempSubset ) );\r\n sCube = SubsetGetElementName( cDimCubes, cTempSubset, nCube );\r\n ### Build View ###\r\n If( ViewExists( sCube, cView ) = 1 );\r\n ViewDestroy( sCube, cView );\r\n EndIf;\r\n nDim = 1;\r\n sDim = TABDIM( sCube, nDim );\r\n While ( sDim @<> '' );\r\n # filter selection has non-empty intersect with current cube dimensions\r\n #If ( SubsetElementExists( cDimDimensions, cTempSubset, sDim ) = 1 ); - bug does not work\r\n IF( SubsetElementGetIndex( cDimDimensions, cTempSubset, sDim, 1 ) > 0 );\r\n # create view if and only if there is at least one match with dimensions\r\n If( ViewExists( sCube, cView ) = 0 );\r\n ViewCreate( sCube, cView, cTemp );\r\n ViewExtractSkipZeroesSet( sCube, cView, pSuppressZero );\r\n ViewExtractSkipCalcsSet( sCube, cView, pSuppressConsol );\r\n ViewExtractSkipRuleValuesSet( sCube, cView, pSuppressRules );\r\n EndIf;\r\n If ( SubsetExists ( sDim, cSubset ) = 1 );\r\n If ( SubsetGetSize( sDim, cSubset ) > 0 );\r\n SubsetDeleteAllElements( sDim, cSubset );\r\n EndIf;\r\n Else;\r\n SubsetCreate( sDim, cSubset, cTemp );\r\n EndIf;\r\n ViewSubsetAssign( sCube, cView, sDim, cSubset );\r\n EndIf;\r\n nDim = nDim + 1;\r\n sDim = TABDIM( sCube, nDim );\r\n End;\r\n \r\n # creating N level subset for all dim not included in pDim for the cube\r\n If(pSubN = 1);\r\n nCountDimC = 1;\r\n While( TabDim( sCube, nCountDimC ) @<> '' );\r\n sDimC = TabDim( sCube, nCountDimC );\r\n If ( ViewExists( sCube, cView ) = 1 & SubsetElementGetIndex( cDimDimensions, cTempSubset, sDimC, 1 ) = 0 );\r\n If ( SubsetExists ( sDimC, cSubset ) = 1 );\r\n If ( SubsetGetSize( sDimC, cSubset ) > 0 );\r\n SubsetDeleteAllElements( sDimC, cSubset );\r\n EndIf;\r\n Else;\r\n SubsetCreate( sDimC, cSubset, cTemp );\r\n Endif; \r\n nElCount = DIMSIZ ( sDimC );\r\n nElC = 1;\r\n WHILE ( nElC <= nElCount );\r\n sEl = DIMNM( sDimC, nElC );\r\n IF(ElementLevel( sDimC, sDimC, sEl )= 0 );\r\n SubsetElementInsert( sDimC, cSubset, sEl, 0 );\r\n EndIf;\r\n nElC = nElC + 1;\r\n END;\r\n ViewSubsetAssign( sCube, cView, sDimC, cSubset );\r\n Endif;\r\n nCountDimC = nCountDimC + 1;\r\n End;\r\n Endif;\r\n\r\n\r\n nCube = nCube + 1;\r\nEnd;\r\n\r\n\r\n### End Prolog ###\r\n\r\n", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully created views and subsets for cube %pCube%.' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n### End Epilog ###", @@ -10,77 +10,83 @@ "Type": "None" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 1, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pCube", - "Prompt": "REQUIRED: List of Cubes (Separated by Delimiter, Accepts Wild card)", + "Prompt": "REQUIRED: Cube name", "Value": "", "Type": "String" }, { "Name": "pView", - "Prompt": "OPTIONAL: View (will default to pSubset if left blank)", + "Prompt": "OPTIONAL: View name (Default = pSubset )", "Value": "", "Type": "String" }, { "Name": "pSub", - "Prompt": "OPTIONAL: Subset (will default to pView if left blank)", - "Value": "", + "Prompt": "OPTIONAL: View name (Default = pView )", + "Value": "*", "Type": "String" }, { "Name": "pDim", - "Prompt": "REQUIRED: Dimension(s) to create empty processing subsets for (separated by delimiter), * = all", + "Prompt": "OPTIONAL: Delimited list of dimensions to create empty processing subsets for (Default = '*')", "Value": "*", "Type": "String" }, { "Name": "pDelim", - "Prompt": "OPTIONAL: List Delimiter (default value if blank = '&')", + "Prompt": "OPTIONAL: Delimiter for list parameters (Default = '&')", "Value": "&", "Type": "String" }, { "Name": "pSuppressZero", - "Prompt": "OPTIONAL: Suppress Zeros (Boolean Yes = 1)", + "Prompt": "OPTIONAL: Suppress zeroes (Boolean. Default = 1)", "Value": 1, "Type": "Numeric" }, { "Name": "pSuppressConsol", - "Prompt": "OPTIONAL: Suppress Calcs (Boolean Yes = 1)", + "Prompt": "OPTIONAL: Suppress consolidated values (Boolean. Default = 1)", "Value": 1, "Type": "Numeric" }, { "Name": "pSuppressRules", - "Prompt": "OPTIONAL: Suppress Rules (Boolean Yes = 1)", + "Prompt": "OPTIONAL: Suppress rules (Boolean. Default = 1)", "Value": 1, "Type": "Numeric" }, { "Name": "pTemp", - "Prompt": "OPTIONAL: Make View Temporary (1=Temporary)", + "Prompt": "OPTIONAL: Delete/create temporary objects (0 = Do not delete, 1 = Delete, 2 = if view and subsets are created, keep only subsets)", "Value": 1, "Type": "Numeric" }, { "Name": "pSubN", - "Prompt": "OPTIONAL: Create N level subset for all dims not mentioned in pDim", + "Prompt": "OPTIONAL: Create N level subset for all dims not specified (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [], diff --git a/bedrock_processes_json/}bedrock.cube.viewandsubsets.delete.json b/bedrock_processes_json/}bedrock.cube.viewandsubsets.delete.json index 8aaf9fa..3726bfa 100644 --- a/bedrock_processes_json/}bedrock.cube.viewandsubsets.delete.json +++ b/bedrock_processes_json/}bedrock.cube.viewandsubsets.delete.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.cube.viewandsubsets.delete", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.cube.viewandsubsets.delete', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n\t 'pCube', '', 'pView', '', 'pSub', '', 'pMode', 1\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process deletes a view and all subsets of the same name.\r\n\r\n# Use case: \r\n# 1. In production environment used in Epilog to remove view & subsets used for processing.\r\n# 2. In development/prototyping to manually clean up views & subsets. \r\n\r\n# Note:\r\n# * Lists and wildcards are not supported in this process\r\n# * A valid cube name pCube is mandatory otherwise the process will abort. \r\n# * A valid view name pView is mandatory otherwise the process will abort.\r\n# * The matching assumption is based on **name**. Subsets of the same name as the view will be deleted (whether they were assigned to the view or not).\r\n# * pMode 0 = Delete views and **indirectly** delete subsets via bedrock process call. If a subset cannot be deleted the process will continue and exit with minor error status.\r\n# * pMode 1 = Delete views and **directly** delete subsets via SubsetDestroy function. If a subset cannot be deleted the process will abort with major error status.\r\n# * pMode 2 = Delete views only and leave subsets as is.\r\n#EndRegion @DOC\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncMsgInfoLevel = 'INFO';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pCube:%pCube%, pView:%pView%, pSub:%pSub%, pMode:%pMode%.' ; \r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSubset = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\nsMessage = '';\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\n### Validate Paramters ##\r\nIF( pMode <> 0 & pMode <> 1 & pMode <> 2 );\r\n sMessage = 'Invailid mode value provided %pMode%. Do not destroy views or subsets.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nENDIF;\r\n\r\nIf( Trim( pCube ) @= '' );\r\n sMessage = 'No cube specified.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( CubeExists( pCube ) = 0 ); \r\n sMessage = Expand( 'Invalid cube specified: %pCube%.' );\r\n nErrors = 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate pView \r\nIf( Trim( pView ) @= '' );\r\n sMessage = 'No view specified.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( ViewExists(pCube, pView ) = 0 ); \r\n sMessage = Expand('There is no view :%pView% in %pCube% cube.') ;\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElse;\r\n cView = Trim( pView );\r\nEndIf;\r\n\r\n# Validate psubset\r\nIf( pSub @= '' );\r\n cSubset = Trim( pView );\r\nElse;\r\n cSubset = Trim( pSub );\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors > 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n## Clean up view\r\nViewDestroy( pCube, cView );\r\n\r\n## Clean up subsets\r\nIf( pMode <= 1 );\r\n\r\n nDimCount = 0;\r\n i = 1;\r\n sDimName = TabDim( pCube, i );\r\n While( sDimName @<> '' );\r\n If( SubsetExists ( sDimName, cSubset ) = 1 );\r\n If( pMode = 0 );\r\n # \"indirect\" deletion\r\n nRet = ExecuteProcess( '}bedrock.hier.sub.delete',\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pLogOutput', pLogOutput,\r\n \t'pDim', sDimName,\r\n \t'pHier','',\r\n \t'pSub', cSubset,\r\n \t'pDelim', If( Scan( '&', cSubset ) = 0, '&', ':' ),\r\n \t'pMode', 0\r\n );\r\n If( pLogOutput >= 1 & nRet <> ProcessExitNormal() );\r\n nErrors = nErrors + 1;\r\n sMessage = 'Subset %cSubset% in dimension %sDimName% could not be deleted. It may be used in another view.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n EndIf;\r\n ElseIf( pMode = 1 );\r\n # pMode=1, \"direct\" deletion\r\n SubsetDestroy( sDimName, cSubset );\r\n EndIf;\r\n EndIf;\r\n i = i + 1;\r\n sDimName = TabDim( pCube, i );\r\n End;\r\n\r\nEndIf;", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.cube.viewandsubsets.delete', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n\t 'pCube', '', 'pView', '', 'pSub', '', 'pMode', 1\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process deletes a view and all subsets of the same name.\r\n\r\n# Use case: \r\n# 1. In production environment used in Epilog to remove view & subsets used for processing.\r\n# 2. In development/prototyping to manually clean up views & subsets. \r\n\r\n# Note:\r\n# * Lists and wildcards are not supported in this process\r\n# * A valid cube name pCube is mandatory otherwise the process will abort. \r\n# * A valid view name pView is mandatory otherwise the process will abort.\r\n# * The matching assumption is based on **name**. Subsets of the same name as the view will be deleted (whether they were assigned to the view or not).\r\n# * pMode 0 = Delete views and **indirectly** delete subsets via bedrock process call. If a subset cannot be deleted the process will continue and exit with minor error status.\r\n# * pMode 1 = Delete views and **directly** delete subsets via SubsetDestroy function. If a subset cannot be deleted the process will abort with major error status.\r\n# * pMode 2 = Delete views only and leave subsets as is.\r\n#EndRegion @DOC\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncMsgInfoLevel = 'INFO';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pCube:%pCube%, pView:%pView%, pSub:%pSub%, pMode:%pMode%.' ; \r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSubset = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\nsMessage = '';\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pCube\": null,\r\n \"pSub\": \"*\",\r\n \"pView\": \"\",\r\n \"pLogOutput\": 0,\r\n \"pMode\": 1,\r\n \"pStrictErrorHandling\": 0\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pCube\": '|StringToJson ( pCube )|',\r\n \"pSub\": '|StringToJson ( pSub )|',\r\n \"pView\": '|StringToJson ( pView )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pMode\": '|NumberToString( pMode )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npCube = JsonToString( JsonGet( pJson, 'pCube' ) );\r\npSub = JsonToString( JsonGet( pJson, 'pSub' ) );\r\npView = JsonToString( JsonGet( pJson, 'pView' ) );\r\n# Numeric Parameters\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npMode = StringToNumber( JsonToString( JsonGet( pJson, 'pMode' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\n### Validate Paramters ##\r\nIF( pMode <> 0 & pMode <> 1 & pMode <> 2 );\r\n sMessage = 'Invailid mode value provided %pMode%. Do not destroy views or subsets.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nENDIF;\r\n\r\nIf( Trim( pCube ) @= '' );\r\n sMessage = 'No cube specified.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( CubeExists( pCube ) = 0 ); \r\n sMessage = Expand( 'Invalid cube specified: %pCube%.' );\r\n nErrors = 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate pView \r\nIf( Trim( pView ) @= '' );\r\n sMessage = 'No view specified.';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( ViewExists(pCube, pView ) = 0 ); \r\n sMessage = Expand('There is no view :%pView% in %pCube% cube.') ;\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElse;\r\n cView = Trim( pView );\r\nEndIf;\r\n\r\n# Validate psubset\r\nIf( pSub @= '' );\r\n cSubset = Trim( pView );\r\nElse;\r\n cSubset = Trim( pSub );\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors > 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n## Clean up view\r\nViewDestroy( pCube, cView );\r\n\r\n## Clean up subsets\r\nIf( pMode <= 1 );\r\n\r\n nDimCount = 0;\r\n i = 1;\r\n sDimName = TabDim( pCube, i );\r\n While( sDimName @<> '' );\r\n If( SubsetExists ( sDimName, cSubset ) = 1 );\r\n If( pMode = 0 );\r\n # \"indirect\" deletion\r\n nRet = ExecuteProcess( '}bedrock.hier.sub.delete',\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pLogOutput', pLogOutput,\r\n \t'pDim', sDimName,\r\n \t'pHier','',\r\n \t'pSub', cSubset,\r\n \t'pDelim', If( Scan( '&', cSubset ) = 0, '&', ':' ),\r\n \t'pMode', 0\r\n );\r\n If( pLogOutput >= 1 & nRet <> ProcessExitNormal() );\r\n nErrors = nErrors + 1;\r\n sMessage = 'Subset %cSubset% in dimension %sDimName% could not be deleted. It may be used in another view.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n EndIf;\r\n ElseIf( pMode = 1 );\r\n # pMode=1, \"direct\" deletion\r\n SubsetDestroy( sDimName, cSubset );\r\n EndIf;\r\n EndIf;\r\n i = i + 1;\r\n sDimName = TabDim( pCube, i );\r\n End;\r\n\r\nEndIf;", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully deleted views and subsets for cube %pCube%.' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n### End Epilog ###", @@ -10,41 +10,47 @@ "Type": "None" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pCube", - "Prompt": "REQUIRED: Cube Name", + "Prompt": "REQUIRED: Cube name", "Value": "", "Type": "String" }, { "Name": "pView", - "Prompt": "REQUIRED: View Name", + "Prompt": "OPTIONAL: View name (Default = pSubset )", "Value": "", "Type": "String" }, { "Name": "pSub", - "Prompt": "OPTIONAL: Subset Name (will default to pView if left blank)", - "Value": "", + "Prompt": "OPTIONAL: View name (Default = pView )", + "Value": "*", "Type": "String" }, { "Name": "pMode", - "Prompt": "REQUIRED: Delete temporary view and Subset (0 = Delete View and Subsets indirectly 1 = Delete View and Subsets directly 2 = Delete View only )", + "Prompt": "OPTIONAL: Delete temporary view and subsets (0 = Retain View and Subsets, 1 = Delete View and Subsets, 2 = Delete View only. Default = 1)", "Value": 1, "Type": "Numeric" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [], diff --git a/bedrock_processes_json/}bedrock.dim.attr.create.json b/bedrock_processes_json/}bedrock.dim.attr.create.json index e9e6822..9695751 100644 --- a/bedrock_processes_json/}bedrock.dim.attr.create.json +++ b/bedrock_processes_json/}bedrock.dim.attr.create.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.dim.attr.create", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.dim.attr.create', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pDim', '', 'pAttr', '',\r\n \t'pPrevAttr', '', 'pAttrType', '',\r\n \t'pDelim', '&'\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process can insert one or more attributes in one or more specified dimensions. \r\n\r\n# Use case: Intended for development/prototyping.\r\n# 1/ Add multiple dimension attributes.\r\n\r\n# Note:\r\n# Delimited lists and/or wild card(*) are acceptable for pDim & pAttr.\r\n# Naturally, valid dimension name(s) (pDim) are mandatory otherwise the process will abort.\r\n# Known limitation: This process can insert multiple attributes to multiple dimensions but only for a single attribute type.\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent= 'Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'User:%cUserName% Process:%cThisProcName% run with parameters pDim:%pDim%, pPrevAttr:%pPrevAttr%, pAttr:%pAttr%, pAttrType:%pAttrType%, pDelim:%pDelim%.'; \r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\n# Validate dimension\r\nIf( Trim( pDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate attribute\r\nIF( Trim( pAttr ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No attribute specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate attribute type\r\nIF( Trim( pAttrType ) @= '' );\r\n pAttrType = 'S';\r\nENDIF;\r\n\r\npAttrType = Upper( SubSt( pAttrType, 1, 1 ) );\r\nIf( pAttrType @<> 'A' & pAttrType @<> 'S' & pAttrType @<> 'N' );\r\n nErrors = 1;\r\n sMessage = 'Invalid attribute type specified: ' | pAttrType | '. Defaulted to String type';\r\n LogOutput( 'INFO', Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate previous attribute\r\nIf( DimIx( '}ElementAttributes_' | pDim, pPrevAttr ) = 0 % pPrevAttr @= pAttr );\r\n pPrevAttr = '';\r\nEndIf;\r\n\r\n# If blank delimiter specified then convert to default\r\nIf( pDelim @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n# Loop through dimensions in pDim and attributes in pAttr\r\nsDims = pDim;\r\nnDimDelimiterIndex = 1;\r\n# Get 1st dimension\r\nWhile( nDimDelimiterIndex <> 0 );\r\n # Extract 1st dimension > sDim\r\n nDimDelimiterIndex = Scan( pDelim, sDims );\r\n If( nDimDelimiterIndex = 0 );\r\n sDim = sDims;\r\n Else;\r\n sDim = Trim( SubSt( sDims, 1, nDimDelimiterIndex - 1 ) );\r\n sDims = Trim( Subst( sDims, nDimDelimiterIndex + Long(pDelim), Long( sDims ) ) );\r\n EndIf;\r\n \r\n # Check if sDim has wildcard\r\n If( Scan( '*', sDim ) = 0);\r\n # Validate dimension\r\n If( DimensionExists(sDim) = 0 );\r\n nErrors = 1;\r\n sMessage = Expand( 'Dimension \"%sDim%\" does not exist.' );\r\n LogOutput( 'ERROR', Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n Else;\r\n # Loop through attributes in pAttr \r\n sAttrs = pAttr;\r\n nDelimiterIndex = 1;\r\n sAttrDim = '}ElementAttributes_'|sDim ;\r\n While( nDelimiterIndex <> 0 );\r\n \r\n nDelimiterIndex = Scan( pDelim, sAttrs );\r\n If( nDelimiterIndex = 0 );\r\n sAttr = sAttrs;\r\n Else;\r\n sAttr = Trim( SubSt( sAttrs, 1, nDelimiterIndex - 1 ) );\r\n sAttrs = Trim( Subst( sAttrs, nDelimiterIndex + Long(pDelim), Long( sAttrs ) ) );\r\n EndIf;\r\n \r\n # Check to see if attribute already exists.\r\n If( Dimix( sAttrDim , sAttr ) = 1 );\r\n nErrors = 1;\r\n sMessage = 'Attribute ' | sAttr | ' already exist in dimension ' | sDim;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n Else;\r\n AttrInsert( sDim , pPrevAttr , sAttr , pAttrType ) ;\r\n If( pLogOutput = 1 );\r\n LogOutput( 'INFO', Expand( 'Attribute \"%sAttr%\" added to dimension %sDim%.' ) );\r\n EndIf;\r\n Endif;\r\n End;\r\n EndIf; \r\n Else;\r\n # Create subset using Wildcard to loop through dimensions in pDim with wildcard\r\n sDimExp = '\"'|sDim|'\"';\r\n sMdx = '{TM1FILTERBYPATTERN( EXCEPT ( TM1SUBSETALL( [}Dimensions] ) , TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) , \"*:*\") ) ,'| sDimExp | ')}';\r\n If( SubsetExists( '}Dimensions' , cTempSub ) = 1 );\r\n # If a delimited list of attr names includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( '}Dimensions' , cTempSub, sMDX );\r\n Else;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSub, sMDX, '}Dimensions' , 1 );\r\n EndIf;\r\n \r\n # Loop through dimensions in subset created based on wildcard\r\n nCountDim = SubsetGetSize( '}Dimensions' , cTempSub );\r\n While( nCountDim >= 1 );\r\n \r\n sDim = SubsetGetElementName( '}Dimensions' , cTempSub, nCountDim );\r\n # Validate dimension name\r\n If( DimensionExists(sDim) = 0 );\r\n nErrors = 1;\r\n sMessage = Expand( 'Dimension \"%sDim%\" does not exist.' );\r\n LogOutput( 'ERROR', Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n Else;\r\n # Loop through attributes in pAttr \r\n sAttrs = pAttr;\r\n nDelimiterIndex = 1;\r\n sAttrDim = '}ElementAttributes_'|sDim ;\r\n While( nDelimiterIndex <> 0 );\r\n \r\n nDelimiterIndex = Scan( pDelim, sAttrs );\r\n If( nDelimiterIndex = 0 );\r\n sAttr = sAttrs;\r\n Else;\r\n sAttr = Trim( SubSt( sAttrs, 1, nDelimiterIndex - 1 ) );\r\n sAttrs = Trim( Subst( sAttrs, nDelimiterIndex + Long(pDelim), Long( sAttrs ) ) );\r\n EndIf;\r\n \r\n # Check to see if attribute already exists.\r\n If( Dimix( sAttrDim , sAttr ) = 1 );\r\n nErrors = 1;\r\n sMessage = 'Attribute ' | sAttr | ' already exist in dimension ' | sDim;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n Else;\r\n AttrInsert( sDim , pPrevAttr , sAttr , pAttrType ) ;\r\n If( pLogOutput = 1 );\r\n LogOutput( 'INFO', Expand( 'Attribute \"%sAttr%\" added to dimension %sDim%.' ) );\r\n EndIf;\r\n Endif;\r\n End; \r\n EndIf;\r\n \r\n nCountDim = nCountDim - 1;\r\n End;\r\n EndIf;\r\n \r\n \r\nEnd;\r\n\r\n### End Prolog ###", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.dim.attr.create', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pDim', '', 'pAttr', '',\r\n \t'pPrevAttr', '', 'pAttrType', '',\r\n \t'pDelim', '&'\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process can insert one or more attributes in one or more specified dimensions. \r\n\r\n# Use case: Intended for development/prototyping.\r\n# 1/ Add multiple dimension attributes.\r\n\r\n# Note:\r\n# Delimited lists and/or wild card(*) are acceptable for pDim & pAttr.\r\n# Naturally, valid dimension name(s) (pDim) are mandatory otherwise the process will abort.\r\n# Known limitation: This process can insert multiple attributes to multiple dimensions but only for a single attribute type.\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent= 'Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'User:%cUserName% Process:%cThisProcName% run with parameters pDim:%pDim%, pPrevAttr:%pPrevAttr%, pAttr:%pAttr%, pAttrType:%pAttrType%, pDelim:%pDelim%.';\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pAttr\": null,\r\n \"pAttrType\": \"S\",\r\n \"pDelim\": \"&\",\r\n \"pDim\": null,\r\n \"pPrevAttr\": \"\",\r\n \"pLogOutput\": 0,\r\n \"pStrictErrorHandling\": 0\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pAttr\": '|StringToJson ( pAttr )|',\r\n \"pAttrType\": '|StringToJson ( pAttrType )|',\r\n \"pDelim\": '|StringToJson ( pDelim )|',\r\n \"pDim\": '|StringToJson ( pDim )|',\r\n \"pPrevAttr\": '|StringToJson ( pPrevAttr )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npAttr = JsonToString( JsonGet( pJson, 'pAttr' ) );\r\npAttrType = JsonToString( JsonGet( pJson, 'pAttrType' ) );\r\npDelim = JsonToString( JsonGet( pJson, 'pDelim' ) );\r\npDim = JsonToString( JsonGet( pJson, 'pDim' ) );\r\npPrevAttr = JsonToString( JsonGet( pJson, 'pPrevAttr' ) );\r\n# Numeric Parameters\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\n# Validate dimension\r\nIf( Trim( pDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate attribute\r\nIF( Trim( pAttr ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No attribute specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate attribute type\r\nIF( Trim( pAttrType ) @= '' );\r\n pAttrType = 'S';\r\nENDIF;\r\n\r\npAttrType = Upper( SubSt( pAttrType, 1, 1 ) );\r\nIf( pAttrType @<> 'A' & pAttrType @<> 'S' & pAttrType @<> 'N' );\r\n nErrors = 1;\r\n sMessage = 'Invalid attribute type specified: ' | pAttrType | '. Defaulted to String type';\r\n LogOutput( 'INFO', Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate previous attribute\r\nIf( DimIx( '}ElementAttributes_' | pDim, pPrevAttr ) = 0 % pPrevAttr @= pAttr );\r\n pPrevAttr = '';\r\nEndIf;\r\n\r\n# If blank delimiter specified then convert to default\r\nIf( pDelim @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n# Loop through dimensions in pDim and attributes in pAttr\r\nsDims = pDim;\r\nnDimDelimiterIndex = 1;\r\n# Get 1st dimension\r\nWhile( nDimDelimiterIndex <> 0 );\r\n # Extract 1st dimension > sDim\r\n nDimDelimiterIndex = Scan( pDelim, sDims );\r\n If( nDimDelimiterIndex = 0 );\r\n sDim = sDims;\r\n Else;\r\n sDim = Trim( SubSt( sDims, 1, nDimDelimiterIndex - 1 ) );\r\n sDims = Trim( Subst( sDims, nDimDelimiterIndex + Long(pDelim), Long( sDims ) ) );\r\n EndIf;\r\n \r\n # Check if sDim has wildcard\r\n If( Scan( '*', sDim ) = 0);\r\n # Validate dimension\r\n If( DimensionExists(sDim) = 0 );\r\n nErrors = 1;\r\n sMessage = Expand( 'Dimension \"%sDim%\" does not exist.' );\r\n LogOutput( 'ERROR', Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n Else;\r\n # Loop through attributes in pAttr \r\n sAttrs = pAttr;\r\n nDelimiterIndex = 1;\r\n sAttrDim = '}ElementAttributes_'|sDim ;\r\n While( nDelimiterIndex <> 0 );\r\n \r\n nDelimiterIndex = Scan( pDelim, sAttrs );\r\n If( nDelimiterIndex = 0 );\r\n sAttr = sAttrs;\r\n Else;\r\n sAttr = Trim( SubSt( sAttrs, 1, nDelimiterIndex - 1 ) );\r\n sAttrs = Trim( Subst( sAttrs, nDelimiterIndex + Long(pDelim), Long( sAttrs ) ) );\r\n EndIf;\r\n \r\n # Check to see if attribute already exists.\r\n If( Dimix( sAttrDim , sAttr ) = 1 );\r\n nErrors = 1;\r\n sMessage = 'Attribute ' | sAttr | ' already exist in dimension ' | sDim;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n Else;\r\n AttrInsert( sDim , pPrevAttr , sAttr , pAttrType ) ;\r\n If( pLogOutput = 1 );\r\n LogOutput( 'INFO', Expand( 'Attribute \"%sAttr%\" added to dimension %sDim%.' ) );\r\n EndIf;\r\n Endif;\r\n End;\r\n EndIf; \r\n Else;\r\n # Create subset using Wildcard to loop through dimensions in pDim with wildcard\r\n sDimExp = '\"'|sDim|'\"';\r\n sMdx = '{TM1FILTERBYPATTERN( EXCEPT ( TM1SUBSETALL( [}Dimensions] ) , TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) , \"*:*\") ) ,'| sDimExp | ')}';\r\n If( SubsetExists( '}Dimensions' , cTempSub ) = 1 );\r\n # If a delimited list of attr names includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( '}Dimensions' , cTempSub, sMDX );\r\n Else;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSub, sMDX, '}Dimensions' , 1 );\r\n EndIf;\r\n \r\n # Loop through dimensions in subset created based on wildcard\r\n nCountDim = SubsetGetSize( '}Dimensions' , cTempSub );\r\n While( nCountDim >= 1 );\r\n \r\n sDim = SubsetGetElementName( '}Dimensions' , cTempSub, nCountDim );\r\n # Validate dimension name\r\n If( DimensionExists(sDim) = 0 );\r\n nErrors = 1;\r\n sMessage = Expand( 'Dimension \"%sDim%\" does not exist.' );\r\n LogOutput( 'ERROR', Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n Else;\r\n # Loop through attributes in pAttr \r\n sAttrs = pAttr;\r\n nDelimiterIndex = 1;\r\n sAttrDim = '}ElementAttributes_'|sDim ;\r\n While( nDelimiterIndex <> 0 );\r\n \r\n nDelimiterIndex = Scan( pDelim, sAttrs );\r\n If( nDelimiterIndex = 0 );\r\n sAttr = sAttrs;\r\n Else;\r\n sAttr = Trim( SubSt( sAttrs, 1, nDelimiterIndex - 1 ) );\r\n sAttrs = Trim( Subst( sAttrs, nDelimiterIndex + Long(pDelim), Long( sAttrs ) ) );\r\n EndIf;\r\n \r\n # Check to see if attribute already exists.\r\n If( Dimix( sAttrDim , sAttr ) = 1 );\r\n nErrors = 1;\r\n sMessage = 'Attribute ' | sAttr | ' already exist in dimension ' | sDim;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n Else;\r\n AttrInsert( sDim , pPrevAttr , sAttr , pAttrType ) ;\r\n If( pLogOutput = 1 );\r\n LogOutput( 'INFO', Expand( 'Attribute \"%sAttr%\" added to dimension %sDim%.' ) );\r\n EndIf;\r\n Endif;\r\n End; \r\n EndIf;\r\n \r\n nCountDim = nCountDim - 1;\r\n End;\r\n EndIf;\r\n \r\n \r\nEnd;\r\n\r\n### End Prolog ###", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully created attribute %pAttr% in dimension %pDim%.' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n### End Epilog ###", @@ -10,47 +10,53 @@ "Type": "None" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pDim", - "Prompt": "REQUIRED: dimension name, parameter accepts delimited list and wildcards", + "Prompt": "REQUIRED: Delimited list of dimensions", "Value": "", "Type": "String" }, { "Name": "pAttr", - "Prompt": "REQUIRED: attribute name, parameter accepts delimited list (separate with delimiter for multiple item e.g. Type&Active )", + "Prompt": "REQUIRED: Delimited list of attribute names", "Value": "", "Type": "String" }, { "Name": "pPrevAttr", - "Prompt": "OPTIONAL: insert position (previous attribute) (Defaults to blank)", + "Prompt": "OPTIONAL: Insert position", "Value": "", "Type": "String" }, { "Name": "pAttrType", - "Prompt": "OPTIONAL: attribute type (e.g. A, S or N. If blank then assumed to be type=string)", - "Value": "", + "Prompt": "OPTIONAL: Attribute type ('A', 'S', or 'N'. Default = 'S')", + "Value": "S", "Type": "String" }, { "Name": "pDelim", - "Prompt": "OPTIONAL: delimiter character for attribute list. (Defaults to & if blank)", + "Prompt": "OPTIONAL: Delimiter for list parameters (Default = '&')", "Value": "&", "Type": "String" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [], diff --git a/bedrock_processes_json/}bedrock.dim.attr.delete.json b/bedrock_processes_json/}bedrock.dim.attr.delete.json index 8723a9e..df6ca56 100644 --- a/bedrock_processes_json/}bedrock.dim.attr.delete.json +++ b/bedrock_processes_json/}bedrock.dim.attr.delete.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.dim.attr.delete", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.dim.attr.delete', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n\t 'pDim', '', 'pAttr', '', 'pDelim', '&', 'pCtrlObj', 0\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process can delete one or more attributes in one or more specified dimensions.\r\n#\r\n# Use case: Intended for development/prototyping.\r\n# 1. Clean up unused dimension attributes before going to production\r\n#\r\n# Note:\r\n# * Delimited lists and/or wild card(*) are acceptable for pDim & pAttr\r\n# * Multi-character wildcard \"*\" value for pAttr is evaluated as \"ALL\"\r\n# * You cannot specify \"*\" for **both** pDim and pAttr!\r\n#\r\n# Warning:\r\n# 1. As the process accepts wildcards USE WITH GREAT CARE! As if using wildcards for dimensions and attributes any matching attributes \r\n# in any matching dimensions will be removed from the system.\r\n# 2. Multi-character wildcard \"*\" value for pAttr is evaluated as \"ALL\". Setting pAttr to \"*\" will delete all attributes in the spacified dimension.\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncMsgInfoContent = 'User:%cUserName% Process:%cThisProcName% Message:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pAttr:%pAttr%, pDelim:%pDelim%, pCtrlObj:%pCtrlObj%.'; \r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\n## Validate dimension\r\nIf( (Trim( pDim ) @= 'ALL' & Trim( pAttr ) @= 'ALL') % (Trim( pDim ) @= '*' & Trim( pAttr ) @= 'ALL') % (Trim( pDim ) @= 'ALL' & Trim( pAttr ) @= '*') % (Trim( pDim ) @= '*' & Trim( pAttr ) @= '*') );\r\n nErrors = 1;\r\n sMessage = 'Deleting all attrbitutes from all dimensions is not supported.';\r\n LogOutput( 'ERROR', Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nIf( Trim( pDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No dimension specified.';\r\n LogOutput( 'ERROR', Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate attribute\r\nIf( Trim( pAttr ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No attribute specified.';\r\n LogOutput( 'ERROR', Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# If blank delimiter specified then convert to default\r\nIf( pDelim @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors > 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n# Loop through dimensions in pDim and attributes in pAttr\r\nsDims = pDim;\r\nnDimDelimiterIndex = 1;\r\nsMdx = '';\r\n# Get 1st dimension\r\nWhile( nDimDelimiterIndex <> 0 );\r\n # Extract 1st dimension > sDim\r\n nDimDelimiterIndex = Scan( pDelim, sDims );\r\n If( nDimDelimiterIndex = 0 );\r\n sDim = sDims;\r\n Else;\r\n sDim = Trim( SubSt( sDims, 1, nDimDelimiterIndex - 1 ) );\r\n sDims = Trim( Subst( sDims, nDimDelimiterIndex + Long(pDelim), Long( sDims ) ) );\r\n EndIf;\r\n \r\n # Create subset of dimensions using Wildcard to loop through dimensions in pDim with wildcard\r\n sDimExp = '\"'|sDim|'\"';\r\n IF( pCtrlObj = 1 );\r\n sMdxPart = '{TM1FILTERBYPATTERN( EXCEPT( TM1SUBSETALL( [}Dimensions] ) , TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) , \"*:*\") ) ,'| sDimExp | ')}';\r\n ELSE;\r\n sMdxPart = '{TM1FILTERBYPATTERN( EXCEPT( EXCEPT( TM1SUBSETALL( [}Dimensions] ) , TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) , \"*:*\") ) , TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) , \"}*\" ) ) ,'| sDimExp | ')}'; \r\n ENDIF;\r\n IF( sMdx @= ''); \r\n sMdx = sMdxPart; \r\n ELSE;\r\n sMdx = sMdx | ' + ' | sMdxPart;\r\n ENDIF;\r\n \r\n If( SubsetExists( '}Dimensions' , cTempSub ) = 1 );\r\n # If a delimited list of dim names includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( '}Dimensions' , cTempSub, sMDX );\r\n Else;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSub, sMDX, '}Dimensions' , 1 );\r\n EndIf;\r\n \r\n # Loop through dimensions in subset created based on wildcard\r\n nCountDim = SubsetGetSize( '}Dimensions' , cTempSub );\r\n While( nCountDim >= 1 );\r\n sDim = SubsetGetElementName( '}Dimensions' , cTempSub, nCountDim );\r\n # Validate dimension name\r\n If( DimensionExists(sDim) = 0 );\r\n nErrors = 1;\r\n sMessage = Expand( 'Dimension %sDim% does not exist.' );\r\n LogOutput( 'ERROR', Expand( cMsgErrorContent ) );\r\n Else;\r\n If( pLogOutput = 1 );\r\n sMessage = Expand( 'Dimension %sDim% being processed....' );\r\n LogOutput( 'INFO', Expand( cMsgInfoContent ) );\r\n EndIf;\r\n # Loop through attributes in pAttr \r\n sAttrs = pAttr;\r\n nDelimiterIndexA = 1;\r\n sAttrDim = '}ElementAttributes_'|sDim ;\r\n sMdxAttr = '';\r\n While( nDelimiterIndexA <> 0 );\r\n\r\n nDelimiterIndexA = Scan( pDelim, sAttrs );\r\n If( nDelimiterIndexA = 0 );\r\n sAttr = sAttrs;\r\n Else;\r\n sAttr = Trim( SubSt( sAttrs, 1, nDelimiterIndexA - 1 ) );\r\n sAttrs = Trim( Subst( sAttrs, nDelimiterIndexA + Long(pDelim), Long( sAttrs ) ) );\r\n EndIf;\r\n\r\n # Validate if sDim has attributes\r\n IF( DimensionExists( '}ElementAttributes_'| sDim ) = 0 );\r\n sMessage = 'Dimension ' | sDim | ' has no attributes.';\r\n LogOutput( 'INFO' , Expand( cMsgInfoContent ) );\r\n ElseIf( sAttr @= '*' );\r\n # Delete attribute cube and dimension if pAttr is blank or set to ALL\r\n CubeDestroy( sAttrDim );\r\n DimensionDestroy( sAttrDim );\r\n Else;\r\n # Create subset of attributes using Wildcard to loop through attributes in pAttr with wildcard\r\n sAttr = '\"'|sAttr|'\"';\r\n sMdxAttrPart = '{TM1FILTERBYPATTERN( {TM1SUBSETALL([ ' |sAttrDim| '])},'| sAttr| ')}';\r\n IF( sMdxAttr @= ''); \r\n sMdxAttr = sMdxAttrPart; \r\n ELSE;\r\n sMdxAttr = sMdxAttr | ' + ' | sMdxAttrPart;\r\n ENDIF;\r\n If( SubsetExists( sAttrDim, cTempSub ) = 1 );\r\n # If a delimited list of attr names includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( sAttrDim, cTempSub, sMdxAttr );\r\n Else;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSub, sMdxAttr, sAttrDim, 1 );\r\n EndIf;\r\n \r\n # Loop through subset of attributes created based on wildcard\r\n nCountAttr = SubsetGetSize( sAttrDim, cTempSub );\r\n While( nCountAttr >= 1 );\r\n sAttr = SubsetGetElementName( sAttrDim, cTempSub, nCountAttr );\r\n # Validate attribute name in sDim\r\n If( Dimix( sAttrDim , sAttr ) = 0 );\r\n sMessage = Expand('The %sAttr% attribute does NOT exist in the %sDim% dimension.');\r\n LogOutput( 'INFO' , Expand( cMsgInfoContent ) );\r\n Else;\r\n AttrDelete( sDim , sAttr ) ;\r\n If( pLogOutput = 1 );\r\n LogOutput( 'INFO', Expand( 'Attribute \"%sAttr%\" deleted from dimension %sDim%.' ) );\r\n EndIf;\r\n Endif;\r\n nCountAttr = nCountAttr - 1;\r\n End;\r\n Endif;\r\n \r\n End; \r\n EndIf;\r\n \r\n nCountDim = nCountDim - 1;\r\n End;\r\nEnd;\r\n\r\n### End Prolog ###", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.dim.attr.delete', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n\t 'pDim', '', 'pAttr', '', 'pDelim', '&', 'pCtrlObj', 0\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process can delete one or more attributes in one or more specified dimensions.\r\n#\r\n# Use case: Intended for development/prototyping.\r\n# 1. Clean up unused dimension attributes before going to production\r\n#\r\n# Note:\r\n# * Delimited lists and/or wild card(*) are acceptable for pDim & pAttr\r\n# * Multi-character wildcard \"*\" value for pAttr is evaluated as \"ALL\"\r\n# * You cannot specify \"*\" for **both** pDim and pAttr!\r\n#\r\n# Warning:\r\n# 1. As the process accepts wildcards USE WITH GREAT CARE! As if using wildcards for dimensions and attributes any matching attributes \r\n# in any matching dimensions will be removed from the system.\r\n# 2. Multi-character wildcard \"*\" value for pAttr is evaluated as \"ALL\". Setting pAttr to \"*\" will delete all attributes in the spacified dimension.\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncMsgInfoContent = 'User:%cUserName% Process:%cThisProcName% Message:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pAttr:%pAttr%, pDelim:%pDelim%, pCtrlObj:%pCtrlObj%.';\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pAttr\": null,\r\n \"pDelim\": \"&\",\r\n \"pDim\": null,\r\n \"pCtrlObj\": 0,\r\n \"pLogOutput\": 0,\r\n \"pStrictErrorHandling\": 0\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pAttr\": '|StringToJson ( pAttr )|',\r\n \"pDelim\": '|StringToJson ( pDelim )|',\r\n \"pDim\": '|StringToJson ( pDim )|',\r\n \"pCtrlObj\": '|NumberToString( pCtrlObj )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npAttr = JsonToString( JsonGet( pJson, 'pAttr' ) );\r\npDelim = JsonToString( JsonGet( pJson, 'pDelim' ) );\r\npDim = JsonToString( JsonGet( pJson, 'pDim' ) );\r\n# Numeric Parameters\r\npCtrlObj = StringToNumber( JsonToString( JsonGet( pJson, 'pCtrlObj' ) ) );\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\n## Validate dimension\r\nIf( (Trim( pDim ) @= 'ALL' & Trim( pAttr ) @= 'ALL') % (Trim( pDim ) @= '*' & Trim( pAttr ) @= 'ALL') % (Trim( pDim ) @= 'ALL' & Trim( pAttr ) @= '*') % (Trim( pDim ) @= '*' & Trim( pAttr ) @= '*') );\r\n nErrors = 1;\r\n sMessage = 'Deleting all attrbitutes from all dimensions is not supported.';\r\n LogOutput( 'ERROR', Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nIf( Trim( pDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No dimension specified.';\r\n LogOutput( 'ERROR', Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate attribute\r\nIf( Trim( pAttr ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No attribute specified.';\r\n LogOutput( 'ERROR', Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# If blank delimiter specified then convert to default\r\nIf( pDelim @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors > 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n# Loop through dimensions in pDim and attributes in pAttr\r\nsDims = pDim;\r\nnDimDelimiterIndex = 1;\r\nsMdx = '';\r\n# Get 1st dimension\r\nWhile( nDimDelimiterIndex <> 0 );\r\n # Extract 1st dimension > sDim\r\n nDimDelimiterIndex = Scan( pDelim, sDims );\r\n If( nDimDelimiterIndex = 0 );\r\n sDim = sDims;\r\n Else;\r\n sDim = Trim( SubSt( sDims, 1, nDimDelimiterIndex - 1 ) );\r\n sDims = Trim( Subst( sDims, nDimDelimiterIndex + Long(pDelim), Long( sDims ) ) );\r\n EndIf;\r\n \r\n # Create subset of dimensions using Wildcard to loop through dimensions in pDim with wildcard\r\n sDimExp = '\"'|sDim|'\"';\r\n IF( pCtrlObj = 1 );\r\n sMdxPart = '{TM1FILTERBYPATTERN( EXCEPT( TM1SUBSETALL( [}Dimensions] ) , TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) , \"*:*\") ) ,'| sDimExp | ')}';\r\n ELSE;\r\n sMdxPart = '{TM1FILTERBYPATTERN( EXCEPT( EXCEPT( TM1SUBSETALL( [}Dimensions] ) , TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) , \"*:*\") ) , TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) , \"}*\" ) ) ,'| sDimExp | ')}'; \r\n ENDIF;\r\n IF( sMdx @= ''); \r\n sMdx = sMdxPart; \r\n ELSE;\r\n sMdx = sMdx | ' + ' | sMdxPart;\r\n ENDIF;\r\n \r\n If( SubsetExists( '}Dimensions' , cTempSub ) = 1 );\r\n # If a delimited list of dim names includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( '}Dimensions' , cTempSub, sMDX );\r\n Else;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSub, sMDX, '}Dimensions' , 1 );\r\n EndIf;\r\n \r\n # Loop through dimensions in subset created based on wildcard\r\n nCountDim = SubsetGetSize( '}Dimensions' , cTempSub );\r\n While( nCountDim >= 1 );\r\n sDim = SubsetGetElementName( '}Dimensions' , cTempSub, nCountDim );\r\n # Validate dimension name\r\n If( DimensionExists(sDim) = 0 );\r\n nErrors = 1;\r\n sMessage = Expand( 'Dimension %sDim% does not exist.' );\r\n LogOutput( 'ERROR', Expand( cMsgErrorContent ) );\r\n Else;\r\n If( pLogOutput = 1 );\r\n sMessage = Expand( 'Dimension %sDim% being processed....' );\r\n LogOutput( 'INFO', Expand( cMsgInfoContent ) );\r\n EndIf;\r\n # Loop through attributes in pAttr \r\n sAttrs = pAttr;\r\n nDelimiterIndexA = 1;\r\n sAttrDim = '}ElementAttributes_'|sDim ;\r\n sMdxAttr = '';\r\n While( nDelimiterIndexA <> 0 );\r\n\r\n nDelimiterIndexA = Scan( pDelim, sAttrs );\r\n If( nDelimiterIndexA = 0 );\r\n sAttr = sAttrs;\r\n Else;\r\n sAttr = Trim( SubSt( sAttrs, 1, nDelimiterIndexA - 1 ) );\r\n sAttrs = Trim( Subst( sAttrs, nDelimiterIndexA + Long(pDelim), Long( sAttrs ) ) );\r\n EndIf;\r\n\r\n # Validate if sDim has attributes\r\n IF( DimensionExists( '}ElementAttributes_'| sDim ) = 0 );\r\n sMessage = 'Dimension ' | sDim | ' has no attributes.';\r\n LogOutput( 'INFO' , Expand( cMsgInfoContent ) );\r\n ElseIf( sAttr @= '*' );\r\n # Delete attribute cube and dimension if pAttr is blank or set to ALL\r\n CubeDestroy( sAttrDim );\r\n DimensionDestroy( sAttrDim );\r\n Else;\r\n # Create subset of attributes using Wildcard to loop through attributes in pAttr with wildcard\r\n sAttr = '\"'|sAttr|'\"';\r\n sMdxAttrPart = '{TM1FILTERBYPATTERN( {TM1SUBSETALL([ ' |sAttrDim| '])},'| sAttr| ')}';\r\n IF( sMdxAttr @= ''); \r\n sMdxAttr = sMdxAttrPart; \r\n ELSE;\r\n sMdxAttr = sMdxAttr | ' + ' | sMdxAttrPart;\r\n ENDIF;\r\n If( SubsetExists( sAttrDim, cTempSub ) = 1 );\r\n # If a delimited list of attr names includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( sAttrDim, cTempSub, sMdxAttr );\r\n Else;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSub, sMdxAttr, sAttrDim, 1 );\r\n EndIf;\r\n \r\n # Loop through subset of attributes created based on wildcard\r\n nCountAttr = SubsetGetSize( sAttrDim, cTempSub );\r\n While( nCountAttr >= 1 );\r\n sAttr = SubsetGetElementName( sAttrDim, cTempSub, nCountAttr );\r\n # Validate attribute name in sDim\r\n If( Dimix( sAttrDim , sAttr ) = 0 );\r\n sMessage = Expand('The %sAttr% attribute does NOT exist in the %sDim% dimension.');\r\n LogOutput( 'INFO' , Expand( cMsgInfoContent ) );\r\n Else;\r\n AttrDelete( sDim , sAttr ) ;\r\n If( pLogOutput = 1 );\r\n LogOutput( 'INFO', Expand( 'Attribute \"%sAttr%\" deleted from dimension %sDim%.' ) );\r\n EndIf;\r\n Endif;\r\n nCountAttr = nCountAttr - 1;\r\n End;\r\n Endif;\r\n \r\n End; \r\n EndIf;\r\n \r\n nCountDim = nCountDim - 1;\r\n End;\r\nEnd;\r\n\r\n### End Prolog ###", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully deleted attribute(s) %pAttr% from dimension(s) %pDim%.' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n### End Epilog ###\r\n", @@ -10,41 +10,47 @@ "Type": "None" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pDim", - "Prompt": "REQUIRED: dimension name, parameter accepts delimited list and wildcards(*).", + "Prompt": "REQUIRED: Delimited list of dimensions", "Value": "", "Type": "String" }, { "Name": "pAttr", - "Prompt": "REQUIRED: attribute name, parameter accepts delimited list and wildcards (* = ALL).", + "Prompt": "REQUIRED: Delimited list of attribute names", "Value": "", "Type": "String" }, { "Name": "pDelim", - "Prompt": "OPTIONAL: delimiter character for attribute list. (Defaults to & if blank)", + "Prompt": "OPTIONAL: Delimiter for list parameters (Default = '&')", "Value": "&", "Type": "String" }, { "Name": "pCtrlObj", - "Prompt": "REQUIRED: Include control dimensions (1 = include, 0 = not include)", + "Prompt": "OPTIONAL: OPTIONAL: Allow modification of control objects (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [], diff --git a/bedrock_processes_json/}bedrock.dim.attr.importfromfile.json b/bedrock_processes_json/}bedrock.dim.attr.importfromfile.json index 77793d3..188be5b 100644 --- a/bedrock_processes_json/}bedrock.dim.attr.importfromfile.json +++ b/bedrock_processes_json/}bedrock.dim.attr.importfromfile.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.dim.attr.importfromfile", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.dim.attr.importfromfile', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pDim', '', 'pSrcDir', '', 'pSrcFile', '',\r\n \t'pTitleRows', 1, 'pDelim', ',', 'pQuote', '\"'\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will create Attributes of the dimension from a file.\r\n\r\n# Use case: Intended for development/prototyping. \r\n#1/ Add multiple dimension attributes of different types.\r\n\r\n# Note:\r\n# The file format is as per the dimension export file applied to an }ElementsAttributes dimension.\r\n# Naturally, a valid diension name (pDim) is mandatory otherwise the process will abort.\r\n# Also, valid path (pSrcDir) & file name (pSrcFile) are mandatory otherwise the process will abort.\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pSrcDir:%pSrcDir%, pSrcFile:%pSrcFile%, pTitleRows:%pTitleRows%, pDelim:%pDelim%, pQuote:%pQuote%.'; \r\ncLenASCIICode = 3;\r\n\r\npDelimiter = TRIM(pDelim);\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\nnMetaDataCount = 0;\r\n\r\n### Validate Parameters ###\r\n\r\nnErrors = 0;\r\n\r\n## check operating system\r\nIf( SubSt( GetProcessErrorFileDirectory, 2, 1 ) @= ':' );\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nElseIf( Scan( '/', GetProcessErrorFileDirectory ) > 0 );\r\n sOS = 'Linux';\r\n sOSDelim = '/';\r\nElse;\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nEndIf;\r\n\r\n# Validate source dir\r\nIf(Trim( pSrcDir ) @= '' );\r\n pSrcDir = GetProcessErrorFileDirectory;\r\nEndIf;\r\nIf( SubSt( pSrcDir, Long( pSrcDir ), 1 ) @= sOSDelim );\r\n pSrcDir = SubSt( pSrcDir, 1, Long( pSrcDir ) -1 );\r\nEndIf;\r\nIf( FileExists( pSrcDir ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid source directory specified: folder does not exist.';\r\n DataSourceType = 'NULL';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\npSrcDir = pSrcDir | sOSDelim;\r\n\r\n# Validate source file\r\nsFile = pSrcDir | pSrcFile;\r\nIF ( Trim ( pSrcFile ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No source file specified.';\r\n DataSourceType = 'NULL';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( FileExists( sFile ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid path or source file specified: It does not exist.';\r\n DataSourceType = 'NULL';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate dimension\r\nIf( Trim( pDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( DimensionExists( pDim ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Dimension: ' | pDim | ' does not exist on server.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate file delimiter & quote character\r\nIf( pDelimiter @= '' );\r\n pDelimiter = ',';\r\nElse;\r\n # If length of pDelimiter is exactly 3 chars and each of them is decimal digit, then the pDelimiter is entered as ASCII code\r\n nValid = 0;\r\n If ( LONG(pDelimiter) = cLenASCIICode );\r\n nChar = 1;\r\n While ( nChar <= cLenASCIICode );\r\n If( CODE( pDelimiter, nChar )>=CODE( '0', 1 ) & CODE( pDelimiter, nChar )<=CODE( '9', 1 ) );\r\n nValid = 1;\r\n Else;\r\n nValid = 0;\r\n EndIf;\r\n nChar = nChar + 1;\r\n End;\r\n EndIf;\r\n If ( nValid<>0 );\r\n pDelimiter=CHAR(StringToNumber( pDelimiter ));\r\n Else;\r\n pDelimiter = SubSt( Trim( pDelimiter ), 1, 1 );\r\n EndIf;\r\nEndIf;\r\nIf( pQuote @= '' );\r\n ## Use no quote character \r\nElse;\r\n # If length of pQuote is exactly 3 chars and each of them is decimal digit, then the pQuote is entered as ASCII code\r\n nValid = 0;\r\n If ( LONG(pQuote) = cLenASCIICode );\r\n nChar = 1;\r\n While ( nChar <= cLenASCIICode );\r\n If( CODE( pQuote, nChar ) >= CODE( '0', 1 ) & CODE( pQuote, nChar ) <= CODE( '9', 1 ) );\r\n nValid = 1;\r\n Else;\r\n nValid = 0;\r\n EndIf;\r\n nChar = nChar + 1;\r\n End;\r\n EndIf;\r\n If ( nValid<>0 );\r\n pQuote=CHAR(StringToNumber( pQuote ));\r\n Else;\r\n pQuote = SubSt( Trim( pQuote ), 1, 1 );\r\n EndIf;\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### Assign Datasource ###\r\n\r\nDataSourceType = 'CHARACTERDELIMITED';\r\nDatasourceNameForServer = sFile;\r\nDatasourceNameForClient = sFile;\r\nDatasourceASCIIHeaderRecords= pTitleRows;\r\nDatasourceASCIIDelimiter = pDelimiter;\r\nDatasourceASCIIQuoteCharacter= pQuote;\r\n\r\n### End Prolog ###", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.dim.attr.importfromfile', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pDim', '', 'pSrcDir', '', 'pSrcFile', '',\r\n \t'pTitleRows', 1, 'pDelim', ',', 'pQuote', '\"'\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will create Attributes of the dimension from a file.\r\n\r\n# Use case: Intended for development/prototyping. \r\n#1/ Add multiple dimension attributes of different types.\r\n\r\n# Note:\r\n# The file format is as per the dimension export file applied to an }ElementsAttributes dimension.\r\n# Naturally, a valid diension name (pDim) is mandatory otherwise the process will abort.\r\n# Also, valid path (pSrcDir) & file name (pSrcFile) are mandatory otherwise the process will abort.\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pSrcDir:%pSrcDir%, pSrcFile:%pSrcFile%, pTitleRows:%pTitleRows%, pDelim:%pDelim%, pQuote:%pQuote%.'; \r\ncLenASCIICode = 3;\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pDelim\": \"&\",\r\n \"pDim\": null,\r\n \"pQuote\": \"\"\",\r\n \"pSrcDir\": \"\",\r\n \"pSrcFile\": \"\",\r\n \"pLogOutput\": 0,\r\n \"pStrictErrorHandling\": 0,\r\n \"pTitleRows\": 1\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pDelim\": '|StringToJson ( pDelim )|',\r\n \"pDim\": '|StringToJson ( pDim )|',\r\n \"pQuote\": '|StringToJson ( pQuote )|',\r\n \"pSrcDir\": '|StringToJson ( pSrcDir )|',\r\n \"pSrcFile\": '|StringToJson ( pSrcFile )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|',\r\n \"pTitleRows\": '|NumberToString( pTitleRows )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npDelim = JsonToString( JsonGet( pJson, 'pDelim' ) );\r\npDim = JsonToString( JsonGet( pJson, 'pDim' ) );\r\npQuote = JsonToString( JsonGet( pJson, 'pQuote' ) );\r\npSrcDir = JsonToString( JsonGet( pJson, 'pSrcDir' ) );\r\npSrcFile = JsonToString( JsonGet( pJson, 'pSrcFile' ) );\r\n# Numeric Parameters\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\npTitleRows = StringToNumber( JsonToString( JsonGet( pJson, 'pTitleRows' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\npDelimiter = TRIM(pDelim);\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\nnMetaDataCount = 0;\r\n\r\n### Validate Parameters ###\r\n\r\nnErrors = 0;\r\n\r\n## check operating system\r\nIf( SubSt( GetProcessErrorFileDirectory, 2, 1 ) @= ':' );\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nElseIf( Scan( '/', GetProcessErrorFileDirectory ) > 0 );\r\n sOS = 'Linux';\r\n sOSDelim = '/';\r\nElse;\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nEndIf;\r\n\r\n# Validate source dir\r\nIf(Trim( pSrcDir ) @= '' );\r\n pSrcDir = GetProcessErrorFileDirectory;\r\nEndIf;\r\nIf( SubSt( pSrcDir, Long( pSrcDir ), 1 ) @= sOSDelim );\r\n pSrcDir = SubSt( pSrcDir, 1, Long( pSrcDir ) -1 );\r\nEndIf;\r\nIf( FileExists( pSrcDir ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid source directory specified: folder does not exist.';\r\n DataSourceType = 'NULL';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\npSrcDir = pSrcDir | sOSDelim;\r\n\r\n# Validate source file\r\nsFile = pSrcDir | pSrcFile;\r\nIF ( Trim ( pSrcFile ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No source file specified.';\r\n DataSourceType = 'NULL';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( FileExists( sFile ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid path or source file specified: It does not exist.';\r\n DataSourceType = 'NULL';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate dimension\r\nIf( Trim( pDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( DimensionExists( pDim ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Dimension: ' | pDim | ' does not exist on server.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate file delimiter & quote character\r\nIf( pDelimiter @= '' );\r\n pDelimiter = ',';\r\nElse;\r\n # If length of pDelimiter is exactly 3 chars and each of them is decimal digit, then the pDelimiter is entered as ASCII code\r\n nValid = 0;\r\n If ( LONG(pDelimiter) = cLenASCIICode );\r\n nChar = 1;\r\n While ( nChar <= cLenASCIICode );\r\n If( CODE( pDelimiter, nChar )>=CODE( '0', 1 ) & CODE( pDelimiter, nChar )<=CODE( '9', 1 ) );\r\n nValid = 1;\r\n Else;\r\n nValid = 0;\r\n EndIf;\r\n nChar = nChar + 1;\r\n End;\r\n EndIf;\r\n If ( nValid<>0 );\r\n pDelimiter=CHAR(StringToNumber( pDelimiter ));\r\n Else;\r\n pDelimiter = SubSt( Trim( pDelimiter ), 1, 1 );\r\n EndIf;\r\nEndIf;\r\nIf( pQuote @= '' );\r\n ## Use no quote character \r\nElse;\r\n # If length of pQuote is exactly 3 chars and each of them is decimal digit, then the pQuote is entered as ASCII code\r\n nValid = 0;\r\n If ( LONG(pQuote) = cLenASCIICode );\r\n nChar = 1;\r\n While ( nChar <= cLenASCIICode );\r\n If( CODE( pQuote, nChar ) >= CODE( '0', 1 ) & CODE( pQuote, nChar ) <= CODE( '9', 1 ) );\r\n nValid = 1;\r\n Else;\r\n nValid = 0;\r\n EndIf;\r\n nChar = nChar + 1;\r\n End;\r\n EndIf;\r\n If ( nValid<>0 );\r\n pQuote=CHAR(StringToNumber( pQuote ));\r\n Else;\r\n pQuote = SubSt( Trim( pQuote ), 1, 1 );\r\n EndIf;\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### Assign Datasource ###\r\n\r\nDataSourceType = 'CHARACTERDELIMITED';\r\nDatasourceNameForServer = sFile;\r\nDatasourceNameForClient = sFile;\r\nDatasourceASCIIHeaderRecords= pTitleRows;\r\nDatasourceASCIIDelimiter = pDelimiter;\r\nDatasourceASCIIQuoteCharacter= pQuote;\r\n\r\n### End Prolog ###", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n## Metatdata Count\r\nnMetaDataCount = nMetaDataCount + 1;\r\n\r\n### Write data from source file to target dimension ###\r\nsAttrType = Upper(SubSt( vAttrType, 1, 1 ));\r\n\r\n### Validate Record ###\r\nIF(\r\n sAttrType @= 'A' %\r\n sAttrType @= 'N' %\r\n sAttrType @= 'S' );\r\n ## Continute\r\nELSE;\r\n sMessage = 'Invalid attribute type.';\r\n ITEMSKIP;\r\nENDIF;\r\n\r\nAttrInsert( pDim, '', vAttr, sAttrType );\r\n\r\n### End Metadata ###", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully created attributes in %pDim% from file %pSrcFile%.' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n### End Epilog ###", @@ -18,53 +18,59 @@ "dataSourceNameForServer": "D:/TM1Models/Bedrock.v4/Data/Attribute.csv" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pDim", - "Prompt": "REQUIRED: dimension name", + "Prompt": "REQUIRED: Delimited list of dimensions", "Value": "", "Type": "String" }, { "Name": "pSrcDir", - "Prompt": "REQUIRED: Source Directory", + "Prompt": "OPTIONAL: File directory (Default = GetProcessErrorFileDirectory)", "Value": "", "Type": "String" }, { "Name": "pSrcFile", - "Prompt": "REQUIRED: Source File Name", + "Prompt": "OPTIONAL: File name (Default = pCube | '_Export.csv')", "Value": "", "Type": "String" }, { "Name": "pTitleRows", - "Prompt": "OPTIONAL: Number of Title Rows to Skip (default = 1)", + "Prompt": "OPTIONAL: Number of title rows to skip (Default = 1)", "Value": 1, "Type": "Numeric" }, { "Name": "pDelim", - "Prompt": "OPTIONAL: File Delimiter Character (Default=comma, exactly 3 digits = ASCII code)", - "Value": ",", + "Prompt": "OPTIONAL: Delimiter for list parameters (Default = '&')", + "Value": "&", "Type": "String" }, { "Name": "pQuote", - "Prompt": "OPTIONAL: Quote Character (Accepts empty quote, exactly 3 digits = ASCII code)", + "Prompt": "OPTIONAL: Quote character (2 or 3 digits = ASCII code. Default = '\"')", "Value": "\"", "Type": "String" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [ diff --git a/bedrock_processes_json/}bedrock.dim.attr.swapalias.json b/bedrock_processes_json/}bedrock.dim.attr.swapalias.json index a979e42..24ed00f 100644 --- a/bedrock_processes_json/}bedrock.dim.attr.swapalias.json +++ b/bedrock_processes_json/}bedrock.dim.attr.swapalias.json @@ -10,28 +10,34 @@ "Type": "None" }, "Parameters": [ + { + "Name": "pDim", + "Prompt": "REQUIRED: Delimited list of dimensions", + "Value": "", + "Type": "String" + }, + { + "Name": "pAlias", + "Prompt": "REQUIRED: Alias name", + "Value": "", + "Type": "String" + }, { "Name": "pLogOutput", - "Prompt": "REQUIRED: True or False (Boolean True = 1)", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { - "Name": "pDim", - "Prompt": "REQUIRED: Dimension name", - "Value": "", - "Type": "String" - }, - { - "Name": "pAlias", - "Prompt": "REQUIRED: Alias", - "Value": "", + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters.", + "Value": "{}", "Type": "String" } ], diff --git a/bedrock_processes_json/}bedrock.dim.clone.json b/bedrock_processes_json/}bedrock.dim.clone.json index 9e6b8c4..e6acdb3 100644 --- a/bedrock_processes_json/}bedrock.dim.clone.json +++ b/bedrock_processes_json/}bedrock.dim.clone.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.dim.clone", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.dim.clone', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pSrcDim', '', 'pTgtDim', '', 'pHier', '*',\r\n \t'pAttr', 0, 'pUnwind', 0, 'pDelim', '&'\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process can clone a source dimension and all the Hierarchies.\r\n\r\n# Use case: Intended for development/prototyping.\r\n# 1/ Replicate a dimension with it's hierarchies for testing.\r\n\r\n# Note:\r\n# If the target dimension:hierarchy already exists then it will be overwritten.\r\n# Naturally, a valid source dimension name (pSrcDim) is mandatory otherwise the process will abort.\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable ('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode = 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncSubset = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = '%cThisProcName% : %sMessage% : %cUserName%';\r\ncMsgInfoContent = 'User:%cUserName% Process:%cThisProcName% Message:%sMessage%';\r\ncLogInfo = '***Parameters for Process:%cThisProcName% for pSrcDim:%pSrcDim%, pTgtDim:%pTgtDim%, pHier:%pHier%, pAttr:%pAttr%, pUnwind:%pUnwind%, pDelim:%pDelim%.';\r\ncLangDim = '}Cultures';\r\nnNumLang = DimSiz( cLangDim );\r\n\r\n## LogOutput parameters\r\nIF ( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\nIf( Scan( '*', pSrcDim )=0 & Scan( '?', pSrcDim )=0 & Scan( pDelim, pSrcDim )=0 & Scan( ':', pSrcDim ) > 0 & pHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pHier = SubSt( pSrcDim, Scan( ':', pSrcDim ) + 1, Long( pSrcDim ) );\r\n pSrcDim = SubSt( pSrcDim, 1, Scan( ':', pSrcDim ) - 1 );\r\nEndIf;\r\n\r\n## Validate dimension\r\nIF( Trim( pSrcDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No source dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIF( DimensionExists( pSrcDim ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid source dimension: ' | pSrcDim;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nIf( pTgtDim @= '' % pTgtDim @= pSrcDim );\r\n pTgtDim = pSrcDim | '_Clone';\r\nEndIf;\r\n\r\n# Validate hierarchy\r\nIF( Scan( '*', pSrcDim )=0 & Scan( '?', pSrcDim )=0 & Scan( pDelim, pSrcDim )=0 & pHier @= '');\r\n pHier = pSrcDim;\r\nElseIf( Scan( '*', pHier )=0 & Scan( '?', pHier )=0 & Scan( pDelim, pHier )=0 & pHier @<> '' & HierarchyExists(pSrcDim, pHier) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid dimension hierarchy: ' | pHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndif;\r\n\r\nIf( Trim( pHier ) @= '' );\r\n ## use same name as Dimension. Since wildcards are allowed, this is managed inside the code below\r\nEndIf;\r\n\r\n## Default delimiter\r\nIf( pDelim @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### Create target dimension ###\r\n\r\nIf(DimensionExists( pTgtDim ) = 0 );\r\n DimensionCreate( pTgtDim );\r\nElse;\r\n IF(pUnwind = 1 );\r\n nRet = ExecuteProcess('}bedrock.hier.unwind',\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pDim', pTgtDim,\r\n 'pHier', pTgtDim,\r\n 'pConsol', '*',\r\n 'pRecursive', 1\r\n );\r\n ELSEIF(pUnwind = 2 );\r\n # Do nothing;\r\n ELSE;\r\n DimensionDeleteAllElements( pTgtDim );\r\n EndIf;\r\nEndIf;\r\n\r\n### Set the target Sort Order ###\r\n# CellGetS to }DimensionProperties cube removed. Placeholder as expecting a TI function to be made available to be able to read these properties\r\n#sSortElementsType = CELLGETS( '}DimensionProperties', pSrcDim, 'SORTELEMENTSTYPE');\r\n#sSortElementsSense = CELLGETS( '}DimensionProperties', pSrcDim, 'SORTELEMENTSSENSE');\r\n#sSortComponentsType = CELLGETS( '}DimensionProperties', pSrcDim, 'SORTCOMPONENTSTYPE');\r\n#sSortComponentsSense = CELLGETS( '}DimensionProperties', pSrcDim, 'SORTCOMPONENTSSENSE');\r\n\r\n# DimensionSortOrder( pTgtDim, sSortComponentsType, sSortComponentsSense, sSortElementsType , sSortElementsSense);\r\n\r\n\r\nnSourceDimSize = DIMSIZ( pSrcDim );\r\nnIndex = 1;\r\nWHILE( nIndex <= nSourceDimSize );\r\n sElName = DIMNM( pSrcDim, nIndex);\r\n sElType = DTYPE( pSrcDim, sElName);\r\n \r\n DimensionElementInsert( pTgtDim, '', sElName, sElType );\r\n\r\n nIndex = nIndex + 1;\r\nEND;\r\n\r\n### Assign Data Source ###\r\nDatasourceNameForServer = pSrcDim;\r\nDatasourceNameForClient = pSrcDim;\r\nDataSourceType = 'SUBSET';\r\nDatasourceDimensionSubset = 'ALL';\r\n\r\n\r\n### Replicate Attributes ###\r\n# Note: DType on Attr dim returns \"AS\", \"AN\" or \"AA\" need to strip off leading \"A\"\r\nsAttrDim = '}ElementAttributes_' | pSrcDim;\r\nsAttrLoc = '}LocalizedElementAttributes_' | pSrcDim;\r\nsAttrTargetDim = '}ElementAttributes_' | pTgtDim;\r\nsAttrLocTarget = '}LocalizedElementAttributes_' | pTgtDim;\r\n\r\nIf( pAttr = 1 & DimensionExists( sAttrDim ) = 1 );\r\n nNumAttrs = DimSiz( sAttrDim );\r\n nCount = 1;\r\n While( nCount <= nNumAttrs );\r\n sAttrName = DimNm( sAttrDim, nCount );\r\n sAttCheck = SubSt( DTYPE( sAttrDim, sAttrName ), 1, 1 );\r\n IF (sAttCheck @= 'A');\r\n sAttrType = SubSt( DTYPE( sAttrDim, sAttrName ), 2, 1 );\r\n Else;\r\n sAttrType = sAttcheck;\r\n EndIf; \r\n \r\n If ( DimensionExists( sAttrTargetDim ) = 0);\r\n AttrInsert(pTgtDim,'',sAttrName,sAttrType );\r\n ElseIF(DimIx(sAttrTargetDim, sAttrName) = 0);\r\n AttrInsert(pTgtDim,'',sAttrName,sAttrType );\r\n Endif;\r\n \r\n nCount = nCount + 1;\r\n End;\r\nEndIf;\r\n\r\n\r\n### End Prolog ###", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.dim.clone', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pSrcDim', '', 'pTgtDim', '', 'pHier', '*',\r\n \t'pAttr', 0, 'pUnwind', 0, 'pDelim', '&'\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process can clone a source dimension and all the Hierarchies.\r\n\r\n# Use case: Intended for development/prototyping.\r\n# 1/ Replicate a dimension with it's hierarchies for testing.\r\n\r\n# Note:\r\n# If the target dimension:hierarchy already exists then it will be overwritten.\r\n# Naturally, a valid source dimension name (pSrcDim) is mandatory otherwise the process will abort.\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable ('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode = 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncSubset = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = '%cThisProcName% : %sMessage% : %cUserName%';\r\ncMsgInfoContent = 'User:%cUserName% Process:%cThisProcName% Message:%sMessage%';\r\ncLogInfo = '***Parameters for Process:%cThisProcName% for pSrcDim:%pSrcDim%, pTgtDim:%pTgtDim%, pHier:%pHier%, pAttr:%pAttr%, pUnwind:%pUnwind%, pDelim:%pDelim%.';\r\ncLangDim = '}Cultures';\r\nnNumLang = DimSiz( cLangDim );\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pDelim\": \"&\",\r\n \"pHier\": \"*\",\r\n \"pSrcDim\": null,\r\n \"pTgtDim\": \"\",\r\n \"pAttr\": 0,\r\n \"pLogOutput\": 0,\r\n \"pStrictErrorHandling\": 0,\r\n \"pSub\": 0,\r\n \"pUnwind\": 0\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pDelim\": '|StringToJson ( pDelim )|',\r\n \"pHier\": '|StringToJson ( pHier )|',\r\n \"pSrcDim\": '|StringToJson ( pSrcDim )|',\r\n \"pTgtDim\": '|StringToJson ( pTgtDim )|',\r\n \"pAttr\": '|NumberToString( pAttr )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|',\r\n \"pSub\": '|NumberToString( pSub )|',\r\n \"pUnwind\": '|NumberToString( pUnwind )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npDelim = JsonToString( JsonGet( pJson, 'pDelim' ) );\r\npHier = JsonToString( JsonGet( pJson, 'pHier' ) );\r\npSrcDim = JsonToString( JsonGet( pJson, 'pSrcDim' ) );\r\npTgtDim = JsonToString( JsonGet( pJson, 'pTgtDim' ) );\r\n# Numeric Parameters\r\npAttr = StringToNumber( JsonToString( JsonGet( pJson, 'pAttr' ) ) );\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\npSub = StringToNumber( JsonToString( JsonGet( pJson, 'pSub' ) ) );\r\npUnwind = StringToNumber( JsonToString( JsonGet( pJson, 'pUnwind' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n## LogOutput parameters\r\nIF ( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\nIf( Scan( '*', pSrcDim )=0 & Scan( '?', pSrcDim )=0 & Scan( pDelim, pSrcDim )=0 & Scan( ':', pSrcDim ) > 0 & pHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pHier = SubSt( pSrcDim, Scan( ':', pSrcDim ) + 1, Long( pSrcDim ) );\r\n pSrcDim = SubSt( pSrcDim, 1, Scan( ':', pSrcDim ) - 1 );\r\nEndIf;\r\n\r\n## Validate dimension\r\nIF( Trim( pSrcDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No source dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIF( DimensionExists( pSrcDim ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid source dimension: ' | pSrcDim;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nIf( pTgtDim @= '' % pTgtDim @= pSrcDim );\r\n pTgtDim = pSrcDim | '_Clone';\r\nEndIf;\r\n\r\n# Validate hierarchy\r\nIF( Scan( '*', pSrcDim )=0 & Scan( '?', pSrcDim )=0 & Scan( pDelim, pSrcDim )=0 & pHier @= '');\r\n pHier = pSrcDim;\r\nElseIf( Scan( '*', pHier )=0 & Scan( '?', pHier )=0 & Scan( pDelim, pHier )=0 & pHier @<> '' & HierarchyExists(pSrcDim, pHier) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid dimension hierarchy: ' | pHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndif;\r\n\r\nIf( Trim( pHier ) @= '' );\r\n ## use same name as Dimension. Since wildcards are allowed, this is managed inside the code below\r\nEndIf;\r\n\r\n## Default delimiter\r\nIf( pDelim @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### Create target dimension ###\r\n\r\nIf(DimensionExists( pTgtDim ) = 0 );\r\n DimensionCreate( pTgtDim );\r\nElse;\r\n IF(pUnwind = 1 );\r\n nRet = ExecuteProcess('}bedrock.hier.unwind',\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pDim', pTgtDim,\r\n 'pHier', pTgtDim,\r\n 'pConsol', '*',\r\n 'pRecursive', 1\r\n );\r\n ELSEIF(pUnwind = 2 );\r\n # Do nothing;\r\n ELSE;\r\n DimensionDeleteAllElements( pTgtDim );\r\n EndIf;\r\nEndIf;\r\n\r\n### Set the target Sort Order ###\r\n# CellGetS to }DimensionProperties cube removed. Placeholder as expecting a TI function to be made available to be able to read these properties\r\n#sSortElementsType = CELLGETS( '}DimensionProperties', pSrcDim, 'SORTELEMENTSTYPE');\r\n#sSortElementsSense = CELLGETS( '}DimensionProperties', pSrcDim, 'SORTELEMENTSSENSE');\r\n#sSortComponentsType = CELLGETS( '}DimensionProperties', pSrcDim, 'SORTCOMPONENTSTYPE');\r\n#sSortComponentsSense = CELLGETS( '}DimensionProperties', pSrcDim, 'SORTCOMPONENTSSENSE');\r\n\r\n# DimensionSortOrder( pTgtDim, sSortComponentsType, sSortComponentsSense, sSortElementsType , sSortElementsSense);\r\n\r\n\r\nnSourceDimSize = DIMSIZ( pSrcDim );\r\nnIndex = 1;\r\nWHILE( nIndex <= nSourceDimSize );\r\n sElName = DIMNM( pSrcDim, nIndex);\r\n sElType = DTYPE( pSrcDim, sElName);\r\n \r\n DimensionElementInsert( pTgtDim, '', sElName, sElType );\r\n\r\n nIndex = nIndex + 1;\r\nEND;\r\n\r\n### Assign Data Source ###\r\nDatasourceNameForServer = pSrcDim;\r\nDatasourceNameForClient = pSrcDim;\r\nDataSourceType = 'SUBSET';\r\nDatasourceDimensionSubset = 'ALL';\r\n\r\n\r\n### Replicate Attributes ###\r\n# Note: DType on Attr dim returns \"AS\", \"AN\" or \"AA\" need to strip off leading \"A\"\r\nsAttrDim = '}ElementAttributes_' | pSrcDim;\r\nsAttrLoc = '}LocalizedElementAttributes_' | pSrcDim;\r\nsAttrTargetDim = '}ElementAttributes_' | pTgtDim;\r\nsAttrLocTarget = '}LocalizedElementAttributes_' | pTgtDim;\r\n\r\nIf( pAttr = 1 & DimensionExists( sAttrDim ) = 1 );\r\n nNumAttrs = DimSiz( sAttrDim );\r\n nCount = 1;\r\n While( nCount <= nNumAttrs );\r\n sAttrName = DimNm( sAttrDim, nCount );\r\n sAttCheck = SubSt( DTYPE( sAttrDim, sAttrName ), 1, 1 );\r\n IF (sAttCheck @= 'A');\r\n sAttrType = SubSt( DTYPE( sAttrDim, sAttrName ), 2, 1 );\r\n Else;\r\n sAttrType = sAttcheck;\r\n EndIf; \r\n \r\n If ( DimensionExists( sAttrTargetDim ) = 0);\r\n AttrInsert(pTgtDim,'',sAttrName,sAttrType );\r\n ElseIF(DimIx(sAttrTargetDim, sAttrName) = 0);\r\n AttrInsert(pTgtDim,'',sAttrName,sAttrType );\r\n Endif;\r\n \r\n nCount = nCount + 1;\r\n End;\r\nEndIf;\r\n\r\n\r\n### End Prolog ###", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock Ver 4.0.0~~##\r\n################################################################################################# \r\n\r\n\r\n### Check for errors in prolog ###\r\n\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### Add Elements to target dimension ###\r\n\r\nsElType = DType( pSrcDim, vEle );\r\nIF( sElType @= 'C' & ElCompN( pSrcDim, vEle ) > 0 );\r\n nChildren = ElCompN( pSrcDim, vEle );\r\n nCount = 1;\r\n While( nCount <= nChildren );\r\n sChildElement = ElComp( pSrcDim, vEle, nCount );\r\n sChildWeight = ElWeight( pSrcDim, vEle, sChildElement );\r\n DimensionElementComponentAdd( pTgtDim, vEle, sChildElement, sChildWeight );\r\n nCount = nCount + 1;\r\n End;\r\nEndIf;\r\n\r\n### End MetaData ###", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock Ver 4.0.0~~##\r\n################################################################################################# \r\n\r\n\r\n### Check for errors in prolog ###\r\n\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### Replicate Attributes ###\r\n# Note: DTYPE on Attr dim returns \"AS\", \"AN\" or \"AA\" need to strip off leading \"A\"\r\n\r\nIf( pAttr = 1 & DimensionExists( sAttrDim ) = 1 );\r\n\r\n nAttr = 1;\r\n While( nAttr <= nNumAttrs );\r\n sAttrName = DimNm( sAttrDim, nAttr );\r\n sAttCheck = SubSt( DTYPE( sAttrDim, sAttrName ), 1, 1 );\r\n IF (sAttCheck @= 'A');\r\n sAttrType = SubSt( DTYPE( sAttrDim, sAttrName ), 2, 1 );\r\n Else;\r\n sAttrType = sAttcheck;\r\n sMessage = pSrcDim | ' dimension contains invalid attribute - ' | sAttrName ;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 );\r\n ItemReject(Expand( cMsgErrorContent ));\r\n EndIf; \r\n EndIf;\r\n If( CellIsUpdateable( sAttrTargetDim, vEle, sAttrName ) = 1 );\r\n If( sAttrType @= 'S' % sAttrType @= 'A' );\r\n #sAttrVal = AttrS( pSrcDim, vEle, sAttrName );\r\n sAttrVal = CellgetS('}ElementAttributes_'| pSrcDim, vEle, sAttrName);\r\n If( sAttrVal @<> '' );\r\n If( sAttrType @= 'A' );\r\n AttrPutS( sAttrVal, pTgtDim, vEle, sAttrName, 1 );\r\n Else;\r\n AttrPutS( sAttrVal, pTgtDim, vEle, sAttrName );\r\n EndIf;\r\n EndIf;\r\n Else;\r\n #nAttrVal = AttrN( pSrcDim, vEle, sAttrName );\r\n nAttrVal = CellgetN('}ElementAttributes_'| pSrcDim, vEle, sAttrName);\r\n If( nAttrVal <> 0 );\r\n AttrPutN( nAttrVal, pTgtDim, vEle, sAttrName );\r\n EndIf;\r\n EndIf;\r\n EndIf;\r\n # check for localized attributes\r\n If( CubeExists( sAttrLoc ) = 1 );\r\n nLang = 1;\r\n While( nLang <= nNumLang );\r\n sLang = DimNm( cLangDim, nLang );\r\n If( sAttrType @= 'A' % sAttrType @= 'S' );\r\n sAttrVal = AttrS( pSrcDim, vEle, sAttrName );\r\n sAttrValLoc = AttrSL( pSrcDim, vEle, sAttrName, sLang );\r\n If( sAttrValLoc @= sAttrVal ); sAttrValLoc = ''; EndIf;\r\n Else;\r\n nAttrVal = AttrN( pSrcDim, vEle, sAttrName );\r\n nAttrValLoc = AttrNL( pSrcDim, vEle, sAttrName, sLang );\r\n EndIf;\r\n If( CubeExists( sAttrLocTarget ) = 0 );\r\n If( sAttrType @= 'A' );\r\n AttrPutS( sAttrValLoc, pTgtDim, vEle, sAttrName, sLang, 1 );\r\n ElseIf( sAttrType @= 'N' );\r\n If( nAttrValLoc <> nAttrVal );\r\n AttrPutN( nAttrValLoc, pTgtDim, vEle, sAttrName, sLang );\r\n EndIf;\r\n Else;\r\n AttrPutS( sAttrValLoc, pTgtDim, vEle, sAttrName, sLang );\r\n EndIf;\r\n ElseIf( CubeExists( sAttrLocTarget ) = 1 );\r\n If( CellIsUpdateable( sAttrLocTarget, vEle, sLang, sAttrName ) = 1 );\r\n If( sAttrType @= 'A' );\r\n AttrPutS( sAttrValLoc, pTgtDim, vEle, sAttrName, sLang, 1 );\r\n ElseIf( sAttrType @= 'N' );\r\n If( nAttrValLoc <> nAttrVal );\r\n AttrPutN( nAttrValLoc, pTgtDim, vEle, sAttrName, sLang );\r\n EndIf;\r\n Else;\r\n AttrPutS( sAttrValLoc, pTgtDim, vEle, sAttrName, sLang );\r\n EndIf;\r\n EndIf;\r\n EndIf;\r\n nLang = nLang + 1;\r\n End;\r\n EndIf;\r\n nAttr = nAttr + 1;\r\n End;\r\n\r\nEndIf;\r\n\r\n### End Data ###", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock Ver 4.0.0~~##\r\n################################################################################################# \r\n\r\n\r\n### Set the target Sort Order ###\r\n# CellPutS to }DimensionProperties cube removed. Placeholder as expecting a TI function to be made available to be able to modify these properties\r\n# CELLPUTS( sSortElementsType, '}DimensionProperties', pTgtDim, 'SORTELEMENTSTYPE');\r\n# CELLPUTS( sSortElementsSense, '}DimensionProperties', pTgtDim, 'SORTELEMENTSSENSE');\r\n# CELLPUTS( sSortComponentsType, '}DimensionProperties', pTgtDim, 'SORTCOMPONENTSTYPE');\r\n# CELLPUTS( sSortComponentsSense, '}DimensionProperties', pTgtDim, 'SORTCOMPONENTSSENSE');\r\n\r\n### Destroy Source Subset ###\r\n\r\n If( SubsetExists( pSrcDim, cSubset ) = 1 );\r\n SubsetDestroy( pSrcDim, cSubset );\r\n EndIf;\r\n\r\n##Clone all the Hierarchies except default hierarchy & Leaves\r\nIf( pHier @= '*' );\r\n sDim = pSrcDim;\r\n sHierDim = '}Hierarchies_' | sDim;\r\n sTargetHierarchy = '';\r\n nMax = DimSiz( sHierDim );\r\n nCtr = 1;\r\n While( nCtr <= nMax );\r\n sEle = DimNm( sHierDim, nCtr );\r\n nElength = Long(sEle);\r\n nElestart = 0;\r\n nElestart = SCAN(':', sEle) + 1;\r\n If(nElestart > 1);\r\n vSourceHierarchy = SUBST(sEle,nElestart,nElength);\r\n If ( vSourceHierarchy @<> 'Leaves');\r\n nRet = ExecuteProcess('}bedrock.hier.clone',\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pSrcDim', sDim,\r\n 'pSrcHier', vSourceHierarchy,\r\n 'pTgtDim', pTgtDim,\r\n 'pTgtHier', vSourceHierarchy,\r\n 'pAttr', pAttr,\r\n 'pUnwind',pUnwind\r\n );\r\n Endif;\r\n sTargetHierarchy = sTargetHierarchy |':'|vSourceHierarchy;\r\n Endif;\r\n nCtr = nCtr + 1;\r\n End;\r\n### Just one hierarchy specified in parameter\r\nElseIf( Scan( '*', pHier )=0 & Scan( '?', pHier )=0 & Scan( pDelim, pHier )=0 & Trim( pHier ) @<> '' );\r\n sDim = pSrcDim;\r\n sHierDim = '}Hierarchies_' | sDim;\r\n sCurrHier = pHier;\r\n sCurrHierName = Subst( sCurrHier, Scan(':', sCurrHier)+1, Long(sCurrHier) );\r\n # Validate hierarchy name in sHierDim\r\n If( Dimix( sHierDim , sDim |':'| sCurrHier ) = 0 );\r\n sMessage = Expand('The \"%sCurrHier%\" hierarchy does NOT exist in the \"%sDim%\" dimension.');\r\n LogOutput( 'INFO' , Expand( cMsgInfoContent ) );\r\n ElseIf( sCurrHierName @= 'Leaves' );\r\n sMessage = 'Invalid Hierarchy: ' | sCurrHier | ' will be skipped....';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n ElseIf( sCurrHierName @<> sDim );\r\n If( pLogOutput = 1 );\r\n sMessage = Expand( 'Hierarchy \"%sCurrHierName%\" in Dimension \"%sDim%\" being processed....' );\r\n LogOutput( 'INFO', Expand( cMsgInfoContent ) );\r\n EndIf;\r\n nRet = ExecuteProcess('}bedrock.hier.clone',\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pSrcDim', sDim,\r\n 'pSrcHier', sCurrHierName,\r\n 'pTgtDim', pTgtDim,\r\n 'pTgtHier', sCurrHierName,\r\n 'pAttr', pAttr,\r\n 'pUnwind',pUnwind\r\n );\r\n Endif;\r\n### Hierachy is a delimited list with no wildcards\r\nElseIf( Scan( '*', pHier )=0 & Scan( '?', pHier )=0 & Trim( pHier ) @<> '' );\r\n \r\n # Loop through hierarchies in pHier\r\n sDim = pSrcDim;\r\n sHierarchies = pHier;\r\n nDelimiterIndexA = 1;\r\n sHierDim = '}Hierarchies_'| sDim ;\r\n sMdxHier = '';\r\n While( nDelimiterIndexA <> 0 );\r\n \r\n nDelimiterIndexA = Scan( pDelim, sHierarchies );\r\n If( nDelimiterIndexA = 0 );\r\n sHierarchy = sHierarchies;\r\n Else;\r\n sHierarchy = Trim( SubSt( sHierarchies, 1, nDelimiterIndexA - 1 ) );\r\n sHierarchies = Trim( Subst( sHierarchies, nDelimiterIndexA + Long(pDelim), Long( sHierarchies ) ) );\r\n EndIf;\r\n sCurrHier = sHierarchy;\r\n sCurrHierName = Subst( sCurrHier, Scan(':', sCurrHier)+1, Long(sCurrHier) );\r\n # Validate hierarchy name in sHierDim\r\n If( Dimix( sHierDim , sDim |':'| sCurrHier ) = 0 );\r\n sMessage = Expand('The \"%sCurrHier%\" hierarchy does NOT exist in the \"%sDim%\" dimension.');\r\n LogOutput( 'INFO' , Expand( cMsgInfoContent ) );\r\n ElseIf( sCurrHierName @= 'Leaves' );\r\n sMessage = 'Invalid Hierarchy: ' | sCurrHier | ' will be skipped....';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n ElseIf( sCurrHierName @<> sDim );\r\n If( pLogOutput = 1 );\r\n sMessage = Expand( 'Hierarchy \"%sCurrHierName%\" in Dimension \"%sDim%\" being processed....' );\r\n LogOutput( 'INFO', Expand( cMsgInfoContent ) );\r\n EndIf;\r\n nRet = ExecuteProcess('}bedrock.hier.clone',\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pSrcDim', sDim,\r\n 'pSrcHier', sCurrHierName,\r\n 'pTgtDim', pTgtDim,\r\n 'pTgtHier', sCurrHierName,\r\n 'pAttr', pAttr,\r\n 'pUnwind',pUnwind\r\n );\r\n Endif;\r\n End;\r\n\r\n### Hierachy has wildcards inside\r\nElseIf( Trim( pHier ) @<> '' );\r\n \r\n # Loop through hierarchies in pHier\r\n sDim = pSrcDim;\r\n sHierarchies = pHier;\r\n nDelimiterIndexA = 1;\r\n sHierDim = '}Hierarchies_'| sDim ;\r\n sMdxHier = '';\r\n While( nDelimiterIndexA <> 0 );\r\n \r\n nDelimiterIndexA = Scan( pDelim, sHierarchies );\r\n If( nDelimiterIndexA = 0 );\r\n sHierarchy = sHierarchies;\r\n Else;\r\n sHierarchy = Trim( SubSt( sHierarchies, 1, nDelimiterIndexA - 1 ) );\r\n sHierarchies = Trim( Subst( sHierarchies, nDelimiterIndexA + Long(pDelim), Long( sHierarchies ) ) );\r\n EndIf;\r\n \r\n # Create subset of Hierarchies using Wildcard\r\n sHierExp = '\"'| sDim | ':' | sHierarchy|'\"';\r\n sMdxHierPart = '{TM1FILTERBYPATTERN( {TM1SUBSETALL([ ' |sHierDim| '])},'| sHierExp | ')}';\r\n IF( sMdxHier @= ''); \r\n sMdxHier = sMdxHierPart; \r\n ELSE;\r\n sMdxHier = sMdxHier | ' + ' | sMdxHierPart;\r\n ENDIF;\r\n End;\r\n \r\n If( SubsetExists( sHierDim, cSubset ) = 1 );\r\n # If a delimited list of attr names includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( sHierDim, cSubset, sMdxHier );\r\n Else;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cSubset, sMdxHier, sHierDim, 1 );\r\n EndIf;\r\n \r\n # Loop through subset of hierarchies created based on wildcard\r\n nCountHier = SubsetGetSize( sHierDim, cSubset );\r\n While( nCountHier >= 1 );\r\n sCurrHier = SubsetGetElementName( sHierDim, cSubset , nCountHier );\r\n sCurrHierName = Subst( sCurrHier, Scan(':', sCurrHier)+1, Long(sCurrHier) );\r\n # Validate hierarchy name in sHierDim\r\n If( Dimix( sHierDim , sCurrHier ) = 0 );\r\n sMessage = Expand('The \"%sCurrHier%\" hierarchy does NOT exist in the \"%sDim%\" dimension.');\r\n LogOutput( 'INFO' , Expand( cMsgInfoContent ) );\r\n ElseIf( sCurrHierName @= 'Leaves' );\r\n sMessage = 'Invalid Hierarchy: ' | sCurrHier | ' will be skipped....';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n ElseIf( sCurrHierName @<> sDim );\r\n If( pLogOutput = 1 );\r\n sMessage = Expand( 'Hierarchy \"%sCurrHierName%\" in Dimension \"%sDim%\" being processed....' );\r\n LogOutput( 'INFO', Expand( cMsgInfoContent ) );\r\n EndIf;\r\n nRet = ExecuteProcess('}bedrock.hier.clone',\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pSrcDim', sDim,\r\n 'pSrcHier', sCurrHierName,\r\n 'pTgtDim', pTgtDim,\r\n 'pTgtHier', sCurrHierName,\r\n 'pAttr', pAttr,\r\n 'pUnwind',pUnwind\r\n );\r\n Endif;\r\n \r\n nCountHier = nCountHier - 1;\r\n End;\r\nEndif;\r\n\r\n### Clone dimension subsets\r\nIf( pSub = 1);\r\n nCountSubs = DimSiz ('}Subsets_' | sDim);\r\n While ( nCountSubs >= 1 );\r\n sCurrSub = If( Scan( ':', DimNm ('}Subsets_' | sDim, nCountSubs)) = 0, DimNm ('}Subsets_' | sDim, nCountSubs), Subst( DimNm ('}Subsets_' | sDim, nCountSubs), Scan( ':', DimNm ('}Subsets_' | sDim, nCountSubs))+1, Long(DimNm ('}Subsets_' | sDim, nCountSubs))-Scan( ':', DimNm ('}Subsets_' | sDim, nCountSubs))));\r\n sCurrHier = If( Scan( ':', DimNm ('}Subsets_' | sDim, nCountSubs)) = 0, '', Subst(DimNm ('}Subsets_' | sDim, nCountSubs), 1, Scan( ':', DimNm ('}Subsets_' | sDim, nCountSubs))-1));\r\n\r\n ExecuteProcess('}bedrock.hier.sub.clone',\r\n 'pLogOutput',0,\r\n 'pStrictErrorHandling',0,\r\n 'pSrcDim',sDim,\r\n 'pSrcHier',sCurrHier,\r\n 'pSrcSub',sCurrSub,\r\n 'pTgtDim', pTgtDim,\r\n 'pTgtHier', sCurrHier,\r\n 'pTgtSub',sCurrSub,\r\n 'pTemp',0,\r\n 'pAlias','');\r\n nCountSubs = nCountSubs - 1;\r\n End;\r\nEndif;\r\n \r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% has cloned the %pSrcDim% dimension into %pTgtDim%.' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n### End Epilog ###", @@ -13,59 +13,65 @@ "subset": "All" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pSrcDim", - "Prompt": "REQUIRED: Source Dimension", + "Prompt": "REQUIRED: Source dimension name", "Value": "", "Type": "String" }, { "Name": "pTgtDim", - "Prompt": "OPTIONAL: Target Dimension (will default to pSrcDim_clone If blank (or) is same as pSrcDim)", + "Prompt": "OPTIONAL: Target dimension name (Default = pSrcDim | '_Clone')", "Value": "", "Type": "String" }, { "Name": "pHier", - "Prompt": "REQUIRED: Hierarchies to be included (will use default is left blank), accepts wildcards (if = *, then all hierarchies)", + "Prompt": "OPTIONAL: Delimited list of hierarchies to include (Default = '*')", "Value": "*", "Type": "String" }, { "Name": "pAttr", - "Prompt": "REQUIRED: Include Attributes? (Boolean 1=True)", + "Prompt": "OPTIONAL: Include attributes (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { "Name": "pUnwind", - "Prompt": "REQUIRED: 0 = Delete all Elements, 1 = Unwind Existing Elements, 2 = Do not change Existing Elements", + "Prompt": "OPTIONAL: Unwind hierarchies after process (0 = Delete all elements, 1 = Unwind existing elements, 2 = Do not change existing elements. Default = 0)", "Value": 0, "Type": "Numeric" }, { "Name": "pDelim", - "Prompt": "OPTIONAL: delimiter character for element list (required if pEle parameter is used) (default value if blank = '&')", + "Prompt": "OPTIONAL: Delimiter for list parameters (Default = '&')", "Value": "&", "Type": "String" }, { "Name": "pSub", - "Prompt": "OPTIONAL: if 1 = Clone subsets", + "Prompt": "OPTIONAL: Include subsets (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [ @@ -77,7 +83,5 @@ "EndByte": 0 } ], - "VariablesUIData": [ - "VarType=32\fColType=827\f" - ] + "VariablesUIData": [] } \ No newline at end of file diff --git a/bedrock_processes_json/}bedrock.dim.create.json b/bedrock_processes_json/}bedrock.dim.create.json index 95cf707..e93461a 100644 --- a/bedrock_processes_json/}bedrock.dim.create.json +++ b/bedrock_processes_json/}bedrock.dim.create.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.dim.create", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\nExecuteProcess('}bedrock.dim.create',\r\n 'pLogOutput', 0,\r\n 'pStrictErrorHandling', 0,\r\n 'pDim', '',\r\n 'pDelim', '&');\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock Ver 4.0 ~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will create new dimensions based on `pDim`.\r\n\r\n# Use case: Intended for Development but could be used in production too.\r\n# 1. Create a new dimension for testing.\r\n# 2. Create a new dimension to reflect new business needs.\r\n\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncMsgInfoContent = 'User:%cUserName% Process:%cThisProcName% Message:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pHier:%pHier%, pDelim:%pDelim%.'; \r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\nIf( Scan( '*', pDim ) = 0 & Scan( '?', pDim ) = 0 & Scan( pDelim, pDim ) = 0 & Scan( ':', pDim ) > 0 );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pHier = SubSt( pDim, Scan( ':', pDim ) + 1, Long( pDim ) );\r\n pDim = SubSt( pDim, 1, Scan( ':', pDim ) - 1 );\r\nEndIf;\r\n\r\nIf( Trim( pDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# If blank delimiter specified then convert to default\r\nIf( pDelim @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n\r\n# Loop through dimensions in pDim\r\nsDims = pDim;\r\nnDimDelimiterIndex = 1;\r\n# Get 1st dimension\r\nWhile( nDimDelimiterIndex <> 0 );\r\n # Extract 1st dimension > sDim\r\n nDimDelimiterIndex = Scan( pDelim, sDims );\r\n If( nDimDelimiterIndex = 0 );\r\n sDim = sDims;\r\n Else;\r\n sDim = Trim( SubSt( sDims, 1, nDimDelimiterIndex - 1 ) );\r\n sDims = Trim( Subst( sDims, nDimDelimiterIndex + Long(pDelim), Long( sDims ) ) );\r\n EndIf;\r\n \r\n ###Creating Dimension if not exist, where no wildcard\r\n If( Scan( '*', sDim ) = 0 & Scan( '?', sDim ) = 0 & Scan( pDelim, sDim ) = 0 & DimensionExists( sDim ) = 0 );\r\n DimensionCreate( sDim );\r\n If( pLogOutput = 1 );\r\n sMessage = Expand( 'Creating Dimension %sDim%' );\r\n LogOutput( 'INFO', Expand( cMsgInfoContent ) );\r\n EndIf;\r\n EndIf;\r\n \r\nEnd;\r\n\r\n### End Prolog ###", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\nExecuteProcess('}bedrock.dim.create',\r\n 'pLogOutput', 0,\r\n 'pStrictErrorHandling', 0,\r\n 'pDim', '',\r\n 'pDelim', '&');\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock Ver 4.0 ~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will create new dimensions based on `pDim`.\r\n\r\n# Use case: Intended for Development but could be used in production too.\r\n# 1. Create a new dimension for testing.\r\n# 2. Create a new dimension to reflect new business needs.\r\n\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncMsgInfoContent = 'User:%cUserName% Process:%cThisProcName% Message:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pHier:%pHier%, pDelim:%pDelim%.';\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pDelim\": \"&\",\r\n \"pDim\": null,\r\n \"pLogOutput\": 0,\r\n \"pStrictErrorHandling\": 0\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pDelim\": '|StringToJson ( pDelim )|',\r\n \"pDim\": '|StringToJson ( pDim )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npDelim = JsonToString( JsonGet( pJson, 'pDelim' ) );\r\npDim = JsonToString( JsonGet( pJson, 'pDim' ) );\r\n# Numeric Parameters\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\nIf( Scan( '*', pDim ) = 0 & Scan( '?', pDim ) = 0 & Scan( pDelim, pDim ) = 0 & Scan( ':', pDim ) > 0 );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pHier = SubSt( pDim, Scan( ':', pDim ) + 1, Long( pDim ) );\r\n pDim = SubSt( pDim, 1, Scan( ':', pDim ) - 1 );\r\nEndIf;\r\n\r\nIf( Trim( pDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# If blank delimiter specified then convert to default\r\nIf( pDelim @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n\r\n# Loop through dimensions in pDim\r\nsDims = pDim;\r\nnDimDelimiterIndex = 1;\r\n# Get 1st dimension\r\nWhile( nDimDelimiterIndex <> 0 );\r\n # Extract 1st dimension > sDim\r\n nDimDelimiterIndex = Scan( pDelim, sDims );\r\n If( nDimDelimiterIndex = 0 );\r\n sDim = sDims;\r\n Else;\r\n sDim = Trim( SubSt( sDims, 1, nDimDelimiterIndex - 1 ) );\r\n sDims = Trim( Subst( sDims, nDimDelimiterIndex + Long(pDelim), Long( sDims ) ) );\r\n EndIf;\r\n \r\n ###Creating Dimension if not exist, where no wildcard\r\n If( Scan( '*', sDim ) = 0 & Scan( '?', sDim ) = 0 & Scan( pDelim, sDim ) = 0 & DimensionExists( sDim ) = 0 );\r\n DimensionCreate( sDim );\r\n If( pLogOutput = 1 );\r\n sMessage = Expand( 'Creating Dimension %sDim%' );\r\n LogOutput( 'INFO', Expand( cMsgInfoContent ) );\r\n EndIf;\r\n EndIf;\r\n \r\nEnd;\r\n\r\n### End Prolog ###", "MetadataProcedure": "#****Begin: Generated Statements***\r\n#****End: Generated Statements****", "DataProcedure": "#****Begin: Generated Statements***\r\n#****End: Generated Statements****", "EpilogProcedure": "#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully created the %pHier% hierarchy in the %pDim% dimension.' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n\r\n\r\n### End Epilog ###", @@ -10,28 +10,34 @@ "Type": "None" }, "Parameters": [ + { + "Name": "pDim", + "Prompt": "REQUIRED: Delimited list of dimensions", + "Value": "", + "Type": "String" + }, + { + "Name": "pDelim", + "Prompt": "OPTIONAL: Delimiter for list parameters (Default = '&')", + "Value": "&", + "Type": "String" + }, { "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { - "Name": "pDim", - "Prompt": "REQUIRED: Dimension, accepts delimted list", - "Value": "", - "Type": "String" - }, - { - "Name": "pDelim", - "Prompt": "OPTIONAL: delimiter character for element list. (default value if blank = '&')", - "Value": "&", + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", "Type": "String" } ], diff --git a/bedrock_processes_json/}bedrock.dim.delete.json b/bedrock_processes_json/}bedrock.dim.delete.json index 362b516..d6115ea 100644 --- a/bedrock_processes_json/}bedrock.dim.delete.json +++ b/bedrock_processes_json/}bedrock.dim.delete.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.dim.delete", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.dim.delete', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n\t 'pDim', '', 'pDelim', '&'\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~ Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock Ver 4.0 ~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process deletes a dimension, list of dimensions, or set of dimensions specified by wildcard name match.\r\n\r\n# Use case: Intended for development/prototyping.\r\n# 1. During active agile development to remove dimensions due to renaming, change of requirements, etc.\r\n# 2. Clean up unused dimensions prior to system Go Live.\r\n\r\n# Note:\r\n# * A valid dimension name pDim or list thereof is mandatory otherwise the process will abort.\r\n# * Attribute dimensions are deliberately excluded because these are automatically cleaned up by removing the base dimension.\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pDelim:%pDelim%.'; \r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\nIf( Trim( pDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n## Default delimiter\r\nIf( pDelim @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n## Dimension delete\r\n# Loop through dimensions in pDim \r\nsDims = Trim( pDim );\r\nnDimDelimiterIndex = 1;\r\n# Get 1st dimension\r\nWhile( nDimDelimiterIndex <> 0 );\r\n # Extract 1st dimension > sDim\r\n nDimDelimiterIndex = Scan( pDelim, sDims );\r\n If( nDimDelimiterIndex = 0 );\r\n sDim = sDims;\r\n Else;\r\n sDim = Trim( SubSt( sDims, 1, nDimDelimiterIndex - 1 ) );\r\n sDims = Trim( Subst( sDims, nDimDelimiterIndex + Long(pDelim), Long( sDims ) ) );\r\n EndIf;\r\n \r\n # Check if sDim has wildcard\r\n If( Scan( '*', sDim ) = 0);\r\n # check if dim is used in a cube\r\n sDimIsUsed ='';\r\n nDimIsUsed = 0;\r\n nCubes = DimSiz( '}Cubes' );\r\n nCube = 1;\r\n While(nCube <= nCubes);\r\n sCube = DimNm( '}Cubes' , nCube );\r\n nDim = 1;\r\n While(TabDim(sCube,nDim)@<>'' & Subst( sCube , 1 , 1) @<>'}' );\r\n sDimInCube = TABDIM(sCube,nDim);\r\n If(sDimInCube@=sDim);\r\n sDimIsUsed = sDimIsUsed | sCube | ' ';\r\n nDimIsUsed = nDimIsUsed+1;\r\n EndIf;\r\n nDim = nDim + 1;\r\n End;\r\n nCube = nCube + 1;\r\n End; \r\n \r\n # Delete if it exists and is not being used in a cube\r\n If( DimensionExists(sDim) = 0 );\r\n nErrors = 1;\r\n sMessage = Expand( 'Dimension \"%sDim%\" does not exist.' );\r\n LogOutput( 'ERROR', Expand( cMsgErrorContent ) );\r\n ElseIF( sDimIsUsed@='');\r\n DimensionDestroy( sDim );\r\n Else;\r\n nErrors = 1;\r\n sMessage = 'The dimension ' | sDim | ' could not be destroyed as it is being used for ' | NumberToString(nDimIsUsed) | ' cube(s) :' | sDimIsUsed;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n Endif;\r\n Else;\r\n # Create subset of dimensions using Wildcard to loop through dimensions in pDim with wildcard\r\n sDimExp = '\"'|sDim|'\"';\r\n sMdx = '{TM1FILTERBYPATTERN( EXCEPT ( EXCEPT ( TM1SUBSETALL( [}Dimensions] ) , TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) , \"*:*\") ), TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) , \"}ElementAttributes_*\") ) ,'| sDimExp | ')}';\r\n If( SubsetExists( '}Dimensions' , cTempSub ) = 1 );\r\n # If a delimited list of dim names includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( '}Dimensions' , cTempSub, sMDX );\r\n Else;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSub, sMDX, '}Dimensions' , 1 );\r\n EndIf;\r\n \r\n # Loop through dimensions in subset created based on wildcard\r\n nCountDim = SubsetGetSize( '}Dimensions' , cTempSub );\r\n While( nCountDim >= 1 );\r\n sDim = SubsetGetElementName( '}Dimensions' , cTempSub, nCountDim );\r\n # check if dim is used in a cube\r\n sDimIsUsed ='';\r\n nDimIsUsed = 0;\r\n nCubes = DimSiz( '}Cubes' );\r\n nCube = 1;\r\n While(nCube <= nCubes);\r\n sCube = DimNm( '}Cubes' , nCube );\r\n nDim = 1;\r\n While(TabDim(sCube,nDim)@<>'' & Subst( sCube , 1 , 1) @<>'}' );\r\n sDimInCube = TABDIM(sCube,nDim);\r\n If(sDimInCube@=sDim);\r\n sDimIsUsed = sDimIsUsed | sCube | ' ';\r\n nDimIsUsed = nDimIsUsed+1;\r\n EndIf;\r\n nDim = nDim + 1;\r\n End;\r\n nCube = nCube + 1;\r\n End; \r\n # Delete if it exists and is not being used in a cube\r\n If( DimensionExists(sDim) = 0 );\r\n nErrors = 1;\r\n sMessage = Expand( 'Dimension %sDim% does not exist.' );\r\n LogOutput( 'ERROR', Expand( cMsgErrorContent ) );\r\n ElseIF( sDimIsUsed@='');\r\n DimensionDestroy( sDim );\r\n Else;\r\n nErrors = 1;\r\n sMessage = 'The dimension ' | sDim | ' could not be destroyed as it is being used for ' | NumberToString(nDimIsUsed) | ' cube(s) :' | sDimIsUsed;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n Endif;\r\n IF( SubsetGetSize( '}Dimensions' , cTempSub ) < nCountDim - 1 );\r\n nCountDim = SubsetGetSize( '}Dimensions' , cTempSub );\r\n ELSE;\r\n nCountDim = nCountDim - 1;\r\n ENDIF;\r\n End;\r\n EndIf;\r\n \r\nEnd;\r\n\r\n### End Prolog ###", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.dim.delete', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n\t 'pDim', '', 'pDelim', '&'\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~ Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock Ver 4.0 ~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process deletes a dimension, list of dimensions, or set of dimensions specified by wildcard name match.\r\n\r\n# Use case: Intended for development/prototyping.\r\n# 1. During active agile development to remove dimensions due to renaming, change of requirements, etc.\r\n# 2. Clean up unused dimensions prior to system Go Live.\r\n\r\n# Note:\r\n# * A valid dimension name pDim or list thereof is mandatory otherwise the process will abort.\r\n# * Attribute dimensions are deliberately excluded because these are automatically cleaned up by removing the base dimension.\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pDelim:%pDelim%.';\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pDelim\": \"&\",\r\n \"pDim\": null,\r\n \"pLogOutput\": 0,\r\n \"pStrictErrorHandling\": 0\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pDelim\": '|StringToJson ( pDelim )|',\r\n \"pDim\": '|StringToJson ( pDim )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npDelim = JsonToString( JsonGet( pJson, 'pDelim' ) );\r\npDim = JsonToString( JsonGet( pJson, 'pDim' ) );\r\n# Numeric Parameters\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\nIf( Trim( pDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n## Default delimiter\r\nIf( pDelim @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n## Dimension delete\r\n# Loop through dimensions in pDim \r\nsDims = Trim( pDim );\r\nnDimDelimiterIndex = 1;\r\n# Get 1st dimension\r\nWhile( nDimDelimiterIndex <> 0 );\r\n # Extract 1st dimension > sDim\r\n nDimDelimiterIndex = Scan( pDelim, sDims );\r\n If( nDimDelimiterIndex = 0 );\r\n sDim = sDims;\r\n Else;\r\n sDim = Trim( SubSt( sDims, 1, nDimDelimiterIndex - 1 ) );\r\n sDims = Trim( Subst( sDims, nDimDelimiterIndex + Long(pDelim), Long( sDims ) ) );\r\n EndIf;\r\n \r\n # Check if sDim has wildcard\r\n If( Scan( '*', sDim ) = 0);\r\n # check if dim is used in a cube\r\n sDimIsUsed ='';\r\n nDimIsUsed = 0;\r\n nCubes = DimSiz( '}Cubes' );\r\n nCube = 1;\r\n While(nCube <= nCubes);\r\n sCube = DimNm( '}Cubes' , nCube );\r\n nDim = 1;\r\n While(TabDim(sCube,nDim)@<>'' & Subst( sCube , 1 , 1) @<>'}' );\r\n sDimInCube = TABDIM(sCube,nDim);\r\n If(sDimInCube@=sDim);\r\n sDimIsUsed = sDimIsUsed | sCube | ' ';\r\n nDimIsUsed = nDimIsUsed+1;\r\n EndIf;\r\n nDim = nDim + 1;\r\n End;\r\n nCube = nCube + 1;\r\n End; \r\n \r\n # Delete if it exists and is not being used in a cube\r\n If( DimensionExists(sDim) = 0 );\r\n nErrors = 1;\r\n sMessage = Expand( 'Dimension \"%sDim%\" does not exist.' );\r\n LogOutput( 'ERROR', Expand( cMsgErrorContent ) );\r\n ElseIF( sDimIsUsed@='');\r\n DimensionDestroy( sDim );\r\n Else;\r\n nErrors = 1;\r\n sMessage = 'The dimension ' | sDim | ' could not be destroyed as it is being used for ' | NumberToString(nDimIsUsed) | ' cube(s) :' | sDimIsUsed;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n Endif;\r\n Else;\r\n # Create subset of dimensions using Wildcard to loop through dimensions in pDim with wildcard\r\n sDimExp = '\"'|sDim|'\"';\r\n sMdx = '{TM1FILTERBYPATTERN( EXCEPT ( EXCEPT ( TM1SUBSETALL( [}Dimensions] ) , TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) , \"*:*\") ), TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) , \"}ElementAttributes_*\") ) ,'| sDimExp | ')}';\r\n If( SubsetExists( '}Dimensions' , cTempSub ) = 1 );\r\n # If a delimited list of dim names includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( '}Dimensions' , cTempSub, sMDX );\r\n Else;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSub, sMDX, '}Dimensions' , 1 );\r\n EndIf;\r\n \r\n # Loop through dimensions in subset created based on wildcard\r\n nCountDim = SubsetGetSize( '}Dimensions' , cTempSub );\r\n While( nCountDim >= 1 );\r\n sDim = SubsetGetElementName( '}Dimensions' , cTempSub, nCountDim );\r\n # check if dim is used in a cube\r\n sDimIsUsed ='';\r\n nDimIsUsed = 0;\r\n nCubes = DimSiz( '}Cubes' );\r\n nCube = 1;\r\n While(nCube <= nCubes);\r\n sCube = DimNm( '}Cubes' , nCube );\r\n nDim = 1;\r\n While(TabDim(sCube,nDim)@<>'' & Subst( sCube , 1 , 1) @<>'}' );\r\n sDimInCube = TABDIM(sCube,nDim);\r\n If(sDimInCube@=sDim);\r\n sDimIsUsed = sDimIsUsed | sCube | ' ';\r\n nDimIsUsed = nDimIsUsed+1;\r\n EndIf;\r\n nDim = nDim + 1;\r\n End;\r\n nCube = nCube + 1;\r\n End; \r\n # Delete if it exists and is not being used in a cube\r\n If( DimensionExists(sDim) = 0 );\r\n nErrors = 1;\r\n sMessage = Expand( 'Dimension %sDim% does not exist.' );\r\n LogOutput( 'ERROR', Expand( cMsgErrorContent ) );\r\n ElseIF( sDimIsUsed@='');\r\n DimensionDestroy( sDim );\r\n Else;\r\n nErrors = 1;\r\n sMessage = 'The dimension ' | sDim | ' could not be destroyed as it is being used for ' | NumberToString(nDimIsUsed) | ' cube(s) :' | sDimIsUsed;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n Endif;\r\n IF( SubsetGetSize( '}Dimensions' , cTempSub ) < nCountDim - 1 );\r\n nCountDim = SubsetGetSize( '}Dimensions' , cTempSub );\r\n ELSE;\r\n nCountDim = nCountDim - 1;\r\n ENDIF;\r\n End;\r\n EndIf;\r\n \r\nEnd;\r\n\r\n### End Prolog ###", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully deleted dimensions %pDim%.' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n### End Epilog ###", @@ -10,28 +10,34 @@ "Type": "None" }, "Parameters": [ + { + "Name": "pDim", + "Prompt": "REQUIRED: Delimited list of dimensions", + "Value": "", + "Type": "String" + }, + { + "Name": "pDelim", + "Prompt": "OPTIONAL: Delimiter for list parameters (Default = '&')", + "Value": "&", + "Type": "String" + }, { "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { - "Name": "pDim", - "Prompt": "REQUIRED: Dimension (Delimited list & wildcards (*) acceptable)", - "Value": "", - "Type": "String" - }, - { - "Name": "pDelim", - "Prompt": "REQUIRED: delimiter character for attribute list. (default value if blank = '&')", - "Value": "&", + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", "Type": "String" } ], diff --git a/bedrock_processes_json/}bedrock.dim.sort.json b/bedrock_processes_json/}bedrock.dim.sort.json index 1826ea1..102693a 100644 --- a/bedrock_processes_json/}bedrock.dim.sort.json +++ b/bedrock_processes_json/}bedrock.dim.sort.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.dim.sort", - "PrologProcedure": "#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess('}bedrock.dim.sort',\r\n 'pCompSortType', 'ByName',\r\n 'pCompSortSense', 'Ascending',\r\n 'pElSortType', 'ByHierarchy',\r\n 'pElSortSense', 'Descending',\r\n 'pLogOutput', 0,\r\n 'pStrictErrorHandling', 0,\r\n 'pDim', '',\r\n 'pDelim', '&');\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n \r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n \r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n \r\n#Region @DOC\r\n# Description:\r\n# This process sets a dimension's sort order using the DimensionSortOrder function. pDimension\r\n# can use wildcards and/or a delimited list.\r\n \r\n# Note:\r\n# Valid dimension name (pDim) is mandatory.\r\n \r\n# Caution: \r\n# Existing DimensionSortOrder properties will be ignored and overwritten.\r\n#EndRegion @DOC\r\n \r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n \r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSubDim = cThisProcName |'_dims_'| cTimeStamp |'_'| cRandomInt;\r\ncTempSubHier = cThisProcName |'_hiers_'| cTimeStamp |'_'| cRandomInt;\r\ncUserName = TM1User();\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncMsgInfoContent = 'User:%cUserName% Process:%cThisProcName% Message:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters,\r\npCompSortType:%pCompSortType%,\r\npCompSortSense:%pCompSortSense%,\r\npElSortType:%pElSortType%,\r\npElSortSense:%pElSortSense%,\r\npLogOutput:%pLogOutput%,\r\npStrictErrorHandling:%pStrictErrorHandling%,\r\npDim:%pDim%,\r\npDelim:%pDelim%.'; \r\n \r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n \r\n### Validate Parameters ###\r\nnErrors = 0;\r\n \r\n# Validate dimension\r\nIf( Trim( pDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate DimensionSortOrder parameters\r\npCompSortType = UPPER( TRIM( pCompSortType ) );\r\npCompSortSense = UPPER( TRIM( pCompSortSense ) );\r\npElSortType = UPPER( TRIM( pElSortType ) );\r\npElSortSense = UPPER( TRIM( pElSortSense ) );\r\n\r\nIF( pCompSortType @<> 'BYINPUT' & pCompSortType @<> 'BYNAME' );\r\n nErrors = 1;\r\n sMessage = 'Invalid Value for pCompSortType: \"' | pCompSortType | '\". Must be \"ByInput\" or \"ByName\".';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nENDIF;\r\n\r\nIF( pCompSortSense @<> 'ASCENDING' & pCompSortSense @<> 'DESCENDING' );\r\n nErrors = 1;\r\n sMessage = 'Invalid Value for pCompSortSense: \"' | pCompSortSense | '\". Must be \"Ascending\" or \"Descending\".';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nENDIF;\r\n\r\nIF( pElSortType @<> 'BYINPUT' & pElSortType @<> 'BYNAME' & pElSortType @<> 'BYLEVEL' & pElSortType @<> 'BYHIERARCHY' );\r\n nErrors = 1;\r\n sMessage = 'Invalid Value for pElSortType: \"' | pElSortType | '\". Must be \"ByInput\" or \"ByName\" or \"ByLevel\" or \"ByHierarchy\".';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nENDIF;\r\n\r\nIF( pElSortSense @<> 'ASCENDING' & pElSortSense @<> 'DESCENDING' );\r\n nErrors = 1;\r\n sMessage = 'Invalid Value for pElSortSense: \"' | pElSortSense | '\". Must be \"Ascending\" or \"Descending\".';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nENDIF;\r\n \r\n# If blank delimiter specified then convert to default\r\nIf( pDelim @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n \r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n\r\n# Loop through dimensions in pDim\r\nsDims = pDim;\r\nnDimDelimiterIndex = 1;\r\nsMdx = '';\r\n# Get 1st dimension\r\nWhile( nDimDelimiterIndex <> 0 );\r\n # Extract 1st dimension > sDim\r\n nDimDelimiterIndex = Scan( pDelim, sDims );\r\n If( nDimDelimiterIndex = 0 );\r\n sDim = sDims;\r\n Else;\r\n sDim = Trim( SubSt( sDims, 1, nDimDelimiterIndex - 1 ) );\r\n sDims = Trim( Subst( sDims, nDimDelimiterIndex + Long(pDelim), Long( sDims ) ) );\r\n EndIf;\r\n \r\n # Create subset of dimensions using Wildcard to loop through dimensions in pDim with wildcard\r\n sDimExp = '\"'|sDim|'\"';\r\n sMdxPart = '{TM1FILTERBYPATTERN( EXCEPT( TM1SUBSETALL( [}Dimensions] ) , TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) , \"*:*\") ) ,'| sDimExp | ')}';\r\n IF( sMdx @= ''); \r\n sMdx = sMdxPart; \r\n ELSE;\r\n sMdx = sMdx | ' + ' | sMdxPart;\r\n ENDIF;\r\nEnd;\r\n \r\nIf( SubsetExists( '}Dimensions' , cTempSubDim ) = 1 );\r\n # If a delimited list of dim names includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( '}Dimensions' , cTempSubDim, sMDX );\r\nElse;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSubDim, sMDX, '}Dimensions' , 1 );\r\nEndIf;\r\n \r\n# Loop through dimensions in subset created based on wildcard\r\nnCountDim = SubsetGetSize( '}Dimensions' , cTempSubDim );\r\nWhile( nCountDim >= 1 );\r\n sDim = SubsetGetElementName( '}Dimensions' , cTempSubDim, nCountDim );\r\n # Validate dimension name\r\n If( DimensionExists(sDim) = 0 );\r\n nErrors = 1;\r\n sMessage = Expand( 'Dimension %sDim% does not exist.' );\r\n LogOutput( 'ERROR', Expand( cMsgErrorContent ) );\r\n Else;\r\n If( pLogOutput = 1 );\r\n sMessage = Expand( 'Dimension %sDim% being processed....' );\r\n LogOutput( 'INFO', Expand( cMsgInfoContent ) );\r\n EndIf;\r\n \r\n DimensionSortOrder( sDim, pCompSortType, pCompSortSense, pElSortType, pElSortSense );\r\n \r\n EndIf;\r\n \r\n nCountDim = nCountDim - 1;\r\nEnd;", + "PrologProcedure": "#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess('}bedrock.dim.sort',\r\n 'pCompSortType', 'ByName',\r\n 'pCompSortSense', 'Ascending',\r\n 'pElSortType', 'ByHierarchy',\r\n 'pElSortSense', 'Descending',\r\n 'pLogOutput', 0,\r\n 'pStrictErrorHandling', 0,\r\n 'pDim', '',\r\n 'pDelim', '&');\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n \r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n \r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n \r\n#Region @DOC\r\n# Description:\r\n# This process sets a dimension's sort order using the DimensionSortOrder function. pDimension\r\n# can use wildcards and/or a delimited list.\r\n \r\n# Note:\r\n# Valid dimension name (pDim) is mandatory.\r\n \r\n# Caution: \r\n# Existing DimensionSortOrder properties will be ignored and overwritten.\r\n#EndRegion @DOC\r\n \r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n \r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSubDim = cThisProcName |'_dims_'| cTimeStamp |'_'| cRandomInt;\r\ncTempSubHier = cThisProcName |'_hiers_'| cTimeStamp |'_'| cRandomInt;\r\ncUserName = TM1User();\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncMsgInfoContent = 'User:%cUserName% Process:%cThisProcName% Message:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters,\r\npCompSortType:%pCompSortType%,\r\npCompSortSense:%pCompSortSense%,\r\npElSortType:%pElSortType%,\r\npElSortSense:%pElSortSense%,\r\npLogOutput:%pLogOutput%,\r\npStrictErrorHandling:%pStrictErrorHandling%,\r\npDim:%pDim%,\r\npDelim:%pDelim%.';\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pCompSortSense\": \"Ascending\",\r\n \"pCompSortType\": \"ByName\",\r\n \"pDelim\": \"&\",\r\n \"pDim\": null,\r\n \"pElSortSense\": \"Descending\",\r\n \"pElSortType\": \"ByHierarchy\",\r\n \"pLogOutput\": 0,\r\n \"pStrictErrorHandling\": 0\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pCompSortSense\": '|StringToJson ( pCompSortSense )|',\r\n \"pCompSortType\": '|StringToJson ( pCompSortType )|',\r\n \"pDelim\": '|StringToJson ( pDelim )|',\r\n \"pDim\": '|StringToJson ( pDim )|',\r\n \"pElSortSense\": '|StringToJson ( pElSortSense )|',\r\n \"pElSortType\": '|StringToJson ( pElSortType )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npCompSortSense = JsonToString( JsonGet( pJson, 'pCompSortSense' ) );\r\npCompSortType = JsonToString( JsonGet( pJson, 'pCompSortType' ) );\r\npDelim = JsonToString( JsonGet( pJson, 'pDelim' ) );\r\npDim = JsonToString( JsonGet( pJson, 'pDim' ) );\r\npElSortSense = JsonToString( JsonGet( pJson, 'pElSortSense' ) );\r\npElSortType = JsonToString( JsonGet( pJson, 'pElSortType' ) );\r\n# Numeric Parameters\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n \r\n### Validate Parameters ###\r\nnErrors = 0;\r\n \r\n# Validate dimension\r\nIf( Trim( pDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate DimensionSortOrder parameters\r\npCompSortType = UPPER( TRIM( pCompSortType ) );\r\npCompSortSense = UPPER( TRIM( pCompSortSense ) );\r\npElSortType = UPPER( TRIM( pElSortType ) );\r\npElSortSense = UPPER( TRIM( pElSortSense ) );\r\n\r\nIF( pCompSortType @<> 'BYINPUT' & pCompSortType @<> 'BYNAME' );\r\n nErrors = 1;\r\n sMessage = 'Invalid Value for pCompSortType: \"' | pCompSortType | '\". Must be \"ByInput\" or \"ByName\".';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nENDIF;\r\n\r\nIF( pCompSortSense @<> 'ASCENDING' & pCompSortSense @<> 'DESCENDING' );\r\n nErrors = 1;\r\n sMessage = 'Invalid Value for pCompSortSense: \"' | pCompSortSense | '\". Must be \"Ascending\" or \"Descending\".';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nENDIF;\r\n\r\nIF( pElSortType @<> 'BYINPUT' & pElSortType @<> 'BYNAME' & pElSortType @<> 'BYLEVEL' & pElSortType @<> 'BYHIERARCHY' );\r\n nErrors = 1;\r\n sMessage = 'Invalid Value for pElSortType: \"' | pElSortType | '\". Must be \"ByInput\" or \"ByName\" or \"ByLevel\" or \"ByHierarchy\".';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nENDIF;\r\n\r\nIF( pElSortSense @<> 'ASCENDING' & pElSortSense @<> 'DESCENDING' );\r\n nErrors = 1;\r\n sMessage = 'Invalid Value for pElSortSense: \"' | pElSortSense | '\". Must be \"Ascending\" or \"Descending\".';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nENDIF;\r\n \r\n# If blank delimiter specified then convert to default\r\nIf( pDelim @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n \r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n\r\n# Loop through dimensions in pDim\r\nsDims = pDim;\r\nnDimDelimiterIndex = 1;\r\nsMdx = '';\r\n# Get 1st dimension\r\nWhile( nDimDelimiterIndex <> 0 );\r\n # Extract 1st dimension > sDim\r\n nDimDelimiterIndex = Scan( pDelim, sDims );\r\n If( nDimDelimiterIndex = 0 );\r\n sDim = sDims;\r\n Else;\r\n sDim = Trim( SubSt( sDims, 1, nDimDelimiterIndex - 1 ) );\r\n sDims = Trim( Subst( sDims, nDimDelimiterIndex + Long(pDelim), Long( sDims ) ) );\r\n EndIf;\r\n \r\n # Create subset of dimensions using Wildcard to loop through dimensions in pDim with wildcard\r\n sDimExp = '\"'|sDim|'\"';\r\n sMdxPart = '{TM1FILTERBYPATTERN( EXCEPT( TM1SUBSETALL( [}Dimensions] ) , TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) , \"*:*\") ) ,'| sDimExp | ')}';\r\n IF( sMdx @= ''); \r\n sMdx = sMdxPart; \r\n ELSE;\r\n sMdx = sMdx | ' + ' | sMdxPart;\r\n ENDIF;\r\nEnd;\r\n \r\nIf( SubsetExists( '}Dimensions' , cTempSubDim ) = 1 );\r\n # If a delimited list of dim names includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( '}Dimensions' , cTempSubDim, sMDX );\r\nElse;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSubDim, sMDX, '}Dimensions' , 1 );\r\nEndIf;\r\n \r\n# Loop through dimensions in subset created based on wildcard\r\nnCountDim = SubsetGetSize( '}Dimensions' , cTempSubDim );\r\nWhile( nCountDim >= 1 );\r\n sDim = SubsetGetElementName( '}Dimensions' , cTempSubDim, nCountDim );\r\n # Validate dimension name\r\n If( DimensionExists(sDim) = 0 );\r\n nErrors = 1;\r\n sMessage = Expand( 'Dimension %sDim% does not exist.' );\r\n LogOutput( 'ERROR', Expand( cMsgErrorContent ) );\r\n Else;\r\n If( pLogOutput = 1 );\r\n sMessage = Expand( 'Dimension %sDim% being processed....' );\r\n LogOutput( 'INFO', Expand( cMsgInfoContent ) );\r\n EndIf;\r\n \r\n DimensionSortOrder( sDim, pCompSortType, pCompSortSense, pElSortType, pElSortSense );\r\n \r\n EndIf;\r\n \r\n nCountDim = nCountDim - 1;\r\nEnd;", "MetadataProcedure": "#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "DataProcedure": "#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "EpilogProcedure": "#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% sorted dimensions: \"%pDim%\" with the following values: pCompSortType=%pCompSortType%, pCompSortSense=%pCompSortSense%, pElSortType=%pElSortType%, pElSortSense=%pElSortSense%' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n\r\n### End Epilog ###", @@ -12,50 +12,56 @@ "Parameters": [ { "Name": "pCompSortType", - "Prompt": "REQUIRED: sort type for components of consolidated elements \u200b", + "Prompt": "OPTIONAL: Consolidated elements' components sort type (Default = 'ByName')", "Value": "ByName", "Type": "String" }, { "Name": "pCompSortSense", - "Prompt": "REQUIRED: the sense of order for CompSortType either \u2018Ascending\u2019 or \u2018Descending\u2019. This applies only when the CompSortType is ByName. \u200b", + "Prompt": "OPTIONAL: Sort sense for pCompSortType (Default = 'Ascending')", "Value": "Ascending", "Type": "String" }, { "Name": "pElSortType", - "Prompt": "REQUIRED: sort type for all elements\u200b", + "Prompt": "OPTIONAL: Elements' sort type (Default = 'ByHierarchy')", "Value": "ByHierarchy", "Type": "String" }, { "Name": "pElSortSense", - "Prompt": "REQUIRED: the sense of order for ElSortType either \u2018Ascending\u2019 or \u2018Descending\u2019. This applies only when the ElSortType is ByName.\u200b", + "Prompt": "OPTIONAL: Sort sense for pElSortType (Default = 'Descending')", "Value": "Descending", "Type": "String" }, + { + "Name": "pDim", + "Prompt": "REQUIRED: Delimited list of dimensions", + "Value": "", + "Type": "String" + }, + { + "Name": "pDelim", + "Prompt": "OPTIONAL: Delimiter for list parameters (Default = '&')", + "Value": "&", + "Type": "String" + }, { "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { - "Name": "pDim", - "Prompt": "REQUIRED: dimension name, accepts wildcards (if = *, then all the dimensions)", - "Value": "", - "Type": "String" - }, - { - "Name": "pDelim", - "Prompt": "OPTIONAL: delimiter character for element list. (default value if blank = '&')", - "Value": "&", + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", "Type": "String" } ], diff --git a/bedrock_processes_json/}bedrock.hier.clone.json b/bedrock_processes_json/}bedrock.hier.clone.json index 3ae9d37..c283390 100644 --- a/bedrock_processes_json/}bedrock.hier.clone.json +++ b/bedrock_processes_json/}bedrock.hier.clone.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.hier.clone", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.clone', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pSrcDim', '', 'pSrcHier', '',\r\n \t'pTgtDim', '', 'pTgtHier', '',\r\n \t'pAttr', 0, 'pUnwind', 0\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will clone the source dimension Hierarchy.\r\n\r\n# Use case: Mostly in Development.\r\n# 1/ Create a duplicate of an existing hierarchy for testing.\r\n\r\n# Note:\r\n# Valid source dimension name (pSrcDim) and target dimension (pTgtDim) names are mandatory otherwise the process will abort.\r\n# Valid source hierarchy name (pSrcHier) is mandatory otherwise the process will abort.\r\n\r\n# Caution:\r\n# - Target hierarchy cannot be `Leaves`.\r\n# - If the target dimension Hierarchy exists then it will be overwritten.\r\n#EndRegion @DOC\r\n\r\n### Global Varaibales ###\r\nStringGlobalVariable ('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode = 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = '%cThisProcName% : %sMessage% : %cUserName%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pSrcDim:%pSrcDim%, pSrcHier:%pSrcHier%, pTgtDim:%pTgtDim%, pTgtHier:%pTgtHier%, pAttr:%pAttr%, pUnwind:%pUnwind%.';\r\ncLangDim = '}Cultures';\r\nnNumLang = DimSiz( cLangDim );\r\n\r\nnProcessSameNamedHier = 0;\r\nsEpilogTgtHier = '';\r\n\r\n## LogOutput parameters\r\nIF ( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\nIf( Scan( ':', pSrcDim ) > 0 & pSrcHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pSrcHier = SubSt( pSrcDim, Scan( ':', pSrcDim ) + 1, Long( pSrcDim ) );\r\n pSrcDim = SubSt( pSrcDim, 1, Scan( ':', pSrcDim ) - 1 );\r\nEndIf;\r\n\r\n## Validate Source dimension\r\nIF( Trim( pSrcDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No source dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nIF( DimensionExists( pSrcDim ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid source dimension: ' | pSrcDim;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate Source hierarchy\r\nIF( Trim( pSrcHier ) @= '' );\r\n pSrcHier = pSrcDim;\r\nElseIF(HierarchyExists(pSrcDim,pSrcHier ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid source hierarchy: ' | pSrcHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate Target dimension\r\nIF( Trim( pTgtDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No target dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( Scan( ':', pTgtDim ) > 0 & pTgtHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pTgtHier = SubSt( pTgtDim, Scan( ':', pTgtDim ) + 1, Long( pTgtDim ) );\r\n pTgtDim = SubSt( pTgtDim, 1, Scan( ':', pTgtDim ) - 1 );\r\nEndIf;\r\n\r\nIf ( DimensionExists( pTgtDim ) = 0 );\r\n DimensionCreate( pTgtDim );\r\n ### In this case clone source hierarchy into same-named hierarchy of the new target dimension first. This will allow attributes to be processed in the data tab.\r\n nProcessSameNamedHier = 1;\r\nEndIf;\r\n\r\n# Validate target hierarchy\r\nIf( pSrcDim @= pTgtDim);\r\n If( pTgtHier @= '' % pTgtHier @= pSrcHier );\r\n pTgtHier = pSrcHier | '_Clone';\r\n EndIf;\r\nElseIf(pTgtHier @= '');\r\n If( nProcessSameNamedHier = 1 );\r\n sEpilogTgtHier = pTgtHier;\r\n pTgtHier = pTgtDim;\r\n Else;\r\n pTgtHier = pSrcHier;\r\n EndIf;\r\nElseIf( nProcessSameNamedHier = 1 );\r\n sEpilogTgtHier = pTgtHier;\r\n pTgtHier = pTgtDim;\r\nEndif;\r\n\r\npTgtHier = Trim(pTgtHier);\r\n\r\nIF(pTgtHier @= 'Leaves' );\r\n nErrors = 1;\r\n sMessage = 'Leaves is an invalid selection for Target Hierarchy: ' | pTgtDim |':'|pTgtHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nIf( DimensionExists( pTgtDim ) = 0 );\r\n If( pUnwind >= 1 );\r\n pUnwind = 2;\r\n EndIf;\r\nElseIf( HierarchyExists( pTgtDim, pTgtHier ) = 0 );\r\n If( pUnwind >= 1 );\r\n pUnwind = 2;\r\n EndIf;\r\nEndIf; \r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### Create target dimension Hierarchy ###\r\nIf( HierarchyExists( pTgtDim, pTgtHier) = 0 );\r\n HierarchyCreate( pTgtDim, pTgtHier );\r\nElse;\r\n IF(pUnwind = 1 );\r\n nRet = ExecuteProcess('}bedrock.hier.unwind',\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pDim', pTgtDim,\r\n 'pHier', pTgtHier,\r\n 'pConsol', '*',\r\n 'pRecursive', 1\r\n );\r\n ELSEIF(pUnwind = 2 );\r\n #Do nothing\r\n ELSEIF(pUnwind = 0 );\r\n HierarchyDeleteAllElements( pTgtDim, pTgtHier );\r\n EndIf;\r\nEndIf;\r\n \r\nIf(pSrcDim @=pSrcHier);\r\n sDimHier = pSrcDim;\r\n Else;\r\n sDimHier =pSrcDim|':'|pSrcHier;\r\n Endif;\r\n \r\n### Set the target Sort Order ###\r\n# CellGetS to }DimensionProperties cube removed\r\n# Placeholder as expecting a TI function to be made available to be able to read these properties\r\n\r\n#HierarchySortOrder(pTgtDim, pTgtHier, sSortComponentsType, sSortComponentsSense, sSortElementsType , sSortElementsSense);\r\n\r\nnSourceHierSize = DimSiz(pSrcDim|':'|pSrcHier);\r\n\r\nnIndex = 1;\r\nWHILE( nIndex <= nSourceHierSize );\r\n sElName = ElementName(pSrcDim, pSrcHier, nIndex);\r\n sElType = ElementType(pSrcDim, pSrcHier, sElName);\r\n HierarchyElementInsert(pTgtDim, pTgtHier, '', sElName, sElType);\r\n nIndex = nIndex + 1;\r\nEND;\r\n\r\n### Assign Data Source ###\r\n\r\nDatasourceNameForServer = pSrcDim|':'|pSrcHier;\r\nDataSourceType = 'SUBSET';\r\nDatasourceDimensionSubset = 'ALL';\r\n\r\n### Replicate Attributes ###\r\n\r\n# Note: DType on Attr dim returns \"AS\", \"AN\" or \"AA\" need to strip off leading \"A\"\r\n\r\nsAttrDim = '}ElementAttributes_' | pSrcDim;\r\nsAttrLoc = '}LocalizedElementAttributes_' | pSrcDim;\r\nsAttrTragetDim = '}ElementAttributes_' | pTgtDim;\r\nsAttrLocTarget = '}LocalizedElementAttributes_' | pTgtDim;\r\n\r\nIf( pAttr = 1 & DimensionExists( sAttrDim ) = 1 );\r\n nNumAttrs = DimSiz( sAttrDim );\r\n nCount = 1;\r\n While( nCount <= nNumAttrs );\r\n sAttrName = DimNm( sAttrDim, nCount );\r\n sAttrType = SubSt(DType( sAttrDim, sAttrName ), 2, 1 );\r\n If ( DimensionExists( sAttrTragetDim ) = 0);\r\n AttrInsert(pTgtDim,'',sAttrName,sAttrType );\r\n ElseIF(DimIx(sAttrTragetDim, sAttrName) = 0);\r\n AttrInsert(pTgtDim,'',sAttrName,sAttrType );\r\n Endif;\r\n nCount = nCount + 1;\r\n End;\r\nEndIf;\r\n\r\n### End Prolog ###", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.clone', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pSrcDim', '', 'pSrcHier', '',\r\n \t'pTgtDim', '', 'pTgtHier', '',\r\n \t'pAttr', 0, 'pUnwind', 0\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will clone the source dimension Hierarchy.\r\n\r\n# Use case: Mostly in Development.\r\n# 1/ Create a duplicate of an existing hierarchy for testing.\r\n\r\n# Note:\r\n# Valid source dimension name (pSrcDim) and target dimension (pTgtDim) names are mandatory otherwise the process will abort.\r\n# Valid source hierarchy name (pSrcHier) is mandatory otherwise the process will abort.\r\n\r\n# Caution:\r\n# - Target hierarchy cannot be `Leaves`.\r\n# - If the target dimension Hierarchy exists then it will be overwritten.\r\n#EndRegion @DOC\r\n\r\n### Global Varaibales ###\r\nStringGlobalVariable ('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode = 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = '%cThisProcName% : %sMessage% : %cUserName%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pSrcDim:%pSrcDim%, pSrcHier:%pSrcHier%, pTgtDim:%pTgtDim%, pTgtHier:%pTgtHier%, pAttr:%pAttr%, pUnwind:%pUnwind%.';\r\ncLangDim = '}Cultures';\r\nnNumLang = DimSiz( cLangDim );\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pSrcDim\": null,\r\n \"pSrcHier\": null,\r\n \"pTgtDim\": \"\",\r\n \"pTgtHier\": \"\",\r\n \"pAttr\": 0,\r\n \"pLogOutput\": 0,\r\n \"pStrictErrorHandling\": 0,\r\n \"pUnwind\": 0\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pSrcDim\": '|StringToJson ( pSrcDim )|',\r\n \"pSrcHier\": '|StringToJson ( pSrcHier )|',\r\n \"pTgtDim\": '|StringToJson ( pTgtDim )|',\r\n \"pTgtHier\": '|StringToJson ( pTgtHier )|',\r\n \"pAttr\": '|NumberToString( pAttr )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|',\r\n \"pUnwind\": '|NumberToString( pUnwind )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npSrcDim = JsonToString( JsonGet( pJson, 'pSrcDim' ) );\r\npSrcHier = JsonToString( JsonGet( pJson, 'pSrcHier' ) );\r\npTgtDim = JsonToString( JsonGet( pJson, 'pTgtDim' ) );\r\npTgtHier = JsonToString( JsonGet( pJson, 'pTgtHier' ) );\r\n# Numeric Parameters\r\npAttr = StringToNumber( JsonToString( JsonGet( pJson, 'pAttr' ) ) );\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\npUnwind = StringToNumber( JsonToString( JsonGet( pJson, 'pUnwind' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\nnProcessSameNamedHier = 0;\r\nsEpilogTgtHier = '';\r\n\r\n## LogOutput parameters\r\nIF ( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\nIf( Scan( ':', pSrcDim ) > 0 & pSrcHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pSrcHier = SubSt( pSrcDim, Scan( ':', pSrcDim ) + 1, Long( pSrcDim ) );\r\n pSrcDim = SubSt( pSrcDim, 1, Scan( ':', pSrcDim ) - 1 );\r\nEndIf;\r\n\r\n## Validate Source dimension\r\nIF( Trim( pSrcDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No source dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nIF( DimensionExists( pSrcDim ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid source dimension: ' | pSrcDim;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate Source hierarchy\r\nIF( Trim( pSrcHier ) @= '' );\r\n pSrcHier = pSrcDim;\r\nElseIF(HierarchyExists(pSrcDim,pSrcHier ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid source hierarchy: ' | pSrcHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate Target dimension\r\nIF( Trim( pTgtDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No target dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( Scan( ':', pTgtDim ) > 0 & pTgtHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pTgtHier = SubSt( pTgtDim, Scan( ':', pTgtDim ) + 1, Long( pTgtDim ) );\r\n pTgtDim = SubSt( pTgtDim, 1, Scan( ':', pTgtDim ) - 1 );\r\nEndIf;\r\n\r\nIf ( DimensionExists( pTgtDim ) = 0 );\r\n DimensionCreate( pTgtDim );\r\n ### In this case clone source hierarchy into same-named hierarchy of the new target dimension first. This will allow attributes to be processed in the data tab.\r\n nProcessSameNamedHier = 1;\r\nEndIf;\r\n\r\n# Validate target hierarchy\r\nIf( pSrcDim @= pTgtDim);\r\n If( pTgtHier @= '' % pTgtHier @= pSrcHier );\r\n pTgtHier = pSrcHier | '_Clone';\r\n EndIf;\r\nElseIf(pTgtHier @= '');\r\n If( nProcessSameNamedHier = 1 );\r\n sEpilogTgtHier = pTgtHier;\r\n pTgtHier = pTgtDim;\r\n Else;\r\n pTgtHier = pSrcHier;\r\n EndIf;\r\nElseIf( nProcessSameNamedHier = 1 );\r\n sEpilogTgtHier = pTgtHier;\r\n pTgtHier = pTgtDim;\r\nEndif;\r\n\r\npTgtHier = Trim(pTgtHier);\r\n\r\nIF(pTgtHier @= 'Leaves' );\r\n nErrors = 1;\r\n sMessage = 'Leaves is an invalid selection for Target Hierarchy: ' | pTgtDim |':'|pTgtHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nIf( DimensionExists( pTgtDim ) = 0 );\r\n If( pUnwind >= 1 );\r\n pUnwind = 2;\r\n EndIf;\r\nElseIf( HierarchyExists( pTgtDim, pTgtHier ) = 0 );\r\n If( pUnwind >= 1 );\r\n pUnwind = 2;\r\n EndIf;\r\nEndIf; \r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### Create target dimension Hierarchy ###\r\nIf( HierarchyExists( pTgtDim, pTgtHier) = 0 );\r\n HierarchyCreate( pTgtDim, pTgtHier );\r\nElse;\r\n IF(pUnwind = 1 );\r\n nRet = ExecuteProcess('}bedrock.hier.unwind',\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pDim', pTgtDim,\r\n 'pHier', pTgtHier,\r\n 'pConsol', '*',\r\n 'pRecursive', 1\r\n );\r\n ELSEIF(pUnwind = 2 );\r\n #Do nothing\r\n ELSEIF(pUnwind = 0 );\r\n HierarchyDeleteAllElements( pTgtDim, pTgtHier );\r\n EndIf;\r\nEndIf;\r\n \r\nIf(pSrcDim @=pSrcHier);\r\n sDimHier = pSrcDim;\r\n Else;\r\n sDimHier =pSrcDim|':'|pSrcHier;\r\n Endif;\r\n \r\n### Set the target Sort Order ###\r\n# CellGetS to }DimensionProperties cube removed\r\n# Placeholder as expecting a TI function to be made available to be able to read these properties\r\n\r\n#HierarchySortOrder(pTgtDim, pTgtHier, sSortComponentsType, sSortComponentsSense, sSortElementsType , sSortElementsSense);\r\n\r\nnSourceHierSize = DimSiz(pSrcDim|':'|pSrcHier);\r\n\r\nnIndex = 1;\r\nWHILE( nIndex <= nSourceHierSize );\r\n sElName = ElementName(pSrcDim, pSrcHier, nIndex);\r\n sElType = ElementType(pSrcDim, pSrcHier, sElName);\r\n HierarchyElementInsert(pTgtDim, pTgtHier, '', sElName, sElType);\r\n nIndex = nIndex + 1;\r\nEND;\r\n\r\n### Assign Data Source ###\r\n\r\nDatasourceNameForServer = pSrcDim|':'|pSrcHier;\r\nDataSourceType = 'SUBSET';\r\nDatasourceDimensionSubset = 'ALL';\r\n\r\n### Replicate Attributes ###\r\n\r\n# Note: DType on Attr dim returns \"AS\", \"AN\" or \"AA\" need to strip off leading \"A\"\r\n\r\nsAttrDim = '}ElementAttributes_' | pSrcDim;\r\nsAttrLoc = '}LocalizedElementAttributes_' | pSrcDim;\r\nsAttrTragetDim = '}ElementAttributes_' | pTgtDim;\r\nsAttrLocTarget = '}LocalizedElementAttributes_' | pTgtDim;\r\n\r\nIf( pAttr = 1 & DimensionExists( sAttrDim ) = 1 );\r\n nNumAttrs = DimSiz( sAttrDim );\r\n nCount = 1;\r\n While( nCount <= nNumAttrs );\r\n sAttrName = DimNm( sAttrDim, nCount );\r\n sAttrType = SubSt(DType( sAttrDim, sAttrName ), 2, 1 );\r\n If ( DimensionExists( sAttrTragetDim ) = 0);\r\n AttrInsert(pTgtDim,'',sAttrName,sAttrType );\r\n ElseIF(DimIx(sAttrTragetDim, sAttrName) = 0);\r\n AttrInsert(pTgtDim,'',sAttrName,sAttrType );\r\n Endif;\r\n nCount = nCount + 1;\r\n End;\r\nEndIf;\r\n\r\n### End Prolog ###", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock Ver 4.0.0~~##\r\n################################################################################################# \r\n\r\n\r\n### Check for errors in prolog ###\r\n\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### Add Elements to target dimension ###\r\n\r\nsElType = ElementType(pSrcDim, pSrcHier, vEle);\r\n\r\nIF( sElType @= 'C' & ElementComponentCount( pSrcDim, pSrcHier, vEle ) > 0 );\r\n nChildren = ElementComponentCount( pSrcDim, pSrcHier, vEle );\r\n nCount = 1;\r\n While( nCount <= nChildren );\r\n sChildElement = ElementComponent( pSrcDim, pSrcHier, vEle, nCount );\r\n sChildWeight = ElementWeight( pSrcDim,pSrcHier, vEle, sChildElement );\r\n HierarchyElementComponentAdd(pTgtDim, pTgtHier, vEle, sChildElement, sChildWeight);\r\n nCount = nCount + 1;\r\n End;\r\nEndIf;\r\n\r\n### End MetaData ###", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock Ver 4.0.0~~##\r\n################################################################################################# \r\n\r\n\r\n### Check for errors in prolog ###\r\n\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### Replicate Attributes ###\r\n# Note: DTYPE on Attr dim returns \"AS\", \"AN\" or \"AA\" need to strip off leading \"A\"\r\n\r\nIf( pAttr = 1 & DimensionExists( sAttrDim ) = 1 );\r\n\r\n nAttr = 1;\r\n While( nAttr <= nNumAttrs );\r\n sAttrName = DimNm( sAttrDim, nAttr );\r\n sAttrType = SubSt( DTYPE( sAttrDim, sAttrName ), 2, 1 );\r\n \r\n If( sAttrType @= 'S' % sAttrType @= 'A' );\r\n sAttrVal = ElementAttrS( pSrcDim, pSrcHier, vEle, sAttrName );\r\n \r\n If( sAttrVal @<> '' );\r\n If( CellIsUpdateable( '}ElementAttributes_' | pTgtDim, pTgtHier:vEle, sAttrName ) = 1 );\r\n If( sAttrType @= 'A' );\r\n ElementAttrPutS( sAttrVal, pTgtDim, pTgtHier, vEle, sAttrName, 1 );\r\n Else;\r\n ElementAttrPutS( sAttrVal, pTgtDim, pTgtHier, vEle, sAttrName );\r\n EndIf;\r\n EndIf;\r\n EndIf;\r\n Else;\r\n nAttrVal = ElementAttrN( pSrcDim, pSrcHier, vEle, sAttrName );\r\n If( nAttrVal <> 0 );\r\n If( CellIsUpdateable( '}ElementAttributes_' | pTgtDim, pTgtHier:vEle, sAttrName ) = 1 );\r\n ElementAttrPutN( nAttrVal, pTgtDim, pTgtHier, vEle, sAttrName );\r\n EndIf;\r\n EndIf; \r\n EndIf;\r\n # check for localized attributes\r\n If( CubeExists( sAttrLoc ) = 1 );\r\n nLang = 1;\r\n While( nLang <= nNumLang );\r\n sLang = DimNm( cLangDim, nLang );\r\n If( sAttrType @= 'A' % sAttrType @= 'S' );\r\n sAttrVal = ElementAttrS( pSrcDim, pSrcHier, vEle, sAttrName );\r\n sAttrValLoc = ElementAttrSL( pSrcDim, pSrcHier, vEle, sAttrName, sLang );\r\n If( sAttrValLoc @= sAttrVal ); sAttrValLoc = ''; EndIf;\r\n Else;\r\n nAttrVal = ElementAttrN( pSrcDim, pSrcHier, vEle, sAttrName );\r\n nAttrValLoc = ElementAttrNL( pSrcDim, pSrcHier, vEle, sAttrName, sLang );\r\n EndIf;\r\n If( CubeExists( sAttrLocTarget ) = 0 );\r\n If( sAttrType @= 'A' );\r\n ElementAttrPutS( sAttrValLoc, pTgtDim, pTgtHier, vEle, sAttrName, sLang, 1 );\r\n ElseIf( sAttrType @= 'N' );\r\n ElementAttrPutN( nAttrValLoc, pTgtDim, pTgtHier, vEle, sAttrName, sLang );\r\n Else;\r\n ElementAttrPutS( sAttrValLoc, pTgtDim, pTgtHier, vEle, sAttrName, sLang );\r\n EndIf;\r\n ElseIf(CubeExists( sAttrLocTarget ) = 1 );\r\n If( CellIsUpdateable( sAttrLocTarget, pTgtHier:vEle, sLang, sAttrName ) = 1 );\r\n If( sAttrType @= 'A' );\r\n ElementAttrPutS( sAttrValLoc, pTgtDim, pTgtHier, vEle, sAttrName, sLang, 1 );\r\n ElseIf( sAttrType @= 'N' );\r\n ElementAttrPutN( nAttrValLoc, pTgtDim, pTgtHier, vEle, sAttrName, sLang );\r\n Else;\r\n ElementAttrPutS( sAttrValLoc, pTgtDim, pTgtHier, vEle, sAttrName, sLang );\r\n EndIf;\r\n EndIf;\r\n EndIf;\r\n nLang = nLang + 1;\r\n End;\r\n EndIf;\r\n nAttr = nAttr + 1;\r\n End;\r\n\r\nEndIf;\r\n\r\n### End Data ###", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n\r\nIf(pTgtDim @=pTgtHier);\r\n sTargetDimHier = pTgtDim;\r\nElse;\r\n sTargetDimHier =pTgtDim|':'|pTgtHier;\r\nEndIf;\r\n\r\n### Set the target Sort Order ###\r\n# CellPutS to }DimensionProperties cube removed\r\n# Placeholder as expecting a TI function to be made available to be able to modify these properties\r\n \r\n### If a new dimension has been created, call the process recursively to clone the alternate hierarchy, after the same named hierarchy has been processed\r\nIf( nProcessSameNamedHier = 1 );\r\n nRet = ExecuteProcess('}bedrock.hier.clone',\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pSrcDim', pSrcDim,\r\n 'pSrcHier',pSrcHier,\r\n 'pTgtDim', pTgtDim,\r\n 'pTgtHier', sEpilogTgtHier,\r\n 'pAttr', pAttr,\r\n 'pUnwind', pUnwind\r\n );\r\nEndIf;\r\n \r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully cloned the %pSrcDim%:%pSrcHier% dimension:hierarchy to %pTgtDim%:%pTgtHier%' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n### End Epilog ###", @@ -13,53 +13,59 @@ "subset": "All" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pSrcDim", - "Prompt": "REQUIRED: Source Dimension", + "Prompt": "REQUIRED: Source dimension name", "Value": "", "Type": "String" }, { "Name": "pSrcHier", - "Prompt": "REQUIRED: Source Hierarchy", + "Prompt": "REQUIRED: Source hierarchy name", "Value": "", "Type": "String" }, { "Name": "pTgtDim", - "Prompt": "REQUIRED: Target Dimension (can be the same as source)", + "Prompt": "OPTIONAL: Target dimension name (Default = pSrcDim)", "Value": "", "Type": "String" }, { "Name": "pTgtHier", - "Prompt": "OPTIONAL: Target Hierarchy (will default to SrcHier_Clone if the dimensions are the same)", + "Prompt": "OPTIONAL: Target hierarchy name (If pSrcDim = pTgtDim, Default = pSrcHier | '_Clone')", "Value": "", "Type": "String" }, { "Name": "pAttr", - "Prompt": "OPTIONAL: Include Attributes? (Boolean 1=True)", + "Prompt": "OPTIONAL: Include attributes (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { "Name": "pUnwind", - "Prompt": "REQUIRED: Unwind? (0 = Delete all Elements, 1 = Unwind Existing Elements, 2 = Do not change Existing Elements (Only relevant if target hierarchy exists) )", + "Prompt": "OPTIONAL: Unwind hierarchies after process (0 = Delete all elements, 1 = Unwind existing elements, 2 = Do not change existing elements. Default = 0)", "Value": 0, "Type": "Numeric" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [ diff --git a/bedrock_processes_json/}bedrock.hier.consol.delete.json b/bedrock_processes_json/}bedrock.hier.consol.delete.json index ebd49c0..4ea6227 100644 --- a/bedrock_processes_json/}bedrock.hier.consol.delete.json +++ b/bedrock_processes_json/}bedrock.hier.consol.delete.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.hier.consol.delete", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.consol.delete', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pDim', '', 'pHier', '', 'pEle', '',\r\n \t'pDelim', '&'\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will delete a specified C-Level item **or** ALL consolidations in the dimension hierarchy. \r\n\r\n# Use case: Could be used during development or in production.\r\n# 1/ Delete a specific or all C-Level items in a hierarchy.\r\n\r\n# Note:\r\n# Valid dimension name (pDim) is mandatory otherwise the process will abort. Control dimensions are excluded.\r\n# The hierarchy (pHier) will default to pDim if not specified, otherwise it must be valid else the process will abort.\r\n# **ALL** consoldidated items in hierarchy will be deleted if consolidated item (pEle) is specified as \\*, otherwise it needs to contain valid c-level item(s). \r\n# Caution: Target hierarchy (pHier) cannot be `Leaves`.\r\n#EndRegion @DOC\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncUserName = TM1User();\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pHier:%pHier%, pEle:%pEle%, pDelim:%pDelim%.';\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\nIf( Scan( ':', pDim ) > 0 & pHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pHier = SubSt( pDim, Scan( ':', pDim ) + 1, Long( pDim ) );\r\n pDim = SubSt( pDim, 1, Scan( ':', pDim ) - 1 );\r\nEndIf;\r\n\r\n## Validate Dimension\r\nIf( Trim( pDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( DimensionExists( pDim ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Dimension: ' | pDim | ' does not exist on server.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n## Validate Hierarchy\r\nIF(pHier @= 'Leaves' );\r\n nErrors = 1;\r\n sMessage = 'Invalid Hierarchy: ' | pDim |':'|pHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n## Validate Elements\r\nIF(pEle @= '' );\r\n nErrors = 1;\r\n sMessage = 'Element cannot be empty. Use * for all elements';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n\r\nIf( Trim( pHier ) @= '' );\r\n sHier = pDim;\r\nElse;\r\n sHier = pHier;\r\nEndIf;\r\n\r\nIf( HierarchyExists( pDim, sHier ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'The Hierarchy ' | sHier | ' does not exist.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# If blank delimiter specified then convert to default\r\nIf( pDelim @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors > 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\nsEles = pEle;\r\nnDelimiterIndex = 1;\r\nWhile( nDelimiterIndex <> 0 );\r\n \r\n nDelimiterIndex = Scan( pDelim, sEles );\r\n If( nDelimiterIndex = 0 );\r\n sEle = sEles;\r\n Else;\r\n sEle = Trim( SubSt( sEles, 1, nDelimiterIndex - 1 ) );\r\n sEles = Trim( Subst( sEles, nDelimiterIndex + Long(pDelim), Long( sEles ) ) );\r\n EndIf;\r\n \r\n # Check if a wildcard has been used to specify the Element name.\r\n # If it hasn't then just delete the Element if it exists\r\n If( sEle @= '*' );\r\n nElementIndex = Dimsiz(pDim|':'|sHier);\r\n While( nElementIndex >= 1 );\r\n sEle = ElementName( pDim, sHier, nElementIndex );\r\n sElType = ElementType( pDim, sHier, sEle );\r\n If( sElType @= 'C' );\r\n HierarchyElementDelete( pDim, sHier,sEle );\r\n EndIf;\r\n nElementIndex = nElementIndex - 1;\r\n End;\r\n ElseIf( Scan( '*', sEle ) = 0);\r\n If( HierarchyElementExists( pDim,sHier, sEle ) = 1 );\r\n sElType = ElementType( pDim, sHier, sEle ); \r\n If( sElType @='C' );\r\n HierarchyElementDelete( pDim, sHier,sEle );\r\n EndIf;\r\n Else;\r\n nErrors = 1;\r\n sMessage = 'The Hierarchy ' | sHier | ' does not have element ' | sEle;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n EndIf;\r\n Else;\r\n # Wildcard search string\r\n sEle = '\"'|sEle|'\"';\r\n sProc = '}bedrock.hier.sub.create.bymdx';\r\n sMdx = '{TM1FILTERBYPATTERN( {TM1SUBSETALL([ ' |pDim|'].['|sHier |' ])},'| sEle| ')}';\r\n ExecuteProcess('}bedrock.hier.sub.create.bymdx',\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pDim', pDim,\r\n \t'pHier', sHier,\r\n \t'pSub', cTempSub,\r\n \t'pMDXExpr', sMdx,\r\n \t'pConvertToStatic', 1,\r\n \t'pTemp', 1\r\n );\r\n nCount = HierarchySubsetGetSize(pDim, sHier, cTempSub);\r\n While( nCount >= 1 );\r\n sElement = HierarchySubsetGetElementName(pDim, sHier, cTempSub, nCount);\r\n sElType = ElementType( pDim, sHier, sElement );\r\n If( sElType @= 'C' );\r\n HierarchyElementDelete( pDim, sHier,sElement );\r\n EndIf; \r\n nCount = nCount - 1;\r\n End;\r\n EndIf;\r\n\r\nEnd;\r\n\r\n### End Prolog ###", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.consol.delete', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pDim', '', 'pHier', '', 'pEle', '',\r\n \t'pDelim', '&'\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will delete a specified C-Level item **or** ALL consolidations in the dimension hierarchy. \r\n\r\n# Use case: Could be used during development or in production.\r\n# 1/ Delete a specific or all C-Level items in a hierarchy.\r\n\r\n# Note:\r\n# Valid dimension name (pDim) is mandatory otherwise the process will abort. Control dimensions are excluded.\r\n# The hierarchy (pHier) will default to pDim if not specified, otherwise it must be valid else the process will abort.\r\n# **ALL** consoldidated items in hierarchy will be deleted if consolidated item (pEle) is specified as \\*, otherwise it needs to contain valid c-level item(s). \r\n# Caution: Target hierarchy (pHier) cannot be `Leaves`.\r\n#EndRegion @DOC\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncUserName = TM1User();\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pHier:%pHier%, pEle:%pEle%, pDelim:%pDelim%.';\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pDelim\": \"&\",\r\n \"pDim\": null,\r\n \"pEle\": null,\r\n \"pHier\": \"\",\r\n \"pLogOutput\": 0,\r\n \"pStrictErrorHandling\": 0\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pDelim\": '|StringToJson ( pDelim )|',\r\n \"pDim\": '|StringToJson ( pDim )|',\r\n \"pEle\": '|StringToJson ( pEle )|',\r\n \"pHier\": '|StringToJson ( pHier )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npDelim = JsonToString( JsonGet( pJson, 'pDelim' ) );\r\npDim = JsonToString( JsonGet( pJson, 'pDim' ) );\r\npEle = JsonToString( JsonGet( pJson, 'pEle' ) );\r\npHier = JsonToString( JsonGet( pJson, 'pHier' ) );\r\n# Numeric Parameters\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\nIf( Scan( ':', pDim ) > 0 & pHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pHier = SubSt( pDim, Scan( ':', pDim ) + 1, Long( pDim ) );\r\n pDim = SubSt( pDim, 1, Scan( ':', pDim ) - 1 );\r\nEndIf;\r\n\r\n## Validate Dimension\r\nIf( Trim( pDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( DimensionExists( pDim ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Dimension: ' | pDim | ' does not exist on server.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n## Validate Hierarchy\r\nIF(pHier @= 'Leaves' );\r\n nErrors = 1;\r\n sMessage = 'Invalid Hierarchy: ' | pDim |':'|pHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n## Validate Elements\r\nIF(pEle @= '' );\r\n nErrors = 1;\r\n sMessage = 'Element cannot be empty. Use * for all elements';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n\r\nIf( Trim( pHier ) @= '' );\r\n sHier = pDim;\r\nElse;\r\n sHier = pHier;\r\nEndIf;\r\n\r\nIf( HierarchyExists( pDim, sHier ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'The Hierarchy ' | sHier | ' does not exist.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# If blank delimiter specified then convert to default\r\nIf( pDelim @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors > 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\nsEles = pEle;\r\nnDelimiterIndex = 1;\r\nWhile( nDelimiterIndex <> 0 );\r\n \r\n nDelimiterIndex = Scan( pDelim, sEles );\r\n If( nDelimiterIndex = 0 );\r\n sEle = sEles;\r\n Else;\r\n sEle = Trim( SubSt( sEles, 1, nDelimiterIndex - 1 ) );\r\n sEles = Trim( Subst( sEles, nDelimiterIndex + Long(pDelim), Long( sEles ) ) );\r\n EndIf;\r\n \r\n # Check if a wildcard has been used to specify the Element name.\r\n # If it hasn't then just delete the Element if it exists\r\n If( sEle @= '*' );\r\n nElementIndex = Dimsiz(pDim|':'|sHier);\r\n While( nElementIndex >= 1 );\r\n sEle = ElementName( pDim, sHier, nElementIndex );\r\n sElType = ElementType( pDim, sHier, sEle );\r\n If( sElType @= 'C' );\r\n HierarchyElementDelete( pDim, sHier,sEle );\r\n EndIf;\r\n nElementIndex = nElementIndex - 1;\r\n End;\r\n ElseIf( Scan( '*', sEle ) = 0);\r\n If( HierarchyElementExists( pDim,sHier, sEle ) = 1 );\r\n sElType = ElementType( pDim, sHier, sEle ); \r\n If( sElType @='C' );\r\n HierarchyElementDelete( pDim, sHier,sEle );\r\n EndIf;\r\n Else;\r\n nErrors = 1;\r\n sMessage = 'The Hierarchy ' | sHier | ' does not have element ' | sEle;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n EndIf;\r\n Else;\r\n # Wildcard search string\r\n sEle = '\"'|sEle|'\"';\r\n sProc = '}bedrock.hier.sub.create.bymdx';\r\n sMdx = '{TM1FILTERBYPATTERN( {TM1SUBSETALL([ ' |pDim|'].['|sHier |' ])},'| sEle| ')}';\r\n ExecuteProcess('}bedrock.hier.sub.create.bymdx',\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pDim', pDim,\r\n \t'pHier', sHier,\r\n \t'pSub', cTempSub,\r\n \t'pMDXExpr', sMdx,\r\n \t'pConvertToStatic', 1,\r\n \t'pTemp', 1\r\n );\r\n nCount = HierarchySubsetGetSize(pDim, sHier, cTempSub);\r\n While( nCount >= 1 );\r\n sElement = HierarchySubsetGetElementName(pDim, sHier, cTempSub, nCount);\r\n sElType = ElementType( pDim, sHier, sElement );\r\n If( sElType @= 'C' );\r\n HierarchyElementDelete( pDim, sHier,sElement );\r\n EndIf; \r\n nCount = nCount - 1;\r\n End;\r\n EndIf;\r\n\r\nEnd;\r\n\r\n### End Prolog ###", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully deleted the appropriate consolidated elements in hierarchy %pDim%:%pHier%.' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n### End Epilog ###", @@ -10,41 +10,47 @@ "Type": "None" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pDim", - "Prompt": "REQUIRED: Dimension name", + "Prompt": "REQUIRED: Delimited list of dimensions", "Value": "", "Type": "String" }, { "Name": "pHier", - "Prompt": "OPTIONAL: Hierarchy name (if blank then same named hierarchy as dimension is assumed)", + "Prompt": "OPTIONAL: Hierarchy name (Default = pDim)", "Value": "", "Type": "String" }, { "Name": "pEle", - "Prompt": "OPTIONAL: Filter on elements (element list separated by delimiter, accepts wildcards (if * then all the consolidation elements get deleted))", + "Prompt": "REQUIRED: Delimited list of elements", "Value": "", "Type": "String" }, { "Name": "pDelim", - "Prompt": "OPTIONAL: Delimiter character for element list (default to '&' if blank)", + "Prompt": "OPTIONAL: Delimiter for list parameters (Default = '&')", "Value": "&", "Type": "String" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [], diff --git a/bedrock_processes_json/}bedrock.hier.consol.flat.create.json b/bedrock_processes_json/}bedrock.hier.consol.flat.create.json index e9341eb..b61f4c1 100644 --- a/bedrock_processes_json/}bedrock.hier.consol.flat.create.json +++ b/bedrock_processes_json/}bedrock.hier.consol.flat.create.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.hier.consol.flat.create", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.consol.flat.create', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pDim', '', 'pHier', '',\r\n \t'pSrcConsol', '', 'pTgtConsol', '', 'pWeight', 1\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n### Start Prolog ###\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will add consolidated element pTgtConsol in the dimension hierarchy. \r\n\r\n# Use case: Intended for Development but could be used in production too.\r\n# 1/ Create a new hierarchy for testing.\r\n# 2/ Create a new hierarchy to reflect new business needs.\r\n\r\n# Note:\r\n# If source parent element (pSrcConsol) is defined then all its leaf elements will be copied to target\r\n# parent element consolidation. Otherwise all leaf elements in the dimension hierarchy will be \r\n# added into target parent element consolidation.\r\n# Valid source dimension name (pDim), hierarchy (pHier) and taget parent element (pTgtConsol)\r\n# are mandatory otherwise the process will abort.\r\n# Weight of all added elements into target parent consolidation will be assigned accoring to\r\n# pWeight parameter value.\r\n\r\n# Caution: If the target element pTgtConsol exists in the hierarchy, then it will be overwritten.\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent= 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim=%pDim%, pHier=%pHier%, pSrcConsol=%pSrcConsol%, pTgtConsol=%pTgtConsol%.';\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\nIf( Scan( ':', pDim ) > 0 & pHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pHier = SubSt( pDim, Scan( ':', pDim ) + 1, Long( pDim ) );\r\n pDim = SubSt( pDim, 1, Scan( ':', pDim ) - 1 );\r\nEndIf;\r\n\r\nIF( Trim( pDim ) @= '' );\r\n ## No dimension nominated.\r\n nErrors = 1;\r\n sMessage = 'No dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nIf( DimensionExists( pDim) = 0 );\r\n ## Dimension does not exist in the model.\r\n nErrors = 1;\r\n sMessage = 'The dimension does not exist in the model: ' | pDim;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nIF( SUBST( pDim, 1, 1 ) @= '}' );\r\n ## Nominated dimension is a system dimension.\r\n nErrors = 1;\r\n sMessage = 'Can not modify a system dimension with this Bedrock.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n## Validate hierarchy\r\nIF( Trim( pHier ) @= '' );\r\n pHier = pDim;\r\nEndIf;\r\n\r\nIF( HierarchyExists(pDim, pHier ) = 0 % pHier @= 'Leaves');\r\n nErrors = 1;\r\n sMessage = 'Invalid dimension Hierarchy: ' | pDim |':'|pHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n## Validate consolidation Parameter\r\npTgtConsol = Trim( pTgtConsol );\r\nIf( pTgtConsol @= '');\r\n nErrors = 1;\r\n sMessage = 'No target parent element supplied.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( pTgtConsol @= pSrcConsol );\r\n nErrors = 1;\r\n sMessage = 'Target and source consolidations can''t be the same elements: ' | pTgtConsol |':'| pSrcConsol;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndif;\r\n\r\n## Validate Member Consolidation\r\npSrcConsol = Trim( pSrcConsol );\r\nIF( pSrcConsol @<> '' );\r\n ## A source consolidation has been nominated.\r\n IF( ElementIndex( pDim, pHier, pSrcConsol ) = 0 );\r\n ## The Member Consolidation does not exist in the dimension.\r\n nErrors = 1;\r\n sMessage = Expand('Source consolidation %pSrcConsol% does not exist in the dimension:hierarchy: %pDim%:%pHier%.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n ENDIF;\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### UNWIND CONSOLIDATION ###\r\nIF( ElementIndex( pDim, pHier, pTgtConsol ) > 0 );\r\n ExecuteProcess('}bedrock.hier.unwind'\r\n ,'pStrictErrorHandling', pStrictErrorHandling\r\n ,'pDim', pDim\r\n ,'pHier',pHier\r\n ,'pConsol', pTgtConsol\r\n ,'pRecursive', 0\r\n );\r\nElse;\r\n HierarchyElementInsert( pDim, pHier, '', pTgtConsol, 'C' );\r\nENDIF;\r\n\r\n### Assign Datasource ###\r\nDatasourceNameForServer = pDim|':'|pHier;\r\nDataSourceDimensionSubset = 'All';\r\n\r\n### End Prolog ###", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.consol.flat.create', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pDim', '', 'pHier', '',\r\n \t'pSrcConsol', '', 'pTgtConsol', '', 'pWeight', 1\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n### Start Prolog ###\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will add consolidated element pTgtConsol in the dimension hierarchy. \r\n\r\n# Use case: Intended for Development but could be used in production too.\r\n# 1/ Create a new hierarchy for testing.\r\n# 2/ Create a new hierarchy to reflect new business needs.\r\n\r\n# Note:\r\n# If source parent element (pSrcConsol) is defined then all its leaf elements will be copied to target\r\n# parent element consolidation. Otherwise all leaf elements in the dimension hierarchy will be \r\n# added into target parent element consolidation.\r\n# Valid source dimension name (pDim), hierarchy (pHier) and taget parent element (pTgtConsol)\r\n# are mandatory otherwise the process will abort.\r\n# Weight of all added elements into target parent consolidation will be assigned accoring to\r\n# pWeight parameter value.\r\n\r\n# Caution: If the target element pTgtConsol exists in the hierarchy, then it will be overwritten.\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent= 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim=%pDim%, pHier=%pHier%, pSrcConsol=%pSrcConsol%, pTgtConsol=%pTgtConsol%.';\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pDim\": null,\r\n \"pHier\": \"\",\r\n \"pSrcConsol\": \"\",\r\n \"pTgtConsol\": \"\",\r\n \"pLogOutput\": 0,\r\n \"pStrictErrorHandling\": 0,\r\n \"pWeight\": 1\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pDim\": '|StringToJson ( pDim )|',\r\n \"pHier\": '|StringToJson ( pHier )|',\r\n \"pSrcConsol\": '|StringToJson ( pSrcConsol )|',\r\n \"pTgtConsol\": '|StringToJson ( pTgtConsol )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|',\r\n \"pWeight\": '|NumberToString( pWeight )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npDim = JsonToString( JsonGet( pJson, 'pDim' ) );\r\npHier = JsonToString( JsonGet( pJson, 'pHier' ) );\r\npSrcConsol = JsonToString( JsonGet( pJson, 'pSrcConsol' ) );\r\npTgtConsol = JsonToString( JsonGet( pJson, 'pTgtConsol' ) );\r\n# Numeric Parameters\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\npWeight = StringToNumber( JsonToString( JsonGet( pJson, 'pWeight' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\nIf( Scan( ':', pDim ) > 0 & pHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pHier = SubSt( pDim, Scan( ':', pDim ) + 1, Long( pDim ) );\r\n pDim = SubSt( pDim, 1, Scan( ':', pDim ) - 1 );\r\nEndIf;\r\n\r\nIF( Trim( pDim ) @= '' );\r\n ## No dimension nominated.\r\n nErrors = 1;\r\n sMessage = 'No dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nIf( DimensionExists( pDim) = 0 );\r\n ## Dimension does not exist in the model.\r\n nErrors = 1;\r\n sMessage = 'The dimension does not exist in the model: ' | pDim;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nIF( SUBST( pDim, 1, 1 ) @= '}' );\r\n ## Nominated dimension is a system dimension.\r\n nErrors = 1;\r\n sMessage = 'Can not modify a system dimension with this Bedrock.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n## Validate hierarchy\r\nIF( Trim( pHier ) @= '' );\r\n pHier = pDim;\r\nEndIf;\r\n\r\nIF( HierarchyExists(pDim, pHier ) = 0 % pHier @= 'Leaves');\r\n nErrors = 1;\r\n sMessage = 'Invalid dimension Hierarchy: ' | pDim |':'|pHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n## Validate consolidation Parameter\r\npTgtConsol = Trim( pTgtConsol );\r\nIf( pTgtConsol @= '');\r\n nErrors = 1;\r\n sMessage = 'No target parent element supplied.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( pTgtConsol @= pSrcConsol );\r\n nErrors = 1;\r\n sMessage = 'Target and source consolidations can''t be the same elements: ' | pTgtConsol |':'| pSrcConsol;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndif;\r\n\r\n## Validate Member Consolidation\r\npSrcConsol = Trim( pSrcConsol );\r\nIF( pSrcConsol @<> '' );\r\n ## A source consolidation has been nominated.\r\n IF( ElementIndex( pDim, pHier, pSrcConsol ) = 0 );\r\n ## The Member Consolidation does not exist in the dimension.\r\n nErrors = 1;\r\n sMessage = Expand('Source consolidation %pSrcConsol% does not exist in the dimension:hierarchy: %pDim%:%pHier%.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n ENDIF;\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### UNWIND CONSOLIDATION ###\r\nIF( ElementIndex( pDim, pHier, pTgtConsol ) > 0 );\r\n ExecuteProcess('}bedrock.hier.unwind'\r\n ,'pStrictErrorHandling', pStrictErrorHandling\r\n ,'pDim', pDim\r\n ,'pHier',pHier\r\n ,'pConsol', pTgtConsol\r\n ,'pRecursive', 0\r\n );\r\nElse;\r\n HierarchyElementInsert( pDim, pHier, '', pTgtConsol, 'C' );\r\nENDIF;\r\n\r\n### Assign Datasource ###\r\nDatasourceNameForServer = pDim|':'|pHier;\r\nDataSourceDimensionSubset = 'All';\r\n\r\n### End Prolog ###", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock Ver 4.0.0~~##\r\n################################################################################################# \r\n\r\n### Start Metadata ###\r\n\r\n### VALIDATE RECORD ###\r\n\r\nsElType = ElementType( pDim, pHier, vElement );\r\nIF( sElType @<> 'N' );\r\n ## The element is not a 'N' element.\r\n ITEMSKIP;\r\nENDIF;\r\n\r\nIF( pSrcConsol @<> '' );\r\n ## A member consolidation is been used.\r\n IF( ElementIsAncestor( pDim, pHier, pSrcConsol, vElement ) = 0 );\r\n ## The element is not a member of the nominated consolidation.\r\n ITEMSKIP;\r\n ENDIF;\r\nENDIF; \r\n\r\n### BUILD CONSOLIDATION ###\r\n\r\nIf( nErrors = 0 );\r\n HierarchyElementComponentAdd( pDim, pHier, pTgtConsol, vElement, pWeight );\r\nEndIf;\r\n\r\n### End Metadata ###", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock Ver 4.0.0~~##\r\n################################################################################################# \r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully created a consolidation %pTgtConsol% in the hierarchy %pDim%:%pHier%.' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;", @@ -13,27 +13,15 @@ "subset": "All" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pDim", - "Prompt": "REQUIRED: Dimension", + "Prompt": "REQUIRED: Delimited list of dimensions", "Value": "", "Type": "String" }, { "Name": "pHier", - "Prompt": "OPTIONAL: Hierarchy (will default to dimension name if blank)", + "Prompt": "OPTIONAL: Hierarchy name (Default = pDim)", "Value": "", "Type": "String" }, @@ -45,15 +33,33 @@ }, { "Name": "pTgtConsol", - "Prompt": "REQUIRED: Target consolidated element name", + "Prompt": "OPTIONAL: Target consolidated element name", "Value": "", "Type": "String" }, { "Name": "pWeight", - "Prompt": "OPTIONAL: Component Weight", + "Prompt": "OPTIONAL: Component weight (Default = 1)", "Value": 1, "Type": "Numeric" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [ diff --git a/bedrock_processes_json/}bedrock.hier.create.fromattribute.json b/bedrock_processes_json/}bedrock.hier.create.fromattribute.json index c8305eb..c7def8a 100644 --- a/bedrock_processes_json/}bedrock.hier.create.fromattribute.json +++ b/bedrock_processes_json/}bedrock.hier.create.fromattribute.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.hier.create.fromattribute", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.create.fromattribute', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pDim', '', 'pSrcHier', '', 'pTgtHier', '', 'pAttr', '',\r\n \t'pTopNode', 'Total ', 'pPrefix', '', 'pSuffix', '',\r\n \t'pSkipBlank', 0, 'pUnallocated', 'Undefined ', 'pUnwind', 0\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will create a new dimension hierarchy from attribute values.\r\n\r\n# Note:\r\n# Valid dimension name (pDim) and attribute name (pAttr) are mandatory, otherwise the\r\n# process will abort.\r\n\r\n# Caution: It is assumed each element exists __only once__ within the hierarchy. This should hold true except in exceptional circumstances.\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncSubset = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pSrcHier:%pSrcHier%, pTgtHier:%pTgtHier%, pAttr:%pAttr%, pTopNode:%pTopNode%, pPrefix:%pPrefix%, pSuffix:%pSuffix%, pSkipBlank:%pSkipBlank%, pUnallocated:%pUnallocated%.';\r\ncAttributeDim = '}ElementAttributes_' | pDim;\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\nIf( Scan( ':', pDim ) > 0 & pSrcHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pSrcHier = SubSt( pDim, Scan( ':', pDim ) + 1, Long( pDim ) );\r\n pDim = SubSt( pDim, 1, Scan( ':', pDim ) - 1 );\r\nEndIf;\r\n\r\nIF( Trim ( pSrcHier ) @= Trim ( pTgtHier ) & pTgtHier @<> '' );\r\n nErrors = 1;\r\n sMessage = 'Source and target Herarchy can not be the same';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf; \r\n \r\n## Validate dimension\r\nIf( Trim( pDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( DimensionExists( pDim ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Dimension: ' | pDim | ' does not exist.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n## Validate Hierarchy\r\nIF( Trim( pSrcHier ) @= '' );\r\n pSrcHier = Trim( pDim );\r\nEndIf;\r\n\r\nIF( HierarchyExists( pDim, pSrcHier ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid dimension Hierarchy: ' | pDim |':'|pSrcHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\npnew =DType( cAttributeDim, pAttr );\r\n## Validate attribute\r\nIf( Trim( pAttr ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No attribute specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( DimIx( cAttributeDim, pAttr ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Attribute: ' | pAttr | ' does not exists in dimension: ' | pDim;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( DType( cAttributeDim, pAttr ) @<> 'AS' & DType( cAttributeDim, pAttr ) @<> 'AN');\r\n ### as alias values are all unique, not applicable for creating hierarchy\r\n nErrors = 1;\r\n sMessage = 'Only string and numeric attributes may be used for this process.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n## Validate Top node name\r\nIF( Trim( pTopNode ) @= '' );\r\n sTopNode = 'All ' | pAttr;\r\nElseIF( Subst(Trim( pTopNode ),1,7 ) @= '' );\r\n sTopNode = pAttr | ' ' | Subst( pTopNode, 8, Long( pTopNode ) );\r\nElseIF( Subst( pTopNode, Long( pTopNode )-7, 8 ) @= '' );\r\n sTopNode = Subst( pTopNode, 1, Long( pTopNode )-8 ) | ' ' | pAttr;\r\nElseIF( Scan( '', pTopNode ) >0 );\r\n sTopNode = Subst( pTopNode, 1, Scan( '', pTopNode )-1 ) | pAttr | Subst( pTopNode, Scan( '', pTopNode )+7,Long(pTopNode) );\r\nElse;\t\r\n sTopNode = pTopNode;\r\nEndIf;\r\n\r\n## Validate Unallocated node name\r\nIF( Trim( pUnallocated ) @= '' );\r\n pUnallocated = 'Unallocated';\r\nElseIF( Subst(Trim( pUnallocated ),1,7 ) @= '' );\r\n pUnallocated = pAttr | ' ' | Subst( pUnallocated, 8, Long( pUnallocated ) );\r\nElseIF( Subst( pUnallocated, Long( pUnallocated )-7, 8 ) @= '' );\r\n pUnallocated = Subst( pUnallocated, 1, Long( pUnallocated )-8 ) | ' ' | pAttr;\r\nElseIF( Scan( '', pUnallocated ) >0 );\r\n pUnallocated = Subst( pUnallocated, 1, Scan( '', pUnallocated )-1 ) | pAttr | Subst( pUnallocated, Scan( '', pUnallocated )+7,Long(pUnallocated) );\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n## Modify attribute for hierarchy name\r\nsAttribute = Trim(pAttr);\r\n#If Attribute name has \":\" then delete as Hierachy names are not allowed with \":\" \r\nIf(Scan(':', sAttribute) > 0);\r\n nStart = 0;\r\n WHILE ( nStart <> 1 );\r\n nSpecialChar = SCAN ( ':', sAttribute );\r\n \tIF ( nSpecialChar <> 0 );\r\n \t\tsAttribute = DELET (sAttribute , nSpecialChar, 1 );\r\n \tELSE;\r\n \t\tnStart = 1;\r\n \tENDIF;\r\n END;\r\nEndIf;\r\n\r\n### Create target dimension Hierarchy ###\r\nIf(pTgtHier @= '');\r\n sTargetHierarchy = sAttribute;\r\nElse;\r\n sTargetHierarchy = pTgtHier;\r\nEndIf;\r\n\r\nIf( HierarchyExists( pDim, sTargetHierarchy ) = 0 );\r\n HierarchyCreate( pDim, sTargetHierarchy );\r\nElse;\r\n IF ( pUnwind = 1 );\r\n ExecuteProcess('}bedrock.hier.unwind',\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pDim', pDim,\r\n 'pHier', sTargetHierarchy,\r\n 'pConsol', '*',\r\n 'pRecursive', 0,\r\n 'pDelim', '&'\r\n );\r\n Else; \r\n HierarchyDeleteAllElements( pDim, sTargetHierarchy );\r\n Endif; \r\nEndIf;\r\n\r\n#Target consol does not exist then add element to dimension.\r\nIf( ElementIndex(pDim, sTargetHierarchy, sTopNode) = 0);\r\n HierarchyElementinsert(pDim, sTargetHierarchy, '',sTopNode, 'C');\r\nEndif;\r\n\r\n### Format Prefix and Suffix with trailing or leading ' ' ###\r\nIF( pPrefix @<> '' );\r\n IF( SUBST( pPrefix, Long( pPrefix), 1) @<> ' ' );\r\n sPrefix = pPrefix | ' ';\r\n ELSE;\r\n sPrefix = pPrefix;\r\n ENDIF;\r\nENDIF;\r\n\r\nIF( pSuffix @<> '' );\r\n IF( SUBST( pSuffix, 1, 1) @<> ' ' );\r\n sSuffix = ' ' | pSuffix;\r\n ELSE;\r\n sSuffix = pSuffix;\r\n ENDIF;\r\nENDIF;\r\n\r\n\r\n### Assign Data Source ###\r\nDatasourceNameForServer = pDim|':'|pSrcHier;\r\nDatasourceNameForClient = pDim|':'|pSrcHier;\r\nDataSourceType = 'SUBSET';\r\nDatasourceDimensionSubset = 'ALL';", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.create.fromattribute', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pDim', '', 'pSrcHier', '', 'pTgtHier', '', 'pAttr', '',\r\n \t'pTopNode', 'Total ', 'pPrefix', '', 'pSuffix', '',\r\n \t'pSkipBlank', 0, 'pUnallocated', 'Undefined ', 'pUnwind', 0\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will create a new dimension hierarchy from attribute values.\r\n\r\n# Note:\r\n# Valid dimension name (pDim) and attribute name (pAttr) are mandatory, otherwise the\r\n# process will abort.\r\n\r\n# Caution: It is assumed each element exists __only once__ within the hierarchy. This should hold true except in exceptional circumstances.\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncSubset = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pSrcHier:%pSrcHier%, pTgtHier:%pTgtHier%, pAttr:%pAttr%, pTopNode:%pTopNode%, pPrefix:%pPrefix%, pSuffix:%pSuffix%, pSkipBlank:%pSkipBlank%, pUnallocated:%pUnallocated%.';\r\ncAttributeDim = '}ElementAttributes_' | pDim;\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pAttr\": null,\r\n \"pDim\": null,\r\n \"pPrefix\": \"\",\r\n \"pSrcHier\": \"\",\r\n \"pSuffix\": \"\",\r\n \"pTgtHier\": \"\",\r\n \"pTopNode\": \"Total \",\r\n \"pUnallocated\": \"Undefined \",\r\n \"pLogOutput\": 0,\r\n \"pSkipBlank\": 0,\r\n \"pStrictErrorHandling\": 0,\r\n \"pUnwind\": 0\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pAttr\": '|StringToJson ( pAttr )|',\r\n \"pDim\": '|StringToJson ( pDim )|',\r\n \"pPrefix\": '|StringToJson ( pPrefix )|',\r\n \"pSrcHier\": '|StringToJson ( pSrcHier )|',\r\n \"pSuffix\": '|StringToJson ( pSuffix )|',\r\n \"pTgtHier\": '|StringToJson ( pTgtHier )|',\r\n \"pTopNode\": '|StringToJson ( pTopNode )|',\r\n \"pUnallocated\": '|StringToJson ( pUnallocated )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pSkipBlank\": '|NumberToString( pSkipBlank )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|',\r\n \"pUnwind\": '|NumberToString( pUnwind )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npAttr = JsonToString( JsonGet( pJson, 'pAttr' ) );\r\npDim = JsonToString( JsonGet( pJson, 'pDim' ) );\r\npPrefix = JsonToString( JsonGet( pJson, 'pPrefix' ) );\r\npSrcHier = JsonToString( JsonGet( pJson, 'pSrcHier' ) );\r\npSuffix = JsonToString( JsonGet( pJson, 'pSuffix' ) );\r\npTgtHier = JsonToString( JsonGet( pJson, 'pTgtHier' ) );\r\npTopNode = JsonToString( JsonGet( pJson, 'pTopNode' ) );\r\npUnallocated = JsonToString( JsonGet( pJson, 'pUnallocated' ) );\r\n# Numeric Parameters\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npSkipBlank = StringToNumber( JsonToString( JsonGet( pJson, 'pSkipBlank' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\npUnwind = StringToNumber( JsonToString( JsonGet( pJson, 'pUnwind' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\nIf( Scan( ':', pDim ) > 0 & pSrcHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pSrcHier = SubSt( pDim, Scan( ':', pDim ) + 1, Long( pDim ) );\r\n pDim = SubSt( pDim, 1, Scan( ':', pDim ) - 1 );\r\nEndIf;\r\n\r\nIF( Trim ( pSrcHier ) @= Trim ( pTgtHier ) & pTgtHier @<> '' );\r\n nErrors = 1;\r\n sMessage = 'Source and target Herarchy can not be the same';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf; \r\n \r\n## Validate dimension\r\nIf( Trim( pDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( DimensionExists( pDim ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Dimension: ' | pDim | ' does not exist.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n## Validate Hierarchy\r\nIF( Trim( pSrcHier ) @= '' );\r\n pSrcHier = Trim( pDim );\r\nEndIf;\r\n\r\nIF( HierarchyExists( pDim, pSrcHier ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid dimension Hierarchy: ' | pDim |':'|pSrcHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\npnew =DType( cAttributeDim, pAttr );\r\n## Validate attribute\r\nIf( Trim( pAttr ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No attribute specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( DimIx( cAttributeDim, pAttr ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Attribute: ' | pAttr | ' does not exists in dimension: ' | pDim;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( DType( cAttributeDim, pAttr ) @<> 'AS' & DType( cAttributeDim, pAttr ) @<> 'AN');\r\n ### as alias values are all unique, not applicable for creating hierarchy\r\n nErrors = 1;\r\n sMessage = 'Only string and numeric attributes may be used for this process.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n## Validate Top node name\r\nIF( Trim( pTopNode ) @= '' );\r\n sTopNode = 'All ' | pAttr;\r\nElseIF( Subst(Trim( pTopNode ),1,7 ) @= '' );\r\n sTopNode = pAttr | ' ' | Subst( pTopNode, 8, Long( pTopNode ) );\r\nElseIF( Subst( pTopNode, Long( pTopNode )-7, 8 ) @= '' );\r\n sTopNode = Subst( pTopNode, 1, Long( pTopNode )-8 ) | ' ' | pAttr;\r\nElseIF( Scan( '', pTopNode ) >0 );\r\n sTopNode = Subst( pTopNode, 1, Scan( '', pTopNode )-1 ) | pAttr | Subst( pTopNode, Scan( '', pTopNode )+7,Long(pTopNode) );\r\nElse;\t\r\n sTopNode = pTopNode;\r\nEndIf;\r\n\r\n## Validate Unallocated node name\r\nIF( Trim( pUnallocated ) @= '' );\r\n pUnallocated = 'Unallocated';\r\nElseIF( Subst(Trim( pUnallocated ),1,7 ) @= '' );\r\n pUnallocated = pAttr | ' ' | Subst( pUnallocated, 8, Long( pUnallocated ) );\r\nElseIF( Subst( pUnallocated, Long( pUnallocated )-7, 8 ) @= '' );\r\n pUnallocated = Subst( pUnallocated, 1, Long( pUnallocated )-8 ) | ' ' | pAttr;\r\nElseIF( Scan( '', pUnallocated ) >0 );\r\n pUnallocated = Subst( pUnallocated, 1, Scan( '', pUnallocated )-1 ) | pAttr | Subst( pUnallocated, Scan( '', pUnallocated )+7,Long(pUnallocated) );\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n## Modify attribute for hierarchy name\r\nsAttribute = Trim(pAttr);\r\n#If Attribute name has \":\" then delete as Hierachy names are not allowed with \":\" \r\nIf(Scan(':', sAttribute) > 0);\r\n nStart = 0;\r\n WHILE ( nStart <> 1 );\r\n nSpecialChar = SCAN ( ':', sAttribute );\r\n \tIF ( nSpecialChar <> 0 );\r\n \t\tsAttribute = DELET (sAttribute , nSpecialChar, 1 );\r\n \tELSE;\r\n \t\tnStart = 1;\r\n \tENDIF;\r\n END;\r\nEndIf;\r\n\r\n### Create target dimension Hierarchy ###\r\nIf(pTgtHier @= '');\r\n sTargetHierarchy = sAttribute;\r\nElse;\r\n sTargetHierarchy = pTgtHier;\r\nEndIf;\r\n\r\nIf( HierarchyExists( pDim, sTargetHierarchy ) = 0 );\r\n HierarchyCreate( pDim, sTargetHierarchy );\r\nElse;\r\n IF ( pUnwind = 1 );\r\n ExecuteProcess('}bedrock.hier.unwind',\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pDim', pDim,\r\n 'pHier', sTargetHierarchy,\r\n 'pConsol', '*',\r\n 'pRecursive', 0,\r\n 'pDelim', '&'\r\n );\r\n Else; \r\n HierarchyDeleteAllElements( pDim, sTargetHierarchy );\r\n Endif; \r\nEndIf;\r\n\r\n#Target consol does not exist then add element to dimension.\r\nIf( ElementIndex(pDim, sTargetHierarchy, sTopNode) = 0);\r\n HierarchyElementinsert(pDim, sTargetHierarchy, '',sTopNode, 'C');\r\nEndif;\r\n\r\n### Format Prefix and Suffix with trailing or leading ' ' ###\r\nIF( pPrefix @<> '' );\r\n IF( SUBST( pPrefix, Long( pPrefix), 1) @<> ' ' );\r\n sPrefix = pPrefix | ' ';\r\n ELSE;\r\n sPrefix = pPrefix;\r\n ENDIF;\r\nENDIF;\r\n\r\nIF( pSuffix @<> '' );\r\n IF( SUBST( pSuffix, 1, 1) @<> ' ' );\r\n sSuffix = ' ' | pSuffix;\r\n ELSE;\r\n sSuffix = pSuffix;\r\n ENDIF;\r\nENDIF;\r\n\r\n\r\n### Assign Data Source ###\r\nDatasourceNameForServer = pDim|':'|pSrcHier;\r\nDatasourceNameForClient = pDim|':'|pSrcHier;\r\nDataSourceType = 'SUBSET';\r\nDatasourceDimensionSubset = 'ALL';", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock Ver 4.0.0~~##\r\n################################################################################################# \r\n\r\n\r\n### Check for errors in prolog ###\r\n\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n# Skip if the Element is not leaf element\r\nIf( ElementType(pDim, pSrcHier, vEle) @<> 'N' );\r\n ItemSkip;\r\nEndif;\r\n\r\n# Skip if top node\r\nIf( vEle @= sTopNode );\r\n ItemSkip;\r\nENDIF;\r\n\r\nIf( DType( cAttributeDim, pAttr ) @= 'AS' );\r\n sAttrVal = ElementAttrS(pDim, pSrcHier, vEle, pAttr);\r\nElse; \r\n sAttrVal = NumberToString(ElementAttrN(pDim, pSrcHier, vEle, pAttr));\r\nEndIf; \r\nsParent = sAttrVal;\r\n\r\n# Manage not populated attribute.\r\nIf( sParent @= '' & pSkipBlank = 0 );\r\n ItemSkip;\r\nElseIf( sParent @= '' & pSkipBlank <> 0 ); \r\n sParent = pUnallocated;\r\nEndIf;\r\n\r\n#If parent does not exist AND allow insertion of new parents is TRUE then insert new consol\r\n## Add the attribute value to the top node.\r\n \r\n sElPar = sPrefix | sParent | sSuffix;\r\n\r\n HierarchyElementinsert(pDim, sTargetHierarchy, '',sElPar, 'C');\r\n HierarchyElementComponentAdd(pDim, sTargetHierarchy, sTopNode, sElPar, 1);\r\n \r\n HierarchyElementinsert(pDim, sTargetHierarchy, '',vEle, 'N' );\r\n HierarchyElementComponentAdd(pDim, sTargetHierarchy, sElPar, vEle, 1);\r\n\r\n### End Metadata ###", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock Ver 4.0.0~~##\r\n################################################################################################# \r\n\r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully created the %sTargetHierarchy% hierarchy in the %pDim% dimension.' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n### End Epilog ###", @@ -13,77 +13,83 @@ "view": "Temp" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pDim", - "Prompt": "REQUIRED: Dimension", + "Prompt": "REQUIRED: Delimited list of dimensions", "Value": "", "Type": "String" }, { "Name": "pSrcHier", - "Prompt": "OPTIONAL: Source Hierarchy, If not specified takes the default Hierarchy", + "Prompt": "OPTIONAL: Source hierarchy name (Default = pSrcDim)", "Value": "", "Type": "String" }, { "Name": "pTgtHier", - "Prompt": "OPTIONAL: Target Hierarchy, If not specified, takes the same name as attribute", + "Prompt": "OPTIONAL: Target hierarchy name (Default = pAttr)", "Value": "", "Type": "String" }, { "Name": "pAttr", - "Prompt": "REQUIRED: Attribute", + "Prompt": "REQUIRED: Attribute name", "Value": "", "Type": "String" }, { "Name": "pTopNode", - "Prompt": "OPTIONAL: The name of the Target Hierarchy top element (will default to 'All ' attribute name)", + "Prompt": "OPTIONAL: The name to give the top element in the target hierarchy (Will substitute '' with pAttr. Default = 'Total ' | pAttr)", "Value": "Total ", "Type": "String" }, { "Name": "pPrefix", - "Prompt": "OPTIONAL: Prefix before the attribute value", + "Prompt": "OPTIONAL: Add prefix before the value", "Value": "", "Type": "String" }, { "Name": "pSuffix", - "Prompt": "OPTIONAL: Suffix after the attribute value", + "Prompt": "OPTIONAL: Add suffix before the value", "Value": "", "Type": "String" }, { "Name": "pSkipBlank", - "Prompt": "OPTIONAL: To manage empty attribute: 0 = Skip, 1 = Send to unallocated node (by default blank attribute values are skipped)", + "Prompt": "OPTIONAL: To manage empty attribute: 0 = Skip, 1 = Send to unallocated node (by default blank attribute values are skipped) (Default = 0)", "Value": 0, "Type": "Numeric" }, { "Name": "pUnallocated", - "Prompt": "OPTIONAL: Naming convention for rollup if attribute is empty (eg. Unallocated , No , Undefined )", + "Prompt": "OPTIONAL: The name to give the consolidation that elements with empty attribute values will be added to in the target hierarchy (Will substitute '' with pAttr. Default = 'Undefined ' | pAttr)", "Value": "Undefined ", "Type": "String" }, { "Name": "pUnwind", - "Prompt": "OPTIONAL: Unwind target hierarchy (0 = Delete all elements, 1 = Unwind hierarchy and keep elements)", + "Prompt": "OPTIONAL: Unwind target hierarchy before process (0 = Delete all elements, 1 = Unwind existing elements, 2 = Do not change existing elements. Default = 0)", "Value": 0, "Type": "Numeric" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [ @@ -109,9 +115,5 @@ "EndByte": 0 } ], - "VariablesUIData": [ - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f", - "VarType=32\fColType=827\f" - ] + "VariablesUIData": [] } \ No newline at end of file diff --git a/bedrock_processes_json/}bedrock.hier.create.fromrollup.aliasswap.json b/bedrock_processes_json/}bedrock.hier.create.fromrollup.aliasswap.json index 8135573..39a89cb 100644 --- a/bedrock_processes_json/}bedrock.hier.create.fromrollup.aliasswap.json +++ b/bedrock_processes_json/}bedrock.hier.create.fromrollup.aliasswap.json @@ -10,63 +10,51 @@ "Type": "None" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pSrcDim", - "Prompt": "REQUIRED: Source Dimension", + "Prompt": "REQUIRED: Source dimension name", "Value": "", "Type": "String" }, { "Name": "pSrcHier", - "Prompt": "OPTIONAL: Source Hierarchy (blank = same name as source dimension)", + "Prompt": "OPTIONAL: Source hierarchy name (Default = pSrcDim)", "Value": "", "Type": "String" }, { "Name": "pConsol", - "Prompt": "REQUIRED: Cons element in source dim to create root element in target", + "Prompt": "REQUIRED: Consolidated element name used as source", "Value": "", "Type": "String" }, { "Name": "pTgtDim", - "Prompt": "OPTIONAL: Target Dimension (blank = same name as source dimension)", + "Prompt": "OPTIONAL: Target dimension name (Default = pSrcDim)", "Value": "", "Type": "String" }, { "Name": "pTgtHier", - "Prompt": "OPTIONAL: Target Hierarchy (blank = same name as target dimension)", + "Prompt": "OPTIONAL: Target hierarchy name (Default = pTgtDim)", "Value": "", "Type": "String" }, { "Name": "pAttr", - "Prompt": "OPTIONAL: Include Attributes? (Boolean 1=True)", + "Prompt": "OPTIONAL: Include attributes (Boolean. Default = 1)", "Value": 1, "Type": "Numeric" }, { "Name": "pUnwind", - "Prompt": "OPTIONAL: 0 = Delete all Elements, 1 = Unwind Existing Elements, 2 = Do not change Existing Elements", - "Value": 2, + "Prompt": "OPTIONAL: Unwind target hierarchy before process (0 = Delete all elements, 1 = Unwind existing elements, 2 = Do not change existing elements. Default = 0)", + "Value": 0, "Type": "Numeric" }, { "Name": "pRemove", - "Prompt": "OPTIONAL: Remove cons elements from source? (1 = Yes, 0 = No)", + "Prompt": "OPTIONAL: Remove consolidated elements from source (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, @@ -75,6 +63,24 @@ "Prompt": "REQUIRED: Name of the attribute with names to be swapped", "Value": "", "Type": "String" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [], diff --git a/bedrock_processes_json/}bedrock.hier.create.fromrollup.json b/bedrock_processes_json/}bedrock.hier.create.fromrollup.json index eb70cc6..3d50e42 100644 --- a/bedrock_processes_json/}bedrock.hier.create.fromrollup.json +++ b/bedrock_processes_json/}bedrock.hier.create.fromrollup.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.hier.create.fromrollup", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.create.fromrollup', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pSrcDim', '', 'pSrcHier', '', 'pConsol', '',\r\n \t'pTgtDim', '', 'pTgtHier', '',\r\n \t'pAttr', 1, 'pUnwind', 2, 'pRemove', 0\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock Ver 4~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will make an aternative hierarchy from a consolidated element and its children in default hierarchy.\r\n\r\n# Use case: Intended for Development but could be used in production too.\r\n# 1. Create a new hierarchy for testing.\r\n# 2. Create a new hierarchy to reflect new business needs.\r\n\r\n# Note:\r\n# Valid source dimension name (pSrcDim) and source subset (pSubset) are mandatory, otherwise the process will abort.\r\n# If a source hierarchy name (pSrcHier) is specified, it needs to be valid, otherwise the process will abort.\r\n\r\n# Caution:\r\n# - Target hierarchy cannot be `Leaves`.\r\n# - If the target Hierarchy already exists, then it will be overwritten.\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable ('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode = 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pSrcDim:%pSrcDim%, pSrcHier:%pSrcHier%, pConsol:%pConsol%, pTgtDim:%pTgtDim%, pTgtHier:%pTgtHier%, pAttr:%pAttr%, pUnwind:%pUnwind%, pRemove:%pRemove%.';\r\ncHierAttr = 'Bedrock.Descendant';\r\ncAttrVal = 'Descendant';\r\n\r\n## LogOutput parameters\r\nIF ( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\nIf( Scan( ':', pSrcDim ) > 0 & pSrcHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pSrcHier = SubSt( pSrcDim, Scan( ':', pSrcDim ) + 1, Long( pSrcDim ) );\r\n pSrcDim = SubSt( pSrcDim, 1, Scan( ':', pSrcDim ) - 1 );\r\nEndIf;\r\n\r\nIf( Scan( ':', pTgtDim ) > 0 & pTgtHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pTgtHier = SubSt( pTgtDim, Scan( ':', pTgtDim ) + 1, Long( pTgtDim ) );\r\n pTgtDim = SubSt( pTgtDim, 1, Scan( ':', pTgtDim ) - 1 );\r\nEndIf;\r\n\r\n# Validate source dimension\r\nIF( Trim( pSrcDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No source dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nIF( DimensionExists( pSrcDim ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid source dimension: ' | pSrcDim;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n# Validate source Hierarchy\r\nIF(pSrcHier @= '');\r\n pSrcHier = pSrcDim;\r\nElseIf(HierarchyExists(pSrcDim, pSrcHier) = 0);\r\n nErrors = 1;\r\n sMessage = 'Invalid source hierarchy: ' | pSrcHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndif;\r\n\r\n## Validate consolidation\r\npConsol = Trim( pConsol );\r\nIf( pConsol @<> '' );\r\n If( ElementIndex ( pSrcDim, pSrcHier, pConsol ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'The ' | pConsol | ' consolidation does not exist in the '| pSrcDim |' dimension:Hierarchy ' | pSrcDim |':'| pSrcHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n Else;\r\n pConsol = HierarchyElementPrincipalName(pSrcDim, pSrcHier, pConsol);\r\n EndIf;\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n## Validate target Dimension\r\nIf(pTgtDim @= '');\r\n pTgtDim = pSrcDim;\r\nEndif;\r\n\r\nIF( DimensionExists( pTgtDim ) = 0 );\r\n DimensionCreate(pTgtDim);\r\nEndIf;\r\n\r\n### Create target dimension Hierarchy ###\r\nIF(pTgtHier @= '');\r\n pTgtHier = pTgtDim;\r\nEndIf;\r\n\r\n##########################################\r\n# Bedrock subprocesses\r\n\r\n#create subset\r\nExecuteProcess('}bedrock.hier.sub.create',\r\n 'pLogOutput',pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n\t'pDim',pSrcDim,\r\n\t'pHier', pSrcHier,\r\n\t'pSub', cTempSub,\r\n\t'pConsol', pConsol,\r\n\t'pTemp', 1\r\n);\r\n\r\nExecuteProcess('}bedrock.hier.create.fromsubset',\r\n 'pLogOutput',pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pSrcDim',pSrcDim,\r\n 'pSrcHier', pSrcHier,\r\n 'pSubset', cTempSub,\r\n 'pTgtDim', pTgtDim,\r\n 'pTgtHier', pTgtHier,\r\n 'pAttr', pAttr,\r\n 'pUnwind', pUnwind\r\n);\r\n\r\nIF(pRemove = 1);\r\n ExecuteProcess('}bedrock.hier.unwind',\r\n 'pLogOutput',pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n\t'pDim',pSrcDim,\r\n\t'pConsol', pConsol,\r\n\t'pRecursive', 1\r\n);\r\n\r\n ExecuteProcess('}bedrock.hier.emptyconsols.delete',\r\n 'pLogOutput',pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n\t'pDim',pSrcDim,\r\n\t'pHier', pSrcHier\r\n);\r\n\r\nEndif;\r\n\r\n### End Prolog ###", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.create.fromrollup', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pSrcDim', '', 'pSrcHier', '', 'pConsol', '',\r\n \t'pTgtDim', '', 'pTgtHier', '',\r\n \t'pAttr', 1, 'pUnwind', 2, 'pRemove', 0\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock Ver 4~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will make an aternative hierarchy from a consolidated element and its children in default hierarchy.\r\n\r\n# Use case: Intended for Development but could be used in production too.\r\n# 1. Create a new hierarchy for testing.\r\n# 2. Create a new hierarchy to reflect new business needs.\r\n\r\n# Note:\r\n# Valid source dimension name (pSrcDim) and source subset (pSubset) are mandatory, otherwise the process will abort.\r\n# If a source hierarchy name (pSrcHier) is specified, it needs to be valid, otherwise the process will abort.\r\n\r\n# Caution:\r\n# - Target hierarchy cannot be `Leaves`.\r\n# - If the target Hierarchy already exists, then it will be overwritten.\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable ('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode = 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pSrcDim:%pSrcDim%, pSrcHier:%pSrcHier%, pConsol:%pConsol%, pTgtDim:%pTgtDim%, pTgtHier:%pTgtHier%, pAttr:%pAttr%, pUnwind:%pUnwind%, pRemove:%pRemove%.';\r\ncHierAttr = 'Bedrock.Descendant';\r\ncAttrVal = 'Descendant';\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pConsol\": null,\r\n \"pSrcDim\": null,\r\n \"pSrcHier\": \"\",\r\n \"pTgtDim\": \"\",\r\n \"pTgtHier\": \"\",\r\n \"pAttr\": 1,\r\n \"pLogOutput\": 0,\r\n \"pRemove\": 0,\r\n \"pStrictErrorHandling\": 0,\r\n \"pUnwind\": 0\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pConsol\": '|StringToJson ( pConsol )|',\r\n \"pSrcDim\": '|StringToJson ( pSrcDim )|',\r\n \"pSrcHier\": '|StringToJson ( pSrcHier )|',\r\n \"pTgtDim\": '|StringToJson ( pTgtDim )|',\r\n \"pTgtHier\": '|StringToJson ( pTgtHier )|',\r\n \"pAttr\": '|NumberToString( pAttr )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pRemove\": '|NumberToString( pRemove )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|',\r\n \"pUnwind\": '|NumberToString( pUnwind )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npConsol = JsonToString( JsonGet( pJson, 'pConsol' ) );\r\npSrcDim = JsonToString( JsonGet( pJson, 'pSrcDim' ) );\r\npSrcHier = JsonToString( JsonGet( pJson, 'pSrcHier' ) );\r\npTgtDim = JsonToString( JsonGet( pJson, 'pTgtDim' ) );\r\npTgtHier = JsonToString( JsonGet( pJson, 'pTgtHier' ) );\r\n# Numeric Parameters\r\npAttr = StringToNumber( JsonToString( JsonGet( pJson, 'pAttr' ) ) );\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npRemove = StringToNumber( JsonToString( JsonGet( pJson, 'pRemove' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\npUnwind = StringToNumber( JsonToString( JsonGet( pJson, 'pUnwind' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n## LogOutput parameters\r\nIF ( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\nIf( Scan( ':', pSrcDim ) > 0 & pSrcHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pSrcHier = SubSt( pSrcDim, Scan( ':', pSrcDim ) + 1, Long( pSrcDim ) );\r\n pSrcDim = SubSt( pSrcDim, 1, Scan( ':', pSrcDim ) - 1 );\r\nEndIf;\r\n\r\nIf( Scan( ':', pTgtDim ) > 0 & pTgtHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pTgtHier = SubSt( pTgtDim, Scan( ':', pTgtDim ) + 1, Long( pTgtDim ) );\r\n pTgtDim = SubSt( pTgtDim, 1, Scan( ':', pTgtDim ) - 1 );\r\nEndIf;\r\n\r\n# Validate source dimension\r\nIF( Trim( pSrcDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No source dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nIF( DimensionExists( pSrcDim ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid source dimension: ' | pSrcDim;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n# Validate source Hierarchy\r\nIF(pSrcHier @= '');\r\n pSrcHier = pSrcDim;\r\nElseIf(HierarchyExists(pSrcDim, pSrcHier) = 0);\r\n nErrors = 1;\r\n sMessage = 'Invalid source hierarchy: ' | pSrcHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndif;\r\n\r\n## Validate consolidation\r\npConsol = Trim( pConsol );\r\nIf( pConsol @<> '' );\r\n If( ElementIndex ( pSrcDim, pSrcHier, pConsol ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'The ' | pConsol | ' consolidation does not exist in the '| pSrcDim |' dimension:Hierarchy ' | pSrcDim |':'| pSrcHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n Else;\r\n pConsol = HierarchyElementPrincipalName(pSrcDim, pSrcHier, pConsol);\r\n EndIf;\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n## Validate target Dimension\r\nIf(pTgtDim @= '');\r\n pTgtDim = pSrcDim;\r\nEndif;\r\n\r\nIF( DimensionExists( pTgtDim ) = 0 );\r\n DimensionCreate(pTgtDim);\r\nEndIf;\r\n\r\n### Create target dimension Hierarchy ###\r\nIF(pTgtHier @= '');\r\n pTgtHier = pTgtDim;\r\nEndIf;\r\n\r\n##########################################\r\n# Bedrock subprocesses\r\n\r\n#create subset\r\nExecuteProcess('}bedrock.hier.sub.create',\r\n 'pLogOutput',pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n\t'pDim',pSrcDim,\r\n\t'pHier', pSrcHier,\r\n\t'pSub', cTempSub,\r\n\t'pConsol', pConsol,\r\n\t'pTemp', 1\r\n);\r\n\r\nExecuteProcess('}bedrock.hier.create.fromsubset',\r\n 'pLogOutput',pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pSrcDim',pSrcDim,\r\n 'pSrcHier', pSrcHier,\r\n 'pSubset', cTempSub,\r\n 'pTgtDim', pTgtDim,\r\n 'pTgtHier', pTgtHier,\r\n 'pAttr', pAttr,\r\n 'pUnwind', pUnwind\r\n);\r\n\r\nIF(pRemove = 1);\r\n ExecuteProcess('}bedrock.hier.unwind',\r\n 'pLogOutput',pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n\t'pDim',pSrcDim,\r\n\t'pConsol', pConsol,\r\n\t'pRecursive', 1\r\n);\r\n\r\n ExecuteProcess('}bedrock.hier.emptyconsols.delete',\r\n 'pLogOutput',pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n\t'pDim',pSrcDim,\r\n\t'pHier', pSrcHier\r\n);\r\n\r\nEndif;\r\n\r\n### End Prolog ###", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n\r\n", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock Ver 4.0.0~~##\r\n################################################################################################# \r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully cloned dimension:hierarchy %pSrcDim%:%pSrcHier% to %pTgtDim%:%pTgtHier% based on the %pConsol% consolidated element.' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n### End Epilog ###", @@ -10,65 +10,71 @@ "Type": "None" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pSrcDim", - "Prompt": "REQUIRED: Source Dimension", + "Prompt": "REQUIRED: Source dimension name", "Value": "", "Type": "String" }, { "Name": "pSrcHier", - "Prompt": "OPTIONAL: Source Hierarchy (blank = same name as source dimension)", + "Prompt": "OPTIONAL: Source hierarchy name (Default = pSrcDim)", "Value": "", "Type": "String" }, { "Name": "pConsol", - "Prompt": "REQUIRED: Cons element in source dim to create root element in target", + "Prompt": "REQUIRED: Consolidated element name used as source", "Value": "", "Type": "String" }, { "Name": "pTgtDim", - "Prompt": "OPTIONAL: Target Dimension (blank = same name as source dimension)", + "Prompt": "OPTIONAL: Target dimension name (Default = pSrcDim)", "Value": "", "Type": "String" }, { "Name": "pTgtHier", - "Prompt": "OPTIONAL: Target Hierarchy (blank = same name as target dimension)", + "Prompt": "OPTIONAL: Target hierarchy name (Default = pTgtDim)", "Value": "", "Type": "String" }, { "Name": "pAttr", - "Prompt": "OPTIONAL: Include Attributes? (Boolean 1=True)", + "Prompt": "OPTIONAL: Include attributes (Boolean. Default = 1)", "Value": 1, "Type": "Numeric" }, { "Name": "pUnwind", - "Prompt": "OPTIONAL: 0 = Delete all Elements, 1 = Unwind Existing Elements, 2 = Do not change Existing Elements", - "Value": 2, + "Prompt": "OPTIONAL: Unwind target hierarchy before process (0 = Delete all elements, 1 = Unwind existing elements, 2 = Do not change existing elements. Default = 0)", + "Value": 0, "Type": "Numeric" }, { "Name": "pRemove", - "Prompt": "OPTIONAL: Remove cons elements from source? (1 = Yes, 0 = No)", + "Prompt": "OPTIONAL: Remove consolidated elements from source (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [], diff --git a/bedrock_processes_json/}bedrock.hier.create.fromsubset.json b/bedrock_processes_json/}bedrock.hier.create.fromsubset.json index e6c1046..c0998a3 100644 --- a/bedrock_processes_json/}bedrock.hier.create.fromsubset.json +++ b/bedrock_processes_json/}bedrock.hier.create.fromsubset.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.hier.create.fromsubset", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.create.fromsubset', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pSrcDim', '', 'pSrcHier', '', 'pSubset', '',\r\n \t'pTgtDim', '', 'pTgtHier', '',\r\n \t'pAttr', 1, 'pUnwind', 0, 'pFlat', 0\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock Ver 4~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will make a copy of an existing dimension subset, creating it as a new dimension hierarchy.\r\n\r\n# Use case: Intended for Development but could be used in production too.\r\n# 1. Create a new hierarchy for testing.\r\n# 2. Create a new hierarchy to reflect new business needs.\r\n\r\n# Note:\r\n# Valid source dimension name (pSrcDim) and source subset (pSubset) are mandatory, otherwise the process will abort.\r\n# If a source hierarchy name (pSrcHier) is specified, it needs to be valid, otherwise the process will abort.\r\n\r\n# Caution:\r\n# - Target hierarchy cannot be Leaves.\r\n# - If the target Hierarchy already exists, then it will be overwritten.\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable ('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode = 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pSrcDim:%pSrcDim%, pSrcHier:%pSrcHier%, pSubset:%pSubset%, pTgtDim:%pTgtDim%, pTgtHier:%pTgtHier%, pAttr:%pAttr%, pUnwind:%pUnwind%, pFlat:%pFlat%.';\r\ncHierAttr = 'Bedrock.Descendant';\r\ncAttrVal = 'Descendant';\r\n\r\n## LogOutput parameters\r\nIF ( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\nIf( Scan( ':', pSrcDim ) > 0 & pSrcHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pSrcHier = SubSt( pSrcDim, Scan( ':', pSrcDim ) + 1, Long( pSrcDim ) );\r\n pSrcDim = SubSt( pSrcDim, 1, Scan( ':', pSrcDim ) - 1 );\r\nEndIf;\r\n\r\nIf( Scan( ':', pTgtDim ) > 0 & pTgtHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pTgtHier = SubSt( pTgtDim, Scan( ':', pTgtDim ) + 1, Long( pTgtDim ) );\r\n pTgtDim = SubSt( pTgtDim, 1, Scan( ':', pTgtDim ) - 1 );\r\nEndIf;\r\n\r\n# Validate source dimension\r\nIF( Trim( pSrcDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No source dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nIF( DimensionExists( pSrcDim ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid source dimension: ' | pSrcDim;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n# Validate source Hierarchy\r\nIF(pSrcHier @= '');\r\n pSrcHier = pSrcDim;\r\nElseIf(HierarchyExists(pSrcDim, pSrcHier) = 0);\r\n nErrors = 1;\r\n sMessage = 'Invalid source hierarchy: ' | pSrcHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndif;\r\n\r\n## Validate Source Subset\r\nIF(HierarchySubsetExists( pSrcDim, pSrcHier, pSubset) = 0 );\r\n sMessage = 'No valid source subset: ' | pSubset;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nELSE;\r\n cSubset = pSubset;\r\nENDIF;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n## Validate target Dimension\r\nIf(pTgtDim @= '');\r\n pTgtDim = pSrcDim;\r\nEndif;\r\n\r\nIF( DimensionExists( pTgtDim ) = 0 );\r\n DimensionCreate(pTgtDim);\r\nEndIf;\r\n\r\n### Create target dimension Hierarchy ###\r\nIF(pTgtHier @= '');\r\n pTgtHier = pTgtDim;\r\nEndIf;\r\n\r\n\r\nIf( HierarchyExists(pTgtDim, pTgtHier) = 0 );\r\n HierarchyCreate( pTgtDim, pTgtHier );\r\nElse;\r\n IF(pUnwind = 1 );\r\n ExecuteProcess( '}bedrock.hier.unwind', 'pLogOutput', 0,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pDim', pTgtDim, 'pHier', pTgtHier, 'pConsol', '*',\r\n 'pRecursive', 1\r\n );\r\n ELSEIF(\r\n pUnwind = 2 );\r\n #Do nothing\r\n ELSE;\r\n HierarchyDeleteAllElements( pTgtDim, pTgtHier );\r\n EndIf;\r\nEndIf;\r\n\r\n### Assign Data Source ###\r\nDatasourceNameForServer = pSrcDim|':'|pSrcHier;\r\nDatasourceNameForClient = pSrcDim|':'|pSrcHier;\r\nDataSourceType = 'SUBSET';\r\nDatasourceDimensionSubset = cSubset;\r\n\r\n### Set Descendent attribute value\r\nAttrDelete( pSrcDim, cHierAttr );\r\nAttrInsert( pSrcDim, '', cHierAttr, 'S' );\r\n\r\nnIndex = 1;\r\nnLimit = HierarchySubsetGetSize( pSrcDim, pSrcHier, pSubset );\r\nWHILE( nIndex <= nLimit);\r\n sElName = SubsetGetElementName( pSrcDim|':'|pSrcHier, pSubset, nIndex );\r\n ElementAttrPuts( cAttrVal, pSrcDim, pSrcHier, sElName, cHierAttr );\r\n sElType = ElementType( pSrcDim, pSrcHier, sElName );\r\n HierarchyElementInsert(pTgtDim, pTgtHier, '',sElName, sELType);\r\n nIndex = nIndex + 1;\r\nEND;\r\n\r\n### Replicate Attributes ###\r\n# Note: DType on Attr dim returns \"AS\", \"AN\" or \"AA\" need to strip off leading \"A\"\r\n\r\nsTgtAttrDim = '}ElementAttributes_' | pTgtDim;\r\nsSrcAttrDim = '}ElementAttributes_' | pSrcDim;\r\nsLastAttr = '';\r\nIf( pAttr = 1 & DimensionExists( sSrcAttrDim ) = 1 );\r\n nNumAttrs = DimSiz( sSrcAttrDim );\r\n nCount = 1;\r\n While( nCount <= nNumAttrs );\r\n sAttrName = DimNm( sSrcAttrDim, nCount );\r\n sAttrType = SubSt(DType( sSrcAttrDim, sAttrName ), 2, 1 );\r\n AttrInsert( pTgtDim, sLastAttr, sAttrName, sAttrType );\r\n sLastAttr = sAttrName;\r\n nCount = nCount + 1;\r\n End;\r\nEndIf;\r\n \r\n### End Prolog ###", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.create.fromsubset', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pSrcDim', '', 'pSrcHier', '', 'pSubset', '',\r\n \t'pTgtDim', '', 'pTgtHier', '',\r\n \t'pAttr', 1, 'pUnwind', 0, 'pFlat', 0\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock Ver 4~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will make a copy of an existing dimension subset, creating it as a new dimension hierarchy.\r\n\r\n# Use case: Intended for Development but could be used in production too.\r\n# 1. Create a new hierarchy for testing.\r\n# 2. Create a new hierarchy to reflect new business needs.\r\n\r\n# Note:\r\n# Valid source dimension name (pSrcDim) and source subset (pSubset) are mandatory, otherwise the process will abort.\r\n# If a source hierarchy name (pSrcHier) is specified, it needs to be valid, otherwise the process will abort.\r\n\r\n# Caution:\r\n# - Target hierarchy cannot be Leaves.\r\n# - If the target Hierarchy already exists, then it will be overwritten.\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable ('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode = 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pSrcDim:%pSrcDim%, pSrcHier:%pSrcHier%, pSubset:%pSubset%, pTgtDim:%pTgtDim%, pTgtHier:%pTgtHier%, pAttr:%pAttr%, pUnwind:%pUnwind%, pFlat:%pFlat%.';\r\ncHierAttr = 'Bedrock.Descendant';\r\ncAttrVal = 'Descendant';\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pSrcDim\": null,\r\n \"pSrcHier\": \"\",\r\n \"pSubset\": null,\r\n \"pTgtDim\": \"\",\r\n \"pTgtHier\": \"\",\r\n \"pAttr\": 1,\r\n \"pFlat\": 0,\r\n \"pLogOutput\": 0,\r\n \"pStrictErrorHandling\": 0,\r\n \"pUnwind\": 0\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pSrcDim\": '|StringToJson ( pSrcDim )|',\r\n \"pSrcHier\": '|StringToJson ( pSrcHier )|',\r\n \"pSubset\": '|StringToJson ( pSubset )|',\r\n \"pTgtDim\": '|StringToJson ( pTgtDim )|',\r\n \"pTgtHier\": '|StringToJson ( pTgtHier )|',\r\n \"pAttr\": '|NumberToString( pAttr )|',\r\n \"pFlat\": '|NumberToString( pFlat )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|',\r\n \"pUnwind\": '|NumberToString( pUnwind )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npSrcDim = JsonToString( JsonGet( pJson, 'pSrcDim' ) );\r\npSrcHier = JsonToString( JsonGet( pJson, 'pSrcHier' ) );\r\npSubset = JsonToString( JsonGet( pJson, 'pSubset' ) );\r\npTgtDim = JsonToString( JsonGet( pJson, 'pTgtDim' ) );\r\npTgtHier = JsonToString( JsonGet( pJson, 'pTgtHier' ) );\r\n# Numeric Parameters\r\npAttr = StringToNumber( JsonToString( JsonGet( pJson, 'pAttr' ) ) );\r\npFlat = StringToNumber( JsonToString( JsonGet( pJson, 'pFlat' ) ) );\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\npUnwind = StringToNumber( JsonToString( JsonGet( pJson, 'pUnwind' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n## LogOutput parameters\r\nIF ( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\nIf( Scan( ':', pSrcDim ) > 0 & pSrcHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pSrcHier = SubSt( pSrcDim, Scan( ':', pSrcDim ) + 1, Long( pSrcDim ) );\r\n pSrcDim = SubSt( pSrcDim, 1, Scan( ':', pSrcDim ) - 1 );\r\nEndIf;\r\n\r\nIf( Scan( ':', pTgtDim ) > 0 & pTgtHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pTgtHier = SubSt( pTgtDim, Scan( ':', pTgtDim ) + 1, Long( pTgtDim ) );\r\n pTgtDim = SubSt( pTgtDim, 1, Scan( ':', pTgtDim ) - 1 );\r\nEndIf;\r\n\r\n# Validate source dimension\r\nIF( Trim( pSrcDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No source dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nIF( DimensionExists( pSrcDim ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid source dimension: ' | pSrcDim;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n# Validate source Hierarchy\r\nIF(pSrcHier @= '');\r\n pSrcHier = pSrcDim;\r\nElseIf(HierarchyExists(pSrcDim, pSrcHier) = 0);\r\n nErrors = 1;\r\n sMessage = 'Invalid source hierarchy: ' | pSrcHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndif;\r\n\r\n## Validate Source Subset\r\nIF(HierarchySubsetExists( pSrcDim, pSrcHier, pSubset) = 0 );\r\n sMessage = 'No valid source subset: ' | pSubset;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nELSE;\r\n cSubset = pSubset;\r\nENDIF;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n## Validate target Dimension\r\nIf(pTgtDim @= '');\r\n pTgtDim = pSrcDim;\r\nEndif;\r\n\r\nIF( DimensionExists( pTgtDim ) = 0 );\r\n DimensionCreate(pTgtDim);\r\nEndIf;\r\n\r\n### Create target dimension Hierarchy ###\r\nIF(pTgtHier @= '');\r\n pTgtHier = pTgtDim;\r\nEndIf;\r\n\r\n\r\nIf( HierarchyExists(pTgtDim, pTgtHier) = 0 );\r\n HierarchyCreate( pTgtDim, pTgtHier );\r\nElse;\r\n IF(pUnwind = 1 );\r\n ExecuteProcess( '}bedrock.hier.unwind', 'pLogOutput', 0,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pDim', pTgtDim, 'pHier', pTgtHier, 'pConsol', '*',\r\n 'pRecursive', 1\r\n );\r\n ELSEIF(\r\n pUnwind = 2 );\r\n #Do nothing\r\n ELSE;\r\n HierarchyDeleteAllElements( pTgtDim, pTgtHier );\r\n EndIf;\r\nEndIf;\r\n\r\n### Assign Data Source ###\r\nDatasourceNameForServer = pSrcDim|':'|pSrcHier;\r\nDatasourceNameForClient = pSrcDim|':'|pSrcHier;\r\nDataSourceType = 'SUBSET';\r\nDatasourceDimensionSubset = cSubset;\r\n\r\n### Set Descendent attribute value\r\nAttrDelete( pSrcDim, cHierAttr );\r\nAttrInsert( pSrcDim, '', cHierAttr, 'S' );\r\n\r\nnIndex = 1;\r\nnLimit = HierarchySubsetGetSize( pSrcDim, pSrcHier, pSubset );\r\nWHILE( nIndex <= nLimit);\r\n sElName = HierarchySubsetGetElementName( pSrcDim, pSrcHier, pSubset, nIndex );\r\n ElementAttrPuts( cAttrVal, pSrcDim, pSrcHier, sElName, cHierAttr );\r\n sElType = ElementType( pSrcDim, pSrcHier, sElName );\r\n HierarchyElementInsert(pTgtDim, pTgtHier, '',sElName, sELType);\r\n nIndex = nIndex + 1;\r\nEND;\r\n\r\n### Replicate Attributes ###\r\n# Note: DType on Attr dim returns \"AS\", \"AN\" or \"AA\" need to strip off leading \"A\"\r\n\r\nsTgtAttrDim = '}ElementAttributes_' | pTgtDim;\r\nsSrcAttrDim = '}ElementAttributes_' | pSrcDim;\r\nsLastAttr = '';\r\nIf( pAttr = 1 & DimensionExists( sSrcAttrDim ) = 1 );\r\n nNumAttrs = DimSiz( sSrcAttrDim );\r\n nCount = 1;\r\n While( nCount <= nNumAttrs );\r\n sAttrName = DimNm( sSrcAttrDim, nCount );\r\n sAttrType = SubSt(DType( sSrcAttrDim, sAttrName ), 2, 1 );\r\n AttrInsert( pTgtDim, sLastAttr, sAttrName, sAttrType );\r\n sLastAttr = sAttrName;\r\n nCount = nCount + 1;\r\n End;\r\nEndIf;\r\n \r\n### End Prolog ###", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n### Check for errors in prolog ###\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\nIf (pFlat = 1);\r\n ##Creating the Flat hierarchy subset in the target dimension\r\n sElType = ElementType(pSrcDim, pSrcHier, vElement);\r\n ## Add the element to the target dimension.\r\n ## 'C' elements can't be inserted as 'N' elements in the same dimension\r\n IF(pTgtdim @= pSrcDim);\r\n IF(sElType @<> 'C' );\r\n HierarchyElementInsert( pTgtDim, pTgtHier, '', vElement, sElType );\r\n Else;\r\n If( pLogOutput = 1 );\r\n sMessage = 'Name conflict! Cannot create leaf element %vElement% in dimension %pTgtDim% as C element with same name already exists.';\r\n LogOutput( 'WARN', Expand( cMsgErrorContent ) );\r\n EndIf;\r\n EndIf;\r\n Else;\r\n IF(sElType @= 'C' );\r\n HierarchyElementInsert( pTgtDim, pTgtHier, '', vElement, 'N' );\r\n Else;\r\n HierarchyElementInsert( pTgtDim, pTgtHier, '', vElement, sElType );\r\n EndIf;\r\n EndIf;\r\nElse;\r\n nIndex = 1;\r\n nLimit = ElementComponentCount( pSrcDim, pSrcHier, vElement );\r\n WHILE( nIndex <= nLimit );\r\n sElName = ElementComponent( pSrcDim, pSrcHier, vElement, nIndex );\r\n sDecendant = ElementAttrS(pSrcDim, pSrcHier, sElName, cHierAttr);\r\n IF(\r\n sDecendant @= cAttrVal);\r\n nElWeight = ElementWeight( pSrcDim, pSrcHier, vElement, sElName );\r\n HierarchyElementComponentAdd( pTgtDim, pTgtHier, vElement, sElName, nElWeight );\r\n ENDIF;\r\n nIndex = nIndex + 1;\r\n END;\r\nEndif;\r\n\r\n### End MetaData ###", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n\r\n### Check for errors in prolog ###\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n\r\n### Replicate Attributes ###\r\n\r\n# Note: DTYPE on Attr dim returns \"AS\", \"AN\" or \"AA\" need to strip off leading \"A\"\r\n\r\nIf( pAttr = 1 );\r\n\r\n nCount = 1;\r\n While( nCount <= nNumAttrs );\r\n sAttrName = DimNm( sSrcAttrDim, nCount );\r\n sAttrType = SubSt( DTYPE( sSrcAttrDim, sAttrName ), 2, 1 );\r\n If( sAttrType @= 'S' % sAttrType @= 'A' );\r\n sAttrVal = ElementAttrS(pSrcDim, pSrcHier, vElement, sAttrName);\r\n If( sAttrVal @<> '' );\r\n If( pStrictErrorHandling = 0 & CellIsUpdateable(sTgtAttrDim, pTgtHier:vElement, sAttrName) = 0 );\r\n #skip\r\n ElseIf( sAttrType @= 'A' );\r\n ElementAttrPutS( sAttrVal, pTgtDim, pTgtHier, vElement, sAttrName, 1 );\r\n Else;\r\n ElementAttrPutS( sAttrVal, pTgtDim, pTgtHier, vElement, sAttrName );\r\n EndIf;\r\n EndIf;\r\n Else;\r\n nAttrVal = ElementAttrN(pSrcDim, pSrcHier, vElement, sAttrName);\r\n If( nAttrVal <> 0 );\r\n If( pStrictErrorHandling = 0 & CellIsUpdateable(sTgtAttrDim, pTgtHier:vElement, sAttrName) = 0 );\r\n #skip\r\n Else;\r\n ElementAttrPutN( nAttrVal, pTgtDim, pTgtHier, vElement, sAttrName );\r\n EndIf;\r\n EndIf;\r\n EndIf;\r\n nCount = nCount + 1;\r\n End;\r\n\r\n EndIf;\r\n\r\n### End Data ###", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n### Set Target dimension sort order ###\r\n\r\nIf(pSrcDim @= pSrcHier);\r\n sSourceElement = pSrcDim;\r\nElse;\r\n sSourceElement = pSrcDim|':'|pSrcHier;\r\nEndif;\r\nIf(pTgtDim @= pTgtHier);\r\n sTargetElement = pTgtDim;\r\nElse;\r\n sTargetElement = pTgtDim|':'|pTgtHier;\r\nEndif;\r\n\r\n# Placeholder for copying dimension order and captions from source to target as expecting a TI function to be made available to be able to read & modify these properties\r\n\r\n### Set Descendent attribute value\r\nAttrDelete( pSrcDim, cHierAttr );\r\nIf( pAttr = 1 );\r\n AttrDelete( pTgtDim, cHierAttr );\r\nENDIF;\r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully cloned dimension:hierarchy %pSrcDim%:%pSrcHier% to %pTgtDim%:%pTgtHier% based on the %pSubset% subset.' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n### End Epilog ###", @@ -13,65 +13,71 @@ "subset": "All" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pSrcDim", - "Prompt": "REQUIRED: Source Dimension", + "Prompt": "REQUIRED: Source dimension name", "Value": "", "Type": "String" }, { "Name": "pSrcHier", - "Prompt": "OPTIONAL: Source Hierarchy (blank = same name as source dimension)", + "Prompt": "OPTIONAL: Source hierarchy name (Default = pSrcDim)", "Value": "", "Type": "String" }, { "Name": "pSubset", - "Prompt": "REQUIRED: Source Subset", + "Prompt": "REQUIRED: Subset name", "Value": "", "Type": "String" }, { "Name": "pTgtDim", - "Prompt": "OPTIONAL: Target Dimension (blank = same name as source dimension)", + "Prompt": "OPTIONAL: Target dimension name (Default = pSrcDim)", "Value": "", "Type": "String" }, { "Name": "pTgtHier", - "Prompt": "OPTIONAL: Target Hierarchy (blank = same name as target dimension)", + "Prompt": "OPTIONAL: Target hierarchy name (Default = pTgtDim)", "Value": "", "Type": "String" }, { "Name": "pAttr", - "Prompt": "OPTIONAL: Include Attributes? (Boolean 1=True)", + "Prompt": "OPTIONAL: Include attributes (Boolean. Default = 1)", "Value": 1, "Type": "Numeric" }, { "Name": "pUnwind", - "Prompt": "OPTIONAL: 0 = Delete all Elements, 1 = Unwind Existing Elements, 2 = Do not change Existing Elements", + "Prompt": "OPTIONAL: Unwind target hierarchy before process (0 = Delete all elements, 1 = Unwind existing elements, 2 = Do not change existing elements. Default = 0)", "Value": 0, "Type": "Numeric" }, { "Name": "pFlat", - "Prompt": "OPTIONAL: Whether to create flat hierarchy? (1 = Yes, 0 = No)", + "Prompt": "OPTIONAL: Create the hierarchy flat (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [ diff --git a/bedrock_processes_json/}bedrock.hier.create.json b/bedrock_processes_json/}bedrock.hier.create.json index 82c87b3..75e0c57 100644 --- a/bedrock_processes_json/}bedrock.hier.create.json +++ b/bedrock_processes_json/}bedrock.hier.create.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.hier.create", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.create', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n\t 'pDim', '', 'pHier', '', 'pDelim', '&'\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock Ver 4.0 ~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will create a new hierarchy pHier in target dimension pDim.\r\n\r\n# Use case: Intended for Development but could be used in production too.\r\n# 1/ Create a new hierarchy for testing.\r\n# 2/ Create a new hierarchy to reflect new business needs.\r\n\r\n# Note:\r\n# If dimension pDim doesn't exist, it will be created.\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncMsgInfoContent = 'User:%cUserName% Process:%cThisProcName% Message:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pHier:%pHier%, pDelim:%pDelim%.'; \r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\nIf( Scan( '*', pDim ) = 0 & Scan( '?', pDim ) = 0 & Scan( pDelim, pDim ) = 0 & Scan( ':', pDim ) > 0 & pHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pHier = SubSt( pDim, Scan( ':', pDim ) + 1, Long( pDim ) );\r\n pDim = SubSt( pDim, 1, Scan( ':', pDim ) - 1 );\r\nEndIf;\r\n\r\nIf( Trim( pDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# If blank delimiter specified then convert to default\r\nIf( pDelim @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n# Set up hierachy if not provided\r\nIf( Trim( pHier ) @= '' );\r\n pHier = pDim;\r\nEndIf;\r\n\r\n# Loop through dimensions in pDim\r\nsDims = pDim;\r\nnDimDelimiterIndex = 1;\r\nsMdx = '';\r\n# Get 1st dimension\r\nWhile( nDimDelimiterIndex <> 0 );\r\n # Extract 1st dimension > sDim\r\n nDimDelimiterIndex = Scan( pDelim, sDims );\r\n If( nDimDelimiterIndex = 0 );\r\n sDim = sDims;\r\n Else;\r\n sDim = Trim( SubSt( sDims, 1, nDimDelimiterIndex - 1 ) );\r\n sDims = Trim( Subst( sDims, nDimDelimiterIndex + Long(pDelim), Long( sDims ) ) );\r\n EndIf;\r\n \r\n ###Creating Dimension if not exist, where no wildcard\r\n If( Scan( '*', sDim ) = 0 & Scan( '?', sDim ) = 0 & Scan( pDelim, sDim ) = 0 & DimensionExists( sDim ) = 0 );\r\n DimensionCreate( sDim );\r\n If( pLogOutput = 1 );\r\n sMessage = Expand( 'Creating Dimension %sDim%' );\r\n LogOutput( 'INFO', Expand( cMsgInfoContent ) );\r\n EndIf;\r\n EndIf;\r\n \r\n # Create subset of dimensions using Wildcard to loop through dimensions in pDim with wildcard\r\n sDimExp = '\"'|sDim|'\"';\r\n sMdxPart = '{TM1FILTERBYPATTERN( EXCEPT( TM1SUBSETALL( [}Dimensions] ) , TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) , \"*:*\") ) ,'| sDimExp | ')}';\r\n IF( sMdx @= ''); \r\n sMdx = sMdxPart; \r\n ELSE;\r\n sMdx = sMdx | ' + ' | sMdxPart;\r\n ENDIF;\r\nEnd;\r\n\r\nIf( SubsetExists( '}Dimensions' , cTempSub ) = 1 );\r\n # If a delimited list of dim names includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( '}Dimensions' , cTempSub, sMDX );\r\nElse;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSub, sMDX, '}Dimensions' , 1 );\r\nEndIf;\r\n\r\n# Loop through dimensions in subset created based on wildcard\r\nnCountDim = SubsetGetSize( '}Dimensions' , cTempSub );\r\nWhile( nCountDim >= 1 );\r\n sDim = SubsetGetElementName( '}Dimensions' , cTempSub, nCountDim );\r\n # Validate dimension name\r\n If( DimensionExists(sDim) = 0 );\r\n nErrors = 1;\r\n sMessage = Expand( 'Dimension %sDim% does not exist.' );\r\n LogOutput( 'ERROR', Expand( cMsgErrorContent ) );\r\n Else;\r\n If( pLogOutput = 1 );\r\n sMessage = Expand( 'Dimension %sDim% being processed....' );\r\n LogOutput( 'INFO', Expand( cMsgInfoContent ) );\r\n EndIf;\r\n # Loop through hierarchies in pHier\r\n sHierarchies = pHier;\r\n nDelimiterIndexA = 1;\r\n While( nDelimiterIndexA <> 0 );\r\n\r\n nDelimiterIndexA = Scan( pDelim, sHierarchies );\r\n If( nDelimiterIndexA = 0 );\r\n sHierarchy = sHierarchies;\r\n Else;\r\n sHierarchy = Trim( SubSt( sHierarchies, 1, nDelimiterIndexA - 1 ) );\r\n sHierarchies = Trim( Subst( sHierarchies, nDelimiterIndexA + Long(pDelim), Long( sHierarchies ) ) );\r\n EndIf;\r\n ###Creating Hierarchy\r\n If( HierarchyExists( sDim, sHierarchy ) = 1 & sDim @<> sHierarchy );\r\n nErrors = 1;\r\n sMessage = 'The Hierachy ' | pHier | ' already exists.';\r\n LogOutput( cMsgErrorLevel, sMessage );\r\n ElseIf( sDim @<> sHierarchy );\r\n HierarchyCreate( sDim , sHierarchy );\r\n If( pLogOutput = 1 );\r\n sMessage = Expand( 'Creating hierarchy %sHierarchy% in Dimension %sDim%' );\r\n LogOutput( 'INFO', Expand( cMsgInfoContent ) );\r\n EndIf;\r\n EndIf;\r\n End;\r\n EndIf;\r\n \r\n nCountDim = nCountDim - 1;\r\nEnd;\r\n \r\n\r\n### End Prolog ###", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.create', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n\t 'pDim', '', 'pHier', '', 'pDelim', '&'\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock Ver 4.0 ~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will create a new hierarchy pHier in target dimension pDim.\r\n\r\n# Use case: Intended for Development but could be used in production too.\r\n# 1/ Create a new hierarchy for testing.\r\n# 2/ Create a new hierarchy to reflect new business needs.\r\n\r\n# Note:\r\n# If dimension pDim doesn't exist, it will be created.\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncMsgInfoContent = 'User:%cUserName% Process:%cThisProcName% Message:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pHier:%pHier%, pDelim:%pDelim%.';\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pDelim\": \"&\",\r\n \"pDim\": null,\r\n \"pHier\": \"\",\r\n \"pLogOutput\": 0,\r\n \"pStrictErrorHandling\": 0\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pDelim\": '|StringToJson ( pDelim )|',\r\n \"pDim\": '|StringToJson ( pDim )|',\r\n \"pHier\": '|StringToJson ( pHier )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npDelim = JsonToString( JsonGet( pJson, 'pDelim' ) );\r\npDim = JsonToString( JsonGet( pJson, 'pDim' ) );\r\npHier = JsonToString( JsonGet( pJson, 'pHier' ) );\r\n# Numeric Parameters\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\nIf( Scan( '*', pDim ) = 0 & Scan( '?', pDim ) = 0 & Scan( pDelim, pDim ) = 0 & Scan( ':', pDim ) > 0 & pHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pHier = SubSt( pDim, Scan( ':', pDim ) + 1, Long( pDim ) );\r\n pDim = SubSt( pDim, 1, Scan( ':', pDim ) - 1 );\r\nEndIf;\r\n\r\nIf( Trim( pDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# If blank delimiter specified then convert to default\r\nIf( pDelim @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n# Set up hierachy if not provided\r\nIf( Trim( pHier ) @= '' );\r\n pHier = pDim;\r\nEndIf;\r\n\r\n# Loop through dimensions in pDim\r\nsDims = pDim;\r\nnDimDelimiterIndex = 1;\r\nsMdx = '';\r\n# Get 1st dimension\r\nWhile( nDimDelimiterIndex <> 0 );\r\n # Extract 1st dimension > sDim\r\n nDimDelimiterIndex = Scan( pDelim, sDims );\r\n If( nDimDelimiterIndex = 0 );\r\n sDim = sDims;\r\n Else;\r\n sDim = Trim( SubSt( sDims, 1, nDimDelimiterIndex - 1 ) );\r\n sDims = Trim( Subst( sDims, nDimDelimiterIndex + Long(pDelim), Long( sDims ) ) );\r\n EndIf;\r\n \r\n ###Creating Dimension if not exist, where no wildcard\r\n If( Scan( '*', sDim ) = 0 & Scan( '?', sDim ) = 0 & Scan( pDelim, sDim ) = 0 & DimensionExists( sDim ) = 0 );\r\n DimensionCreate( sDim );\r\n If( pLogOutput = 1 );\r\n sMessage = Expand( 'Creating Dimension %sDim%' );\r\n LogOutput( 'INFO', Expand( cMsgInfoContent ) );\r\n EndIf;\r\n EndIf;\r\n \r\n # Create subset of dimensions using Wildcard to loop through dimensions in pDim with wildcard\r\n sDimExp = '\"'|sDim|'\"';\r\n sMdxPart = '{TM1FILTERBYPATTERN( EXCEPT( TM1SUBSETALL( [}Dimensions] ) , TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) , \"*:*\") ) ,'| sDimExp | ')}';\r\n IF( sMdx @= ''); \r\n sMdx = sMdxPart; \r\n ELSE;\r\n sMdx = sMdx | ' + ' | sMdxPart;\r\n ENDIF;\r\nEnd;\r\n\r\nIf( SubsetExists( '}Dimensions' , cTempSub ) = 1 );\r\n # If a delimited list of dim names includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( '}Dimensions' , cTempSub, sMDX );\r\nElse;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSub, sMDX, '}Dimensions' , 1 );\r\nEndIf;\r\n\r\n# Loop through dimensions in subset created based on wildcard\r\nnCountDim = SubsetGetSize( '}Dimensions' , cTempSub );\r\nWhile( nCountDim >= 1 );\r\n sDim = SubsetGetElementName( '}Dimensions' , cTempSub, nCountDim );\r\n # Validate dimension name\r\n If( DimensionExists(sDim) = 0 );\r\n nErrors = 1;\r\n sMessage = Expand( 'Dimension %sDim% does not exist.' );\r\n LogOutput( 'ERROR', Expand( cMsgErrorContent ) );\r\n Else;\r\n If( pLogOutput = 1 );\r\n sMessage = Expand( 'Dimension %sDim% being processed....' );\r\n LogOutput( 'INFO', Expand( cMsgInfoContent ) );\r\n EndIf;\r\n # Loop through hierarchies in pHier\r\n sHierarchies = pHier;\r\n nDelimiterIndexA = 1;\r\n While( nDelimiterIndexA <> 0 );\r\n\r\n nDelimiterIndexA = Scan( pDelim, sHierarchies );\r\n If( nDelimiterIndexA = 0 );\r\n sHierarchy = sHierarchies;\r\n Else;\r\n sHierarchy = Trim( SubSt( sHierarchies, 1, nDelimiterIndexA - 1 ) );\r\n sHierarchies = Trim( Subst( sHierarchies, nDelimiterIndexA + Long(pDelim), Long( sHierarchies ) ) );\r\n EndIf;\r\n ###Creating Hierarchy\r\n If( HierarchyExists( sDim, sHierarchy ) = 1 & sDim @<> sHierarchy );\r\n nErrors = 1;\r\n sMessage = 'The Hierachy ' | pHier | ' already exists.';\r\n LogOutput( cMsgErrorLevel, sMessage );\r\n ElseIf( sDim @<> sHierarchy );\r\n HierarchyCreate( sDim , sHierarchy );\r\n If( pLogOutput = 1 );\r\n sMessage = Expand( 'Creating hierarchy %sHierarchy% in Dimension %sDim%' );\r\n LogOutput( 'INFO', Expand( cMsgInfoContent ) );\r\n EndIf;\r\n EndIf;\r\n End;\r\n EndIf;\r\n \r\n nCountDim = nCountDim - 1;\r\nEnd;\r\n \r\n\r\n### End Prolog ###", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully created the %pHier% hierarchy in the %pDim% dimension.' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n\r\n\r\n### End Epilog ###", @@ -10,35 +10,41 @@ "Type": "None" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pDim", - "Prompt": "REQUIRED: Dimension, accepts wildcards (if = *, then all the dimensions)", + "Prompt": "REQUIRED: Delimited list of dimensions", "Value": "", "Type": "String" }, { "Name": "pHier", - "Prompt": "OPTIONAL: Hierarchy, accepts delimited list", + "Prompt": "OPTIONAL: Delimited list of hierarchies (Default = pDim)", "Value": "", "Type": "String" }, { "Name": "pDelim", - "Prompt": "OPTIONAL: delimiter character for element list. (default value if blank = '&')", + "Prompt": "OPTIONAL: Delimiter for list parameters (Default = '&')", "Value": "&", "Type": "String" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [], diff --git a/bedrock_processes_json/}bedrock.hier.delete.json b/bedrock_processes_json/}bedrock.hier.delete.json index c226057..407901a 100644 --- a/bedrock_processes_json/}bedrock.hier.delete.json +++ b/bedrock_processes_json/}bedrock.hier.delete.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.hier.delete", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.delete', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n\t 'pDim', '', 'pHier', '', 'pDelim', '&'\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~ Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock Ver 4.0 ~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process deletes a dimension or hierarchy (or a list thereof).\r\n\r\n# Use case: Intended for development/prototyping.\r\n# 1/ Clean up unused dimension/hierarchies after Go Live.\r\n\r\n# Note:\r\n# Naturally, a valid dimension name (pDim) is mandatory otherwise the process will abort.\r\n# If no hierarchy (pHier) is specified the dimension will be deleted if not in use by a **regular** cube.\r\n# If a hierarchy is specified, it must be valid otherwise the process will abort.\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncMsgInfoContent = 'User:%cUserName% Process:%cThisProcName% Message:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pHier:%pHier%, pDelim:%pDelim%.'; \r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\nIf( Scan( '*', pDim ) = 0 & Scan( '?', pDim ) = 0 & Scan( pDelim, pDim ) = 0 & Scan( ':', pDim ) > 0 & pHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pHier = SubSt( pDim, Scan( ':', pDim ) + 1, Long( pDim ) );\r\n pDim = SubSt( pDim, 1, Scan( ':', pDim ) - 1 );\r\nEndIf;\r\n\r\nIf( Trim( pDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIF( Scan( '*', pDim ) = 0 & Scan( '?', pDim ) = 0 & Scan( pDelim, pDim ) = 0 & DimensionExists( pDim ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid dimension: ' | pDim;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nIf( Trim( pHier ) @= '' );\r\n ## use same name as Dimension. Since wildcards are allowed this is managed inside the code below\r\nElseIf( Trim( pHier ) @= 'Leaves' );\r\n nErrors = 1;\r\n sMessage = 'Invalid hierarchy: \"Leaves\".';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( Scan( '*', pHier ) = 0 & Scan( '?', pHier ) = 0 & Scan( pDelim, pHier ) = 0 & Scan( '*', pDim ) = 0 & Scan( '?', pDim ) = 0 & Scan( pDelim, pDim ) = 0 & Trim( pHier ) @= Trim( pDim ) );\r\n nErrors = 1;\r\n sMessage = 'Cannot delete same named hierarchy: \"}bedrock.dim.delete\" process should be used for this purpose';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# If blank delimiter specified then convert to default\r\nIf( pDelim @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n\r\nIF( Scan( '*', pHier ) = 0 & Scan( '?', pHier ) = 0 & Scan( pDelim, pHier ) = 0 & Scan( '*', pDim ) = 0 & Scan( '?', pDim ) = 0 & Scan( pDelim, pDim ) = 0 );\r\n If( HierarchyExists( pDim, pHier ) = 0 );\r\n nError = 1;\r\n sMessage = 'The Hierachy \"' | pHier | '\" is not available in \"' | pDim | '\" dimension' ;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n Else;\r\n HierarchyDestroy( pDim ,pHier );\r\n Endif;\r\nElseIf( pHier @= 'Leaves');\r\n nError = 1;\r\n sMessage = 'The Hierachy is Leaves and can not be destroyed';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElse;\r\n # Loop through dimensions in pDim\r\n sDims = pDim;\r\n nDimDelimiterIndex = 1;\r\n sMdx = '';\r\n # Get 1st dimension\r\n While( nDimDelimiterIndex <> 0 );\r\n # Extract 1st dimension > sDim\r\n nDimDelimiterIndex = Scan( pDelim, sDims );\r\n If( nDimDelimiterIndex = 0 );\r\n sDim = sDims;\r\n Else;\r\n sDim = Trim( SubSt( sDims, 1, nDimDelimiterIndex - 1 ) );\r\n sDims = Trim( Subst( sDims, nDimDelimiterIndex + Long(pDelim), Long( sDims ) ) );\r\n EndIf;\r\n \r\n # Create subset of dimensions using Wildcard to loop through dimensions in pDim with wildcard\r\n sDimExp = '\"'|sDim|'\"';\r\n sMdxPart = '{TM1FILTERBYPATTERN( EXCEPT( TM1SUBSETALL( [}Dimensions] ) , TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) , \"*:*\") ) ,'| sDimExp | ')}';\r\n IF( sMdx @= ''); \r\n sMdx = sMdxPart; \r\n ELSE;\r\n sMdx = sMdx | ' + ' | sMdxPart;\r\n ENDIF;\r\n End;\r\n \r\n If( SubsetExists( '}Dimensions' , cTempSub ) = 1 );\r\n # If a delimited list of dim names includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( '}Dimensions' , cTempSub, sMDX );\r\n Else;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSub, sMDX, '}Dimensions' , 1 );\r\n EndIf;\r\n \r\n # Loop through dimensions in subset created based on wildcard\r\n nCountDim = SubsetGetSize( '}Dimensions' , cTempSub );\r\n While( nCountDim >= 1 );\r\n sDim = SubsetGetElementName( '}Dimensions' , cTempSub, nCountDim );\r\n # Validate dimension name\r\n If( DimensionExists(sDim) = 0 );\r\n nErrors = 1;\r\n sMessage = Expand( 'Dimension %sDim% does not exist.' );\r\n LogOutput( 'ERROR', Expand( cMsgErrorContent ) );\r\n Else;\r\n If( pLogOutput = 1 );\r\n sMessage = Expand( 'Dimension %sDim% being processed....' );\r\n LogOutput( 'INFO', Expand( cMsgInfoContent ) );\r\n EndIf;\r\n # Loop through hierarchies in pHier\r\n If( Trim( pHier ) @= '' );\r\n ### Use main hierarchy for each dimension if pHier is empty\r\n sHierarchies = sDim;\r\n Else;\r\n sHierarchies = pHier;\r\n EndIf;\r\n nDelimiterIndexA = 1;\r\n sHierDim = '}Hierarchies_'|sDim ;\r\n sMdxHier = '';\r\n While( nDelimiterIndexA <> 0 );\r\n \r\n nDelimiterIndexA = Scan( pDelim, sHierarchies );\r\n If( nDelimiterIndexA = 0 );\r\n sHierarchy = sHierarchies;\r\n Else;\r\n sHierarchy = Trim( SubSt( sHierarchies, 1, nDelimiterIndexA - 1 ) );\r\n sHierarchies = Trim( Subst( sHierarchies, nDelimiterIndexA + Long(pDelim), Long( sHierarchies ) ) );\r\n EndIf;\r\n \r\n # Create subset of Hierarchies using Wildcard\r\n sHierExp = '\"'|sDim|':'|sHierarchy|'\"';\r\n sMdxHierPart = '{TM1FILTERBYPATTERN( {TM1SUBSETALL([ ' |sHierDim| '])},'| sHierExp | ')}';\r\n IF( sMdxHier @= ''); \r\n sMdxHier = sMdxHierPart; \r\n ELSE;\r\n sMdxHier = sMdxHier | ' + ' | sMdxHierPart;\r\n ENDIF;\r\n End;\r\n \r\n If( SubsetExists( sHierDim, cTempSub ) = 1 );\r\n # If a delimited list of attr names includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( sHierDim, cTempSub, sMdxHier );\r\n Else;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSub, sMdxHier, sHierDim, 1 );\r\n EndIf;\r\n \r\n # Loop through subset of hierarchies created based on wildcard\r\n nCountHier = SubsetGetSize( sHierDim, cTempSub );\r\n While( nCountHier >= 1 );\r\n sCurrHier = SubsetGetElementName( sHierDim, cTempSub, nCountHier );\r\n sCurrHierName = Subst( sCurrHier, Scan(':', sCurrHier)+1, Long(sCurrHier) );\r\n \r\n # Validate hierarchy name in dimension\r\n If( Dimix( sHierDim , sCurrHier ) = 0 );\r\n sMessage = Expand('The %sCurrHier% hierarchy does NOT exist in the %sDim% dimension.');\r\n LogOutput( 'INFO' , Expand( cMsgInfoContent ) );\r\n Else;\r\n If( pLogOutput = 1 );\r\n sMessage = Expand( 'Hierarchy %sCurrHierName% in Dimension %sDim% being processed....' );\r\n LogOutput( 'INFO', Expand( cMsgInfoContent ) );\r\n EndIf;\r\n If( Trim( sCurrHierName ) @= Trim( sDim ) );\r\n ## Do not remove main hierarchy\r\n ElseIf( sCurrHierName @= 'Leaves');\r\n If( pLogOutput = 1 );\r\n sMessage = 'The Hierachy is Leaves and can not be destroyed';\r\n LogOutput( 'INFO', Expand( cMsgInfoContent ) );\r\n EndIf;\r\n Else;\r\n HierarchyDestroy( sDim, sCurrHierName );\r\n If( pLogOutput = 1 );\r\n sMessage = Expand( 'Destroying hierarchy %sCurrHierName% in Dimension %sDim%' );\r\n LogOutput( 'INFO', Expand( cMsgInfoContent ) );\r\n EndIf;\r\n Endif;\r\n Endif;\r\n \r\n nCountHier = nCountHier - 1;\r\n End;\r\n \r\n EndIf;\r\n \r\n nCountDim = nCountDim - 1;\r\n End;\r\nEndIf;\r\n\r\n\r\n### End Prolog ###", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.delete', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n\t 'pDim', '', 'pHier', '', 'pDelim', '&'\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~ Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock Ver 4.0 ~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process deletes a dimension or hierarchy (or a list thereof).\r\n\r\n# Use case: Intended for development/prototyping.\r\n# 1/ Clean up unused dimension/hierarchies after Go Live.\r\n\r\n# Note:\r\n# Naturally, a valid dimension name (pDim) is mandatory otherwise the process will abort.\r\n# If no hierarchy (pHier) is specified the dimension will be deleted if not in use by a **regular** cube.\r\n# If a hierarchy is specified, it must be valid otherwise the process will abort.\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncMsgInfoContent = 'User:%cUserName% Process:%cThisProcName% Message:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pHier:%pHier%, pDelim:%pDelim%.';\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pDelim\": \"&\",\r\n \"pDim\": null,\r\n \"pHier\": \"\",\r\n \"pLogOutput\": 0,\r\n \"pStrictErrorHandling\": 0\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pDelim\": '|StringToJson ( pDelim )|',\r\n \"pDim\": '|StringToJson ( pDim )|',\r\n \"pHier\": '|StringToJson ( pHier )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npDelim = JsonToString( JsonGet( pJson, 'pDelim' ) );\r\npDim = JsonToString( JsonGet( pJson, 'pDim' ) );\r\npHier = JsonToString( JsonGet( pJson, 'pHier' ) );\r\n# Numeric Parameters\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\nIf( Scan( '*', pDim ) = 0 & Scan( '?', pDim ) = 0 & Scan( pDelim, pDim ) = 0 & Scan( ':', pDim ) > 0 & pHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pHier = SubSt( pDim, Scan( ':', pDim ) + 1, Long( pDim ) );\r\n pDim = SubSt( pDim, 1, Scan( ':', pDim ) - 1 );\r\nEndIf;\r\n\r\nIf( Trim( pDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIF( Scan( '*', pDim ) = 0 & Scan( '?', pDim ) = 0 & Scan( pDelim, pDim ) = 0 & DimensionExists( pDim ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid dimension: ' | pDim;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nIf( Trim( pHier ) @= '' );\r\n ## use same name as Dimension. Since wildcards are allowed this is managed inside the code below\r\nElseIf( Trim( pHier ) @= 'Leaves' );\r\n nErrors = 1;\r\n sMessage = 'Invalid hierarchy: \"Leaves\".';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( Scan( '*', pHier ) = 0 & Scan( '?', pHier ) = 0 & Scan( pDelim, pHier ) = 0 & Scan( '*', pDim ) = 0 & Scan( '?', pDim ) = 0 & Scan( pDelim, pDim ) = 0 & Trim( pHier ) @= Trim( pDim ) );\r\n nErrors = 1;\r\n sMessage = 'Cannot delete same named hierarchy: \"}bedrock.dim.delete\" process should be used for this purpose';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# If blank delimiter specified then convert to default\r\nIf( pDelim @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n\r\nIF( Scan( '*', pHier ) = 0 & Scan( '?', pHier ) = 0 & Scan( pDelim, pHier ) = 0 & Scan( '*', pDim ) = 0 & Scan( '?', pDim ) = 0 & Scan( pDelim, pDim ) = 0 );\r\n If( HierarchyExists( pDim, pHier ) = 0 );\r\n nError = 1;\r\n sMessage = 'The Hierachy \"' | pHier | '\" is not available in \"' | pDim | '\" dimension' ;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n Else;\r\n HierarchyDestroy( pDim ,pHier );\r\n Endif;\r\nElseIf( pHier @= 'Leaves');\r\n nError = 1;\r\n sMessage = 'The Hierachy is Leaves and can not be destroyed';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElse;\r\n # Loop through dimensions in pDim\r\n sDims = pDim;\r\n nDimDelimiterIndex = 1;\r\n sMdx = '';\r\n # Get 1st dimension\r\n While( nDimDelimiterIndex <> 0 );\r\n # Extract 1st dimension > sDim\r\n nDimDelimiterIndex = Scan( pDelim, sDims );\r\n If( nDimDelimiterIndex = 0 );\r\n sDim = sDims;\r\n Else;\r\n sDim = Trim( SubSt( sDims, 1, nDimDelimiterIndex - 1 ) );\r\n sDims = Trim( Subst( sDims, nDimDelimiterIndex + Long(pDelim), Long( sDims ) ) );\r\n EndIf;\r\n \r\n # Create subset of dimensions using Wildcard to loop through dimensions in pDim with wildcard\r\n sDimExp = '\"'|sDim|'\"';\r\n sMdxPart = '{TM1FILTERBYPATTERN( EXCEPT( TM1SUBSETALL( [}Dimensions] ) , TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) , \"*:*\") ) ,'| sDimExp | ')}';\r\n IF( sMdx @= ''); \r\n sMdx = sMdxPart; \r\n ELSE;\r\n sMdx = sMdx | ' + ' | sMdxPart;\r\n ENDIF;\r\n End;\r\n \r\n If( SubsetExists( '}Dimensions' , cTempSub ) = 1 );\r\n # If a delimited list of dim names includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( '}Dimensions' , cTempSub, sMDX );\r\n Else;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSub, sMDX, '}Dimensions' , 1 );\r\n EndIf;\r\n \r\n # Loop through dimensions in subset created based on wildcard\r\n nCountDim = SubsetGetSize( '}Dimensions' , cTempSub );\r\n While( nCountDim >= 1 );\r\n sDim = SubsetGetElementName( '}Dimensions' , cTempSub, nCountDim );\r\n # Validate dimension name\r\n If( DimensionExists(sDim) = 0 );\r\n nErrors = 1;\r\n sMessage = Expand( 'Dimension %sDim% does not exist.' );\r\n LogOutput( 'ERROR', Expand( cMsgErrorContent ) );\r\n Else;\r\n If( pLogOutput = 1 );\r\n sMessage = Expand( 'Dimension %sDim% being processed....' );\r\n LogOutput( 'INFO', Expand( cMsgInfoContent ) );\r\n EndIf;\r\n # Loop through hierarchies in pHier\r\n If( Trim( pHier ) @= '' );\r\n ### Use main hierarchy for each dimension if pHier is empty\r\n sHierarchies = sDim;\r\n Else;\r\n sHierarchies = pHier;\r\n EndIf;\r\n nDelimiterIndexA = 1;\r\n sHierDim = '}Hierarchies_'|sDim ;\r\n sMdxHier = '';\r\n While( nDelimiterIndexA <> 0 );\r\n \r\n nDelimiterIndexA = Scan( pDelim, sHierarchies );\r\n If( nDelimiterIndexA = 0 );\r\n sHierarchy = sHierarchies;\r\n Else;\r\n sHierarchy = Trim( SubSt( sHierarchies, 1, nDelimiterIndexA - 1 ) );\r\n sHierarchies = Trim( Subst( sHierarchies, nDelimiterIndexA + Long(pDelim), Long( sHierarchies ) ) );\r\n EndIf;\r\n \r\n # Create subset of Hierarchies using Wildcard\r\n sHierExp = '\"'|sDim|':'|sHierarchy|'\"';\r\n sMdxHierPart = '{TM1FILTERBYPATTERN( {TM1SUBSETALL([ ' |sHierDim| '])},'| sHierExp | ')}';\r\n IF( sMdxHier @= ''); \r\n sMdxHier = sMdxHierPart; \r\n ELSE;\r\n sMdxHier = sMdxHier | ' + ' | sMdxHierPart;\r\n ENDIF;\r\n End;\r\n \r\n If( SubsetExists( sHierDim, cTempSub ) = 1 );\r\n # If a delimited list of attr names includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( sHierDim, cTempSub, sMdxHier );\r\n Else;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSub, sMdxHier, sHierDim, 1 );\r\n EndIf;\r\n \r\n # Loop through subset of hierarchies created based on wildcard\r\n nCountHier = SubsetGetSize( sHierDim, cTempSub );\r\n While( nCountHier >= 1 );\r\n sCurrHier = SubsetGetElementName( sHierDim, cTempSub, nCountHier );\r\n sCurrHierName = Subst( sCurrHier, Scan(':', sCurrHier)+1, Long(sCurrHier) );\r\n \r\n # Validate hierarchy name in dimension\r\n If( Dimix( sHierDim , sCurrHier ) = 0 );\r\n sMessage = Expand('The %sCurrHier% hierarchy does NOT exist in the %sDim% dimension.');\r\n LogOutput( 'INFO' , Expand( cMsgInfoContent ) );\r\n Else;\r\n If( pLogOutput = 1 );\r\n sMessage = Expand( 'Hierarchy %sCurrHierName% in Dimension %sDim% being processed....' );\r\n LogOutput( 'INFO', Expand( cMsgInfoContent ) );\r\n EndIf;\r\n If( Trim( sCurrHierName ) @= Trim( sDim ) );\r\n ## Do not remove main hierarchy\r\n ElseIf( sCurrHierName @= 'Leaves');\r\n If( pLogOutput = 1 );\r\n sMessage = 'The Hierachy is Leaves and can not be destroyed';\r\n LogOutput( 'INFO', Expand( cMsgInfoContent ) );\r\n EndIf;\r\n Else;\r\n HierarchyDestroy( sDim, sCurrHierName );\r\n If( pLogOutput = 1 );\r\n sMessage = Expand( 'Destroying hierarchy %sCurrHierName% in Dimension %sDim%' );\r\n LogOutput( 'INFO', Expand( cMsgInfoContent ) );\r\n EndIf;\r\n Endif;\r\n Endif;\r\n \r\n nCountHier = nCountHier - 1;\r\n End;\r\n \r\n EndIf;\r\n \r\n nCountDim = nCountDim - 1;\r\n End;\r\nEndIf;\r\n\r\n\r\n### End Prolog ###", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully deleted the dimension:hierarchy %pDim%:%pHier%' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n### End Epilog ###", @@ -10,35 +10,41 @@ "Type": "None" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pDim", - "Prompt": "REQUIRED: Dimension, accepts wildcards (if = *, then all the dimensions)", + "Prompt": "REQUIRED: Delimited list of dimensions", "Value": "", "Type": "String" }, { "Name": "pHier", - "Prompt": "OPTIONAL: Hierarchy, accepts wildcards (all hierarchies except default and Leaves deleted if = *)", + "Prompt": "OPTIONAL: Hierarchy name (Default = pDim)", "Value": "", "Type": "String" }, { "Name": "pDelim", - "Prompt": "OPTIONAL: delimiter character for element list. (default value if blank = '&')", + "Prompt": "OPTIONAL: Delimiter for list parameters (Default = '&')", "Value": "&", "Type": "String" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [], diff --git a/bedrock_processes_json/}bedrock.hier.element.create.json b/bedrock_processes_json/}bedrock.hier.element.create.json index 04e7e38..bdf0f38 100644 --- a/bedrock_processes_json/}bedrock.hier.element.create.json +++ b/bedrock_processes_json/}bedrock.hier.element.create.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.hier.element.create", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.element.create', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pDim', '', 'pHier', '', 'pEle', '',\r\n 'pEleType', '', 'pInsertionPoint', '',\r\n 'pDelim', '&'\r\n );\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n \r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n \r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n \r\n#Region @DOC\r\n# Description:\r\n# This process will create new element in a dimension Hierarchy. More elements than one will be\r\n# created if pEle is supplied with a delimited list of elements.\r\n \r\n# Note:\r\n# Valid dimension name (pDim) and element list are mandatory, otherwise the process will abort.\r\n \r\n# Caution: When target hierarchy is `Leaves`, no consolidated elements will be created.\r\n#EndRegion @DOC\r\n \r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n \r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSubDim = cThisProcName |'_dims_'| cTimeStamp |'_'| cRandomInt;\r\ncTempSubHier = cThisProcName |'_hiers_'| cTimeStamp |'_'| cRandomInt;\r\ncUserName = TM1User();\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncMsgInfoContent = 'User:%cUserName% Process:%cThisProcName% Message:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pHier:%pHier%, pEle:%pEle%, pEleType:%pEleType%, pInsertionPoint:%pInsertionPoint%, pDelim:%pDelim%.'; \r\n \r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n \r\n### Validate Parameters ###\r\nnErrors = 0;\r\n \r\nIf( Scan( '*', pDim ) = 0 & Scan( '?', pDim ) = 0 & Scan( pDelim, pDim ) = 0 & Scan( ':', pDim ) > 0 & pHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pHier = SubSt( pDim, Scan( ':', pDim ) + 1, Long( pDim ) );\r\n pDim = SubSt( pDim, 1, Scan( ':', pDim ) - 1 );\r\nEndIf;\r\n \r\n# Validate dimension\r\nIf( Trim( pDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n \r\n# Validate Hierarchy\r\nIf( Trim( pHier ) @= '' );\r\n ## use same name as Dimension. Since wildcards are allowed this is managed inside the code below\r\nEndIf;\r\n \r\n# Validate element\r\nIf( Trim( pEle ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No element specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n \r\n# Validate element type\r\nIf( pEleType @= '' );\r\n pEleType = 'N';\r\nEndIf;\r\npEleType = Upper( pEleType );\r\nIf( pEleType @<> 'N' & pEleType @<> 'C' & pEleType @<> 'S' );\r\n nErrors = 1;\r\n sMessage = 'Invalid element type: ' | pEleType;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n \r\n# If blank delimiter specified then convert to default\r\nIf( pDelim @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n \r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n \r\n \r\n# Loop through dimensions in pDim\r\nsDims = pDim;\r\nnDimDelimiterIndex = 1;\r\nsMdx = '';\r\n# Get 1st dimension\r\nWhile( nDimDelimiterIndex <> 0 );\r\n # Extract 1st dimension > sDim\r\n nDimDelimiterIndex = Scan( pDelim, sDims );\r\n If( nDimDelimiterIndex = 0 );\r\n sDim = sDims;\r\n Else;\r\n sDim = Trim( SubSt( sDims, 1, nDimDelimiterIndex - 1 ) );\r\n sDims = Trim( Subst( sDims, nDimDelimiterIndex + Long(pDelim), Long( sDims ) ) );\r\n EndIf;\r\n \r\n # Create subset of dimensions using Wildcard to loop through dimensions in pDim with wildcard\r\n sDimExp = '\"'|sDim|'\"';\r\n sMdxPart = '{TM1FILTERBYPATTERN( EXCEPT( TM1SUBSETALL( [}Dimensions] ) , TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) , \"*:*\") ) ,'| sDimExp | ')}';\r\n IF( sMdx @= ''); \r\n sMdx = sMdxPart; \r\n ELSE;\r\n sMdx = sMdx | ' + ' | sMdxPart;\r\n ENDIF;\r\nEnd;\r\n \r\nIf( SubsetExists( '}Dimensions' , cTempSubDim ) = 1 );\r\n # If a delimited list of dim names includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( '}Dimensions' , cTempSubDim, sMDX );\r\nElse;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSubDim, sMDX, '}Dimensions' , 1 );\r\nEndIf;\r\n \r\n# Loop through dimensions in subset created based on wildcard\r\nnCountDim = SubsetGetSize( '}Dimensions' , cTempSubDim );\r\nWhile( nCountDim >= 1 );\r\n sDim = SubsetGetElementName( '}Dimensions' , cTempSubDim, nCountDim );\r\n # Validate dimension name\r\n If( DimensionExists(sDim) = 0 );\r\n nErrors = 1;\r\n sMessage = Expand( 'Dimension %sDim% does not exist.' );\r\n LogOutput( 'ERROR', Expand( cMsgErrorContent ) );\r\n Else;\r\n If( pLogOutput = 1 );\r\n sMessage = Expand( 'Dimension %sDim% being processed....' );\r\n LogOutput( 'INFO', Expand( cMsgInfoContent ) );\r\n EndIf;\r\n # Loop through hierarchies in pHier\r\n If( Trim( pHier ) @= '' );\r\n ### Use main hierarchy for each dimension if pHier is empty\r\n sHierarchies = sDim;\r\n Else;\r\n sHierarchies = pHier;\r\n EndIf;\r\n nDelimiterIndexA = 1;\r\n sHierDim = '}Dimensions';\r\n sMdxHier = '';\r\n While( nDelimiterIndexA <> 0 );\r\n \r\n nDelimiterIndexA = Scan( pDelim, sHierarchies );\r\n If( nDelimiterIndexA = 0 );\r\n sHierarchy = sHierarchies;\r\n Else;\r\n sHierarchy = Trim( SubSt( sHierarchies, 1, nDelimiterIndexA - 1 ) );\r\n sHierarchies = Trim( Subst( sHierarchies, nDelimiterIndexA + Long(pDelim), Long( sHierarchies ) ) );\r\n EndIf;\r\n \r\n ## If no wildcard specified and current hierarchy does not exist in dimension, create it\r\n If( Scan( '*', sHierarchy ) = 0 & Scan( '?', sHierarchy ) = 0);\r\n If( HierarchyExists( sDim, sHierarchy ) = 0 );\r\n HierarchyCreate( sDim, sHierarchy );\r\n EndIf;\r\n EndIf;\r\n \r\n # Create subset of Hierarchies using Wildcard\r\n If( sHierarchy @= sDim );\r\n sHierExp = '\"'| sHierarchy |'\"';\r\n Else;\r\n sHierExp = '\"'|sDim|':'|sHierarchy|'\"';\r\n EndIf;\r\n sMdxHierPart = '{TM1FILTERBYPATTERN( {TM1SUBSETALL([ ' |sHierDim| '])},'| sHierExp | ')}';\r\n IF( sMdxHier @= ''); \r\n sMdxHier = sMdxHierPart; \r\n ELSE;\r\n sMdxHier = sMdxHier | ' + ' | sMdxHierPart;\r\n ENDIF;\r\n End;\r\n If( Trim( pHier ) @= '*' );\r\n sMdxHier = '{ UNION ( ' | sMdxHier |' , {[}Dimensions].[' | sDim | ']} )}';\r\n EndIf;\r\n \r\n If( SubsetExists( sHierDim, cTempSubHier ) = 1 );\r\n # If a delimited list of attr names includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( sHierDim, cTempSubHier, sMdxHier );\r\n Else;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSubHier, sMdxHier, sHierDim, 1 );\r\n EndIf;\r\n \r\n # Loop through subset of hierarchies created based on wildcard\r\n nCountHier = SubsetGetSize( sHierDim, cTempSubHier );\r\n While( nCountHier >= 1 );\r\n sCurrHier = SubsetGetElementName( sHierDim, cTempSubHier, nCountHier );\r\n sCurrHierName = Subst( sCurrHier, Scan(':', sCurrHier)+1, Long(sCurrHier) );\r\n # Validate hierarchy name in dimension\r\n If( Dimix( sHierDim , sCurrHier ) = 0 );\r\n sMessage = Expand('The %sCurrHier% hierarchy does NOT exist in the %sDim% dimension.');\r\n LogOutput( 'INFO' , Expand( cMsgInfoContent ) );\r\n Else;\r\n If( pLogOutput = 1 );\r\n sMessage = Expand( 'Hierarchy %sCurrHierName% in Dimension %sDim% being processed....' );\r\n LogOutput( 'INFO', Expand( cMsgInfoContent ) );\r\n EndIf;\r\n \r\n # Extract, validate & add elements\r\n sEles = pEle;\r\n nDelimiterIndexB = 1;\r\n While( nDelimiterIndexB <> 0 );\r\n \r\n nDelimiterIndexB = Scan( pDelim, sEles );\r\n If( nDelimiterIndexB = 0 );\r\n sEle = sEles;\r\n Else;\r\n sEle = Trim( SubSt( sEles, 1, nDelimiterIndexB - 1 ) );\r\n sEles = Trim( Subst( sEles, nDelimiterIndexB + Long(pDelim), Long( sEles ) ) );\r\n EndIf;\r\n \r\n # Add elements that don't already exist\r\n If( ElementIndex( sDim, sCurrHierName, sEle ) <> 0 );\r\n If( pLogOutput = 1 );\r\n sMessage = Expand( 'Element ' | sEle | ' already exist in hierarchy ' | sCurrHier);\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n EndIf;\r\n Else;\r\n # Validate Insertion point\r\n IF( pInsertionPoint @<> '' );\r\n If( ElementIndex( sDim, sCurrHierName, pInsertionPoint ) = 0 );\r\n If( pLogOutput = 1 );\r\n sMessage = Expand( 'Element insertion point ' | pInsertionPoint | ' does NOT exist in dimension:hierarchy ' | sCurrHier | '. Using '' '' as insertion point.' );\r\n LogOutput( 'INFO', Expand( cMsgInfoContent ) );\r\n EndIf;\r\n sInsertionPoint = '';\r\n Else;\r\n sInsertionPoint = pInsertionPoint;\r\n EndIf;\r\n Else;\r\n sInsertionPoint = pInsertionPoint;\r\n EndIf;\r\n # Leaves hier\r\n If( sCurrHierName @= 'Leaves' & pEleType @= 'C' );\r\n If( pLogOutput = 1 );\r\n sMessage = Expand( 'Invalid element type for Leaves hierarchy in dimension %sDim%: ' | pEleType );\r\n LogOutput( cMsgErrorLevel, Expand( cMsgInfoContent ) );\r\n EndIf;\r\n Else;\r\n HierarchyElementInsert( sDim, sCurrHierName, sInsertionPoint , sEle , pEleType ); \r\n If( pLogOutput = 1 );\r\n sMessage = Expand( 'Element %sEle% created in hierarchy %sCurrHier% having type ' | pEleType );\r\n LogOutput( 'INFO', Expand( cMsgInfoContent ) );\r\n EndIf;\r\n EndIf;\r\n Endif;\r\n End;\r\n Endif;\r\n \r\n nCountHier = nCountHier - 1;\r\n End;\r\n \r\n EndIf;\r\n \r\n nCountDim = nCountDim - 1;\r\nEnd;\r\n \r\n \r\n### End Prolog ###", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.element.create', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pDim', '', 'pHier', '', 'pEle', '',\r\n 'pEleType', '', 'pInsertionPoint', '',\r\n 'pDelim', '&'\r\n );\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n \r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n \r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n \r\n#Region @DOC\r\n# Description:\r\n# This process will create new element in a dimension Hierarchy. More elements than one will be\r\n# created if pEle is supplied with a delimited list of elements.\r\n \r\n# Note:\r\n# Valid dimension name (pDim) and element list are mandatory, otherwise the process will abort.\r\n \r\n# Caution: When target hierarchy is `Leaves`, no consolidated elements will be created.\r\n#EndRegion @DOC\r\n \r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n \r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSubDim = cThisProcName |'_dims_'| cTimeStamp |'_'| cRandomInt;\r\ncTempSubHier = cThisProcName |'_hiers_'| cTimeStamp |'_'| cRandomInt;\r\ncUserName = TM1User();\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncMsgInfoContent = 'User:%cUserName% Process:%cThisProcName% Message:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pHier:%pHier%, pEle:%pEle%, pEleType:%pEleType%, pInsertionPoint:%pInsertionPoint%, pDelim:%pDelim%.';\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pDelim\": \"&\",\r\n \"pDim\": null,\r\n \"pEle\": null,\r\n \"pEleType\": \"N\",\r\n \"pHier\": \"\",\r\n \"pInsertionPoint\": \"\",\r\n \"pLogOutput\": 0,\r\n \"pStrictErrorHandling\": 0\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pDelim\": '|StringToJson ( pDelim )|',\r\n \"pDim\": '|StringToJson ( pDim )|',\r\n \"pEle\": '|StringToJson ( pEle )|',\r\n \"pEleType\": '|StringToJson ( pEleType )|',\r\n \"pHier\": '|StringToJson ( pHier )|',\r\n \"pInsertionPoint\": '|StringToJson ( pInsertionPoint )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npDelim = JsonToString( JsonGet( pJson, 'pDelim' ) );\r\npDim = JsonToString( JsonGet( pJson, 'pDim' ) );\r\npEle = JsonToString( JsonGet( pJson, 'pEle' ) );\r\npEleType = JsonToString( JsonGet( pJson, 'pEleType' ) );\r\npHier = JsonToString( JsonGet( pJson, 'pHier' ) );\r\npInsertionPoint = JsonToString( JsonGet( pJson, 'pInsertionPoint' ) );\r\n# Numeric Parameters\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n \r\n### Validate Parameters ###\r\nnErrors = 0;\r\n \r\nIf( Scan( '*', pDim ) = 0 & Scan( '?', pDim ) = 0 & Scan( pDelim, pDim ) = 0 & Scan( ':', pDim ) > 0 & pHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pHier = SubSt( pDim, Scan( ':', pDim ) + 1, Long( pDim ) );\r\n pDim = SubSt( pDim, 1, Scan( ':', pDim ) - 1 );\r\nEndIf;\r\n \r\n# Validate dimension\r\nIf( Trim( pDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n \r\n# Validate Hierarchy\r\nIf( Trim( pHier ) @= '' );\r\n ## use same name as Dimension. Since wildcards are allowed this is managed inside the code below\r\nEndIf;\r\n \r\n# Validate element\r\nIf( Trim( pEle ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No element specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n \r\n# Validate element type\r\nIf( pEleType @= '' );\r\n pEleType = 'N';\r\nEndIf;\r\npEleType = Upper( pEleType );\r\nIf( pEleType @<> 'N' & pEleType @<> 'C' & pEleType @<> 'S' );\r\n nErrors = 1;\r\n sMessage = 'Invalid element type: ' | pEleType;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n \r\n# If blank delimiter specified then convert to default\r\nIf( pDelim @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n \r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n \r\n \r\n# Loop through dimensions in pDim\r\nsDims = pDim;\r\nnDimDelimiterIndex = 1;\r\nsMdx = '';\r\n# Get 1st dimension\r\nWhile( nDimDelimiterIndex <> 0 );\r\n # Extract 1st dimension > sDim\r\n nDimDelimiterIndex = Scan( pDelim, sDims );\r\n If( nDimDelimiterIndex = 0 );\r\n sDim = sDims;\r\n Else;\r\n sDim = Trim( SubSt( sDims, 1, nDimDelimiterIndex - 1 ) );\r\n sDims = Trim( Subst( sDims, nDimDelimiterIndex + Long(pDelim), Long( sDims ) ) );\r\n EndIf;\r\n \r\n # Create subset of dimensions using Wildcard to loop through dimensions in pDim with wildcard\r\n sDimExp = '\"'|sDim|'\"';\r\n sMdxPart = '{TM1FILTERBYPATTERN( EXCEPT( TM1SUBSETALL( [}Dimensions] ) , TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) , \"*:*\") ) ,'| sDimExp | ')}';\r\n IF( sMdx @= ''); \r\n sMdx = sMdxPart; \r\n ELSE;\r\n sMdx = sMdx | ' + ' | sMdxPart;\r\n ENDIF;\r\nEnd;\r\n \r\nIf( SubsetExists( '}Dimensions' , cTempSubDim ) = 1 );\r\n # If a delimited list of dim names includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( '}Dimensions' , cTempSubDim, sMDX );\r\nElse;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSubDim, sMDX, '}Dimensions' , 1 );\r\nEndIf;\r\n \r\n# Loop through dimensions in subset created based on wildcard\r\nnCountDim = SubsetGetSize( '}Dimensions' , cTempSubDim );\r\nWhile( nCountDim >= 1 );\r\n sDim = SubsetGetElementName( '}Dimensions' , cTempSubDim, nCountDim );\r\n # Validate dimension name\r\n If( DimensionExists(sDim) = 0 );\r\n nErrors = 1;\r\n sMessage = Expand( 'Dimension %sDim% does not exist.' );\r\n LogOutput( 'ERROR', Expand( cMsgErrorContent ) );\r\n Else;\r\n If( pLogOutput = 1 );\r\n sMessage = Expand( 'Dimension %sDim% being processed....' );\r\n LogOutput( 'INFO', Expand( cMsgInfoContent ) );\r\n EndIf;\r\n # Loop through hierarchies in pHier\r\n If( Trim( pHier ) @= '' );\r\n ### Use main hierarchy for each dimension if pHier is empty\r\n sHierarchies = sDim;\r\n Else;\r\n sHierarchies = pHier;\r\n EndIf;\r\n nDelimiterIndexA = 1;\r\n sHierDim = '}Dimensions';\r\n sMdxHier = '';\r\n While( nDelimiterIndexA <> 0 );\r\n \r\n nDelimiterIndexA = Scan( pDelim, sHierarchies );\r\n If( nDelimiterIndexA = 0 );\r\n sHierarchy = sHierarchies;\r\n Else;\r\n sHierarchy = Trim( SubSt( sHierarchies, 1, nDelimiterIndexA - 1 ) );\r\n sHierarchies = Trim( Subst( sHierarchies, nDelimiterIndexA + Long(pDelim), Long( sHierarchies ) ) );\r\n EndIf;\r\n \r\n ## If no wildcard specified and current hierarchy does not exist in dimension, create it\r\n If( Scan( '*', sHierarchy ) = 0 & Scan( '?', sHierarchy ) = 0);\r\n If( HierarchyExists( sDim, sHierarchy ) = 0 );\r\n HierarchyCreate( sDim, sHierarchy );\r\n EndIf;\r\n EndIf;\r\n \r\n # Create subset of Hierarchies using Wildcard\r\n If( sHierarchy @= sDim );\r\n sHierExp = '\"'| sHierarchy |'\"';\r\n Else;\r\n sHierExp = '\"'|sDim|':'|sHierarchy|'\"';\r\n EndIf;\r\n sMdxHierPart = '{TM1FILTERBYPATTERN( {TM1SUBSETALL([ ' |sHierDim| '])},'| sHierExp | ')}';\r\n IF( sMdxHier @= ''); \r\n sMdxHier = sMdxHierPart; \r\n ELSE;\r\n sMdxHier = sMdxHier | ' + ' | sMdxHierPart;\r\n ENDIF;\r\n End;\r\n If( Trim( pHier ) @= '*' );\r\n sMdxHier = '{ UNION ( ' | sMdxHier |' , {[}Dimensions].[' | sDim | ']} )}';\r\n EndIf;\r\n \r\n If( SubsetExists( sHierDim, cTempSubHier ) = 1 );\r\n # If a delimited list of attr names includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( sHierDim, cTempSubHier, sMdxHier );\r\n Else;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSubHier, sMdxHier, sHierDim, 1 );\r\n EndIf;\r\n \r\n # Loop through subset of hierarchies created based on wildcard\r\n nCountHier = SubsetGetSize( sHierDim, cTempSubHier );\r\n While( nCountHier >= 1 );\r\n sCurrHier = SubsetGetElementName( sHierDim, cTempSubHier, nCountHier );\r\n sCurrHierName = Subst( sCurrHier, Scan(':', sCurrHier)+1, Long(sCurrHier) );\r\n # Validate hierarchy name in dimension\r\n If( Dimix( sHierDim , sCurrHier ) = 0 );\r\n sMessage = Expand('The %sCurrHier% hierarchy does NOT exist in the %sDim% dimension.');\r\n LogOutput( 'INFO' , Expand( cMsgInfoContent ) );\r\n Else;\r\n If( pLogOutput = 1 );\r\n sMessage = Expand( 'Hierarchy %sCurrHierName% in Dimension %sDim% being processed....' );\r\n LogOutput( 'INFO', Expand( cMsgInfoContent ) );\r\n EndIf;\r\n \r\n # Extract, validate & add elements\r\n sEles = pEle;\r\n nDelimiterIndexB = 1;\r\n While( nDelimiterIndexB <> 0 );\r\n \r\n nDelimiterIndexB = Scan( pDelim, sEles );\r\n If( nDelimiterIndexB = 0 );\r\n sEle = sEles;\r\n Else;\r\n sEle = Trim( SubSt( sEles, 1, nDelimiterIndexB - 1 ) );\r\n sEles = Trim( Subst( sEles, nDelimiterIndexB + Long(pDelim), Long( sEles ) ) );\r\n EndIf;\r\n \r\n # Add elements that don't already exist\r\n If( ElementIndex( sDim, sCurrHierName, sEle ) <> 0 );\r\n If( pLogOutput = 1 );\r\n sMessage = Expand( 'Element ' | sEle | ' already exist in hierarchy ' | sCurrHier);\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n EndIf;\r\n Else;\r\n # Validate Insertion point\r\n IF( pInsertionPoint @<> '' );\r\n If( ElementIndex( sDim, sCurrHierName, pInsertionPoint ) = 0 );\r\n If( pLogOutput = 1 );\r\n sMessage = Expand( 'Element insertion point ' | pInsertionPoint | ' does NOT exist in dimension:hierarchy ' | sCurrHier | '. Using '' '' as insertion point.' );\r\n LogOutput( 'INFO', Expand( cMsgInfoContent ) );\r\n EndIf;\r\n sInsertionPoint = '';\r\n Else;\r\n sInsertionPoint = pInsertionPoint;\r\n EndIf;\r\n Else;\r\n sInsertionPoint = pInsertionPoint;\r\n EndIf;\r\n # Leaves hier\r\n If( sCurrHierName @= 'Leaves' & pEleType @= 'C' );\r\n If( pLogOutput = 1 );\r\n sMessage = Expand( 'Invalid element type for Leaves hierarchy in dimension %sDim%: ' | pEleType );\r\n LogOutput( cMsgErrorLevel, Expand( cMsgInfoContent ) );\r\n EndIf;\r\n Else;\r\n HierarchyElementInsert( sDim, sCurrHierName, sInsertionPoint , sEle , pEleType ); \r\n If( pLogOutput = 1 );\r\n sMessage = Expand( 'Element %sEle% created in hierarchy %sCurrHier% having type ' | pEleType );\r\n LogOutput( 'INFO', Expand( cMsgInfoContent ) );\r\n EndIf;\r\n EndIf;\r\n Endif;\r\n End;\r\n Endif;\r\n \r\n nCountHier = nCountHier - 1;\r\n End;\r\n \r\n EndIf;\r\n \r\n nCountDim = nCountDim - 1;\r\nEnd;\r\n \r\n \r\n### End Prolog ###", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% inserted element(s) %pEle% with type %pEleType% into %pDim%:%pHier%.' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n\r\n### End Epilog ###", @@ -10,53 +10,59 @@ "Type": "None" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pDim", - "Prompt": "REQUIRED: dimension name, accepts wildcards (if = *, then all the dimensions)", + "Prompt": "REQUIRED: Delimited list of dimensions", "Value": "", "Type": "String" }, { "Name": "pHier", - "Prompt": "OPTIONAL: hierarchy (default value same named hierarchy as dimension), accepts wildcards (if = *, then all hierarchies)", + "Prompt": "OPTIONAL: Hierarchy name (Default = pDim)", "Value": "", "Type": "String" }, { "Name": "pEle", - "Prompt": "REQUIRED: element name, accepts delimited list", + "Prompt": "REQUIRED: Delimited list of elements", "Value": "", "Type": "String" }, { "Name": "pEleType", - "Prompt": "OPTIONAL: element type N S C (default value N)", - "Value": "", + "Prompt": "OPTIONAL: Element type ('C', 'S', or 'N'. Default = 'N')", + "Value": "N", "Type": "String" }, { "Name": "pInsertionPoint", - "Prompt": "OPTIONAL: insertion point (default value blank)", + "Prompt": "OPTIONAL: Insert position", "Value": "", "Type": "String" }, { "Name": "pDelim", - "Prompt": "OPTIONAL: delimiter character for element list. (default value if blank = '&')", + "Prompt": "OPTIONAL: Delimiter for list parameters (Default = '&')", "Value": "&", "Type": "String" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [], diff --git a/bedrock_processes_json/}bedrock.hier.element.delete.json b/bedrock_processes_json/}bedrock.hier.element.delete.json index a1d86db..175800e 100644 --- a/bedrock_processes_json/}bedrock.hier.element.delete.json +++ b/bedrock_processes_json/}bedrock.hier.element.delete.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.hier.element.delete", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.element.delete', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pDim', '', 'pHier', '', 'pEle', '',\r\n \t'pDelim', '&'\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will delete specified or all elements from a dimension Hierarchy. Elements might be\r\n# specified as a delimited list of elements. Each member in the list might be specified exactly or\r\n# by a wildcard pattern. Wildcards \"\\*\" and \"?\" are accepted.\r\n#\r\n# Caution: When pEle is set to \\*, __all__ elements in pHier will be deleted!\r\n#EndRegion @DOC\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSubDim = cThisProcName |'_dims_'| cTimeStamp |'_'| cRandomInt;\r\ncTempSubHier = cThisProcName |'_hiers_'| cTimeStamp |'_'| cRandomInt;\r\ncTempSubEle = cThisProcName |'_eles_'| cTimeStamp |'_'| cRandomInt;\r\ncUserName = TM1User();\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgInfoLevel = 'INFO';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncMsgInfoContent = 'User:%cUserName% Process:%cThisProcName% Message:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pHier:%pHier%, pEle:%pEle%, pDelim:%pDelim%.'; \r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\nIf( Scan( '*', pDim ) = 0 & Scan( '?', pDim ) = 0 & Scan( pDelim, pDim ) = 0 & Scan( ':', pDim ) > 0 & pHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pHier = SubSt( pDim, Scan( ':', pDim ) + 1, Long( pDim ) );\r\n pDim = SubSt( pDim, 1, Scan( ':', pDim ) - 1 );\r\nEndIf;\r\n\r\n# Validate Dimension\r\nIf( Trim( pDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# If blank delimiter specified then convert to default\r\nIf( pDelim @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\n# Validate Hierarchy\r\nIf( Trim( pHier ) @= '' );\r\n ## use same name as Dimension. Since wildcards are allowed this is managed inside the code below\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n# Loop through dimensions in pDim\r\nsDims = pDim;\r\nnDimDelimiterIndex = 1;\r\nsMdx = '';\r\n# Get 1st dimension\r\nWhile( nDimDelimiterIndex <> 0 );\r\n # Extract 1st dimension > sDim\r\n nDimDelimiterIndex = Scan( pDelim, sDims );\r\n If( nDimDelimiterIndex = 0 );\r\n sDim = sDims;\r\n Else;\r\n sDim = Trim( SubSt( sDims, 1, nDimDelimiterIndex - 1 ) );\r\n sDims = Trim( Subst( sDims, nDimDelimiterIndex + Long(pDelim), Long( sDims ) ) );\r\n EndIf;\r\n \r\n # Create subset of dimensions using Wildcard to loop through dimensions in pDim with wildcard\r\n sDimExp = '\"'|sDim|'\"';\r\n sMdxPart = '{TM1FILTERBYPATTERN( EXCEPT( TM1SUBSETALL( [}Dimensions] ) , TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) , \"*:*\") ) ,'| sDimExp | ')}';\r\n IF( sMdx @= ''); \r\n sMdx = sMdxPart; \r\n ELSE;\r\n sMdx = sMdx | ' + ' | sMdxPart;\r\n ENDIF;\r\nEnd;\r\n\r\nIf( SubsetExists( '}Dimensions' , cTempSubDim ) = 1 );\r\n # If a delimited list of dim names includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( '}Dimensions' , cTempSubDim, sMDX );\r\nElse;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSubDim, sMDX, '}Dimensions' , 1 );\r\nEndIf;\r\n\r\n# Loop through dimensions in subset created based on wildcard\r\nnCountDim = SubsetGetSize( '}Dimensions' , cTempSubDim );\r\nWhile( nCountDim >= 1 );\r\n sDim = SubsetGetElementName( '}Dimensions' , cTempSubDim, nCountDim );\r\n # Validate dimension name\r\n If( DimensionExists(sDim) = 0 );\r\n nErrors = 1;\r\n sMessage = Expand( 'Dimension %sDim% does not exist.' );\r\n LogOutput( 'ERROR', Expand( cMsgErrorContent ) );\r\n Else;\r\n If( pLogOutput = 1 );\r\n sMessage = Expand( 'Dimension %sDim% being processed....' );\r\n LogOutput( 'INFO', Expand( cMsgInfoContent ) );\r\n EndIf;\r\n # Loop through hierarchies in pHier\r\n If( Trim( pHier ) @= '' );\r\n ### Use main hierarchy for each dimension if pHier is empty\r\n sHierarchies = sDim;\r\n Else;\r\n sHierarchies = pHier;\r\n EndIf;\r\n nDelimiterIndexA = 1;\r\n sHierDim = '}Dimensions' ;\r\n sMdxHier = '';\r\n While( nDelimiterIndexA <> 0 );\r\n\r\n nDelimiterIndexA = Scan( pDelim, sHierarchies );\r\n If( nDelimiterIndexA = 0 );\r\n sHierarchy = sHierarchies;\r\n Else;\r\n sHierarchy = Trim( SubSt( sHierarchies, 1, nDelimiterIndexA - 1 ) );\r\n sHierarchies = Trim( Subst( sHierarchies, nDelimiterIndexA + Long(pDelim), Long( sHierarchies ) ) );\r\n EndIf;\r\n\r\n # Create subset of Hierarchies using Wildcard\r\n If( sHierarchy @= sDim );\r\n sHierExp = '\"'|sDim|'\"';\r\n Else;\r\n sHierExp = '\"'|sDim|':'|sHierarchy|'\"';\r\n EndIf;\r\n sMdxHierPart = '{TM1FILTERBYPATTERN( {TM1SUBSETALL([ ' |sHierDim| '])},'| sHierExp | ')}';\r\n IF( sMdxHier @= ''); \r\n sMdxHier = sMdxHierPart; \r\n ELSE;\r\n sMdxHier = sMdxHier | ' + ' | sMdxHierPart;\r\n ENDIF;\r\n End;\r\n If( Trim( pHier ) @= '*' );\r\n sMdxHier = '{ UNION ( ' | sMdxHier |' , {[}Dimensions].[' | sDim | ']} )}';\r\n EndIf;\r\n\r\n If( SubsetExists( sHierDim, cTempSubHier ) = 1 );\r\n # If a delimited list of hier names includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( sHierDim, cTempSubHier, sMdxHier );\r\n Else;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSubHier, sMdxHier, sHierDim, 1 );\r\n EndIf;\r\n \r\n # Loop through subset of hierarchies created based on wildcard\r\n nCountHier = SubsetGetSize( sHierDim, cTempSubHier );\r\n While( nCountHier >= 1 );\r\n sCurrHier = SubsetGetElementName( sHierDim, cTempSubHier, nCountHier );\r\n sCurrHierName = Subst( sCurrHier, Scan(':', sCurrHier)+1, Long(sCurrHier) );\r\n # Validate hierarchy name in sHierDim\r\n If( Dimix( sHierDim , sCurrHier ) = 0 );\r\n sMessage = Expand('The %sCurrHier% hierarchy does NOT exist in the %sDim% dimension.');\r\n LogOutput( 'INFO' , Expand( cMsgInfoContent ) );\r\n Else;\r\n If( pLogOutput = 1 );\r\n sMessage = Expand( 'Hierarchy %sCurrHierName% in Dimension %sDim% being processed....' );\r\n LogOutput( 'INFO', Expand( cMsgInfoContent ) );\r\n EndIf;\r\n # Loop through hierarchy elements in pEle\r\n sEles = pEle;\r\n nDelimiterIndexB = 1;\r\n While( nDelimiterIndexB <> 0 );\r\n \r\n nDelimiterIndexB = Scan( pDelim, sEles );\r\n If( nDelimiterIndexB = 0 );\r\n sEle = sEles;\r\n Else;\r\n sEle = Trim( SubSt( sEles, 1, nDelimiterIndexB - 1 ) );\r\n sEles = Trim( Subst( sEles, nDelimiterIndexB + Long(pDelim), Long( sEles ) ) );\r\n EndIf;\r\n \r\n # Check if a wildcard has been used to specify the Element name.\r\n # If it hasn't then just delete the Element if it exists\r\n If(sEle @= '*');\r\n HierarchyDeleteAllElements(sDim, sCurrHierName);\r\n ElseIf( Scan( '*', sEle ) = 0 & Scan( '?', sEle ) = 0);\r\n If( HierarchyElementExists( sDim,sCurrHierName, sEle ) = 1 );\r\n HierarchyElementDelete( sDim, sCurrHierName,sEle );\r\n If( sCurrHierName @= 'Leaves' );\r\n sMessage = Expand('Element %sEle% deleted from LEAVES hierarchy in dimension %sDim%. This action removes the element from all hierarchies!');\r\n LogOutput( cMsgInfoLevel, Expand( cMsgInfoContent ) );\r\n ElseIf( pLogOutput = 1 );\r\n sMessage = Expand( 'Element %sEle% deleted from hierarchy %sCurrHierName% in dimension %sDim%.' );\r\n LogOutput( cMsgInfoLevel, Expand( cMsgInfoContent ) );\r\n EndIf;\r\n Else;\r\n If( pLogOutput >= 1 );\r\n sMessage = Expand('The Hierarchy %sCurrHier% does not contain element %sEle%.');\r\n LogOutput( cMsgInfoLevel, Expand( cMsgInfoContent ) );\r\n EndIf;\r\n Endif;\r\n Else;\r\n # Wildcard search string\r\n sEle = '\"'|sEle|'\"';\r\n sProc = '}bedrock.hier.sub.create.bymdx';\r\n sMdxEle = '{TM1FILTERBYPATTERN( {TM1SUBSETALL([ ' | sCurrHier |' ])},'| sEle| ')}';\r\n\r\n If( HierarchySubsetExists( sDim, sCurrHierName, cTempSubEle ) = 1 );\r\n # If a delimited list of ele names includes wildcards then we may have to re-use the subset multiple times\r\n HierarchySubsetMDXSet( sDim, sCurrHierName, cTempSubEle, sMDXEle );\r\n Else;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSubEle, sMDXEle, sCurrHier, 1 );\r\n EndIf;\r\n\r\n # Loop through subset of hierarchy elements created based on wildcard\r\n nCountElems = HierarchySubsetGetSize(sDim, sCurrHierName, cTempSubEle);\r\n While( nCountElems >= 1 );\r\n sElement = HierarchySubsetGetElementName(sDim, sCurrHierName, cTempSubEle, nCountElems);\r\n HierarchyElementDelete( sDim, sCurrHierName,sElement );\r\n If( pLogOutput = 1 );\r\n sMessage = Expand( 'Element %sElement% deleted from hierarchy %sCurrHierName% in dimension %sDim%.' );\r\n LogOutput( cMsgInfoLevel, Expand( cMsgInfoContent ) );\r\n EndIf;\r\n nCountElems = nCountElems - 1;\r\n End;\r\n EndIf;\r\n \r\n End;\r\n Endif;\r\n \r\n nCountHier = nCountHier - 1;\r\n End;\r\n \r\n EndIf;\r\n \r\n nCountDim = nCountDim - 1;\r\nEnd;\r\n\r\n\r\n\r\n### End Prolog ###", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.element.delete', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pDim', '', 'pHier', '', 'pEle', '',\r\n \t'pDelim', '&'\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will delete specified or all elements from a dimension Hierarchy. Elements might be\r\n# specified as a delimited list of elements. Each member in the list might be specified exactly or\r\n# by a wildcard pattern. Wildcards \"\\*\" and \"?\" are accepted.\r\n#\r\n# Caution: When pEle is set to \\*, __all__ elements in pHier will be deleted!\r\n#EndRegion @DOC\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSubDim = cThisProcName |'_dims_'| cTimeStamp |'_'| cRandomInt;\r\ncTempSubHier = cThisProcName |'_hiers_'| cTimeStamp |'_'| cRandomInt;\r\ncTempSubEle = cThisProcName |'_eles_'| cTimeStamp |'_'| cRandomInt;\r\ncUserName = TM1User();\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgInfoLevel = 'INFO';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncMsgInfoContent = 'User:%cUserName% Process:%cThisProcName% Message:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pHier:%pHier%, pEle:%pEle%, pDelim:%pDelim%.';\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pDelim\": \"&\",\r\n \"pDim\": null,\r\n \"pEle\": \"*\",\r\n \"pHier\": \"\",\r\n \"pLogOutput\": 0,\r\n \"pStrictErrorHandling\": 0\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pDelim\": '|StringToJson ( pDelim )|',\r\n \"pDim\": '|StringToJson ( pDim )|',\r\n \"pEle\": '|StringToJson ( pEle )|',\r\n \"pHier\": '|StringToJson ( pHier )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npDelim = JsonToString( JsonGet( pJson, 'pDelim' ) );\r\npDim = JsonToString( JsonGet( pJson, 'pDim' ) );\r\npEle = JsonToString( JsonGet( pJson, 'pEle' ) );\r\npHier = JsonToString( JsonGet( pJson, 'pHier' ) );\r\n# Numeric Parameters\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\nIf( Scan( '*', pDim ) = 0 & Scan( '?', pDim ) = 0 & Scan( pDelim, pDim ) = 0 & Scan( ':', pDim ) > 0 & pHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pHier = SubSt( pDim, Scan( ':', pDim ) + 1, Long( pDim ) );\r\n pDim = SubSt( pDim, 1, Scan( ':', pDim ) - 1 );\r\nEndIf;\r\n\r\n# Validate Dimension\r\nIf( Trim( pDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# If blank delimiter specified then convert to default\r\nIf( pDelim @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\n# Validate Hierarchy\r\nIf( Trim( pHier ) @= '' );\r\n ## use same name as Dimension. Since wildcards are allowed this is managed inside the code below\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n# Loop through dimensions in pDim\r\nsDims = pDim;\r\nnDimDelimiterIndex = 1;\r\nsMdx = '';\r\n# Get 1st dimension\r\nWhile( nDimDelimiterIndex <> 0 );\r\n # Extract 1st dimension > sDim\r\n nDimDelimiterIndex = Scan( pDelim, sDims );\r\n If( nDimDelimiterIndex = 0 );\r\n sDim = sDims;\r\n Else;\r\n sDim = Trim( SubSt( sDims, 1, nDimDelimiterIndex - 1 ) );\r\n sDims = Trim( Subst( sDims, nDimDelimiterIndex + Long(pDelim), Long( sDims ) ) );\r\n EndIf;\r\n \r\n # Create subset of dimensions using Wildcard to loop through dimensions in pDim with wildcard\r\n sDimExp = '\"'|sDim|'\"';\r\n sMdxPart = '{TM1FILTERBYPATTERN( EXCEPT( TM1SUBSETALL( [}Dimensions] ) , TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) , \"*:*\") ) ,'| sDimExp | ')}';\r\n IF( sMdx @= ''); \r\n sMdx = sMdxPart; \r\n ELSE;\r\n sMdx = sMdx | ' + ' | sMdxPart;\r\n ENDIF;\r\nEnd;\r\n\r\nIf( SubsetExists( '}Dimensions' , cTempSubDim ) = 1 );\r\n # If a delimited list of dim names includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( '}Dimensions' , cTempSubDim, sMDX );\r\nElse;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSubDim, sMDX, '}Dimensions' , 1 );\r\nEndIf;\r\n\r\n# Loop through dimensions in subset created based on wildcard\r\nnCountDim = SubsetGetSize( '}Dimensions' , cTempSubDim );\r\nWhile( nCountDim >= 1 );\r\n sDim = SubsetGetElementName( '}Dimensions' , cTempSubDim, nCountDim );\r\n # Validate dimension name\r\n If( DimensionExists(sDim) = 0 );\r\n nErrors = 1;\r\n sMessage = Expand( 'Dimension %sDim% does not exist.' );\r\n LogOutput( 'ERROR', Expand( cMsgErrorContent ) );\r\n Else;\r\n If( pLogOutput = 1 );\r\n sMessage = Expand( 'Dimension %sDim% being processed....' );\r\n LogOutput( 'INFO', Expand( cMsgInfoContent ) );\r\n EndIf;\r\n # Loop through hierarchies in pHier\r\n If( Trim( pHier ) @= '' );\r\n ### Use main hierarchy for each dimension if pHier is empty\r\n sHierarchies = sDim;\r\n Else;\r\n sHierarchies = pHier;\r\n EndIf;\r\n nDelimiterIndexA = 1;\r\n sHierDim = '}Dimensions' ;\r\n sMdxHier = '';\r\n While( nDelimiterIndexA <> 0 );\r\n\r\n nDelimiterIndexA = Scan( pDelim, sHierarchies );\r\n If( nDelimiterIndexA = 0 );\r\n sHierarchy = sHierarchies;\r\n Else;\r\n sHierarchy = Trim( SubSt( sHierarchies, 1, nDelimiterIndexA - 1 ) );\r\n sHierarchies = Trim( Subst( sHierarchies, nDelimiterIndexA + Long(pDelim), Long( sHierarchies ) ) );\r\n EndIf;\r\n\r\n # Create subset of Hierarchies using Wildcard\r\n If( sHierarchy @= sDim );\r\n sHierExp = '\"'|sDim|'\"';\r\n Else;\r\n sHierExp = '\"'|sDim|':'|sHierarchy|'\"';\r\n EndIf;\r\n sMdxHierPart = '{TM1FILTERBYPATTERN( {TM1SUBSETALL([ ' |sHierDim| '])},'| sHierExp | ')}';\r\n IF( sMdxHier @= ''); \r\n sMdxHier = sMdxHierPart; \r\n ELSE;\r\n sMdxHier = sMdxHier | ' + ' | sMdxHierPart;\r\n ENDIF;\r\n End;\r\n If( Trim( pHier ) @= '*' );\r\n sMdxHier = '{ UNION ( ' | sMdxHier |' , {[}Dimensions].[' | sDim | ']} )}';\r\n EndIf;\r\n\r\n If( SubsetExists( sHierDim, cTempSubHier ) = 1 );\r\n # If a delimited list of hier names includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( sHierDim, cTempSubHier, sMdxHier );\r\n Else;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSubHier, sMdxHier, sHierDim, 1 );\r\n EndIf;\r\n \r\n # Loop through subset of hierarchies created based on wildcard\r\n nCountHier = SubsetGetSize( sHierDim, cTempSubHier );\r\n While( nCountHier >= 1 );\r\n sCurrHier = SubsetGetElementName( sHierDim, cTempSubHier, nCountHier );\r\n sCurrHierName = Subst( sCurrHier, Scan(':', sCurrHier)+1, Long(sCurrHier) );\r\n # Validate hierarchy name in sHierDim\r\n If( Dimix( sHierDim , sCurrHier ) = 0 );\r\n sMessage = Expand('The %sCurrHier% hierarchy does NOT exist in the %sDim% dimension.');\r\n LogOutput( 'INFO' , Expand( cMsgInfoContent ) );\r\n Else;\r\n If( pLogOutput = 1 );\r\n sMessage = Expand( 'Hierarchy %sCurrHierName% in Dimension %sDim% being processed....' );\r\n LogOutput( 'INFO', Expand( cMsgInfoContent ) );\r\n EndIf;\r\n # Loop through hierarchy elements in pEle\r\n sEles = pEle;\r\n nDelimiterIndexB = 1;\r\n While( nDelimiterIndexB <> 0 );\r\n \r\n nDelimiterIndexB = Scan( pDelim, sEles );\r\n If( nDelimiterIndexB = 0 );\r\n sEle = sEles;\r\n Else;\r\n sEle = Trim( SubSt( sEles, 1, nDelimiterIndexB - 1 ) );\r\n sEles = Trim( Subst( sEles, nDelimiterIndexB + Long(pDelim), Long( sEles ) ) );\r\n EndIf;\r\n \r\n # Check if a wildcard has been used to specify the Element name.\r\n # If it hasn't then just delete the Element if it exists\r\n If(sEle @= '*');\r\n HierarchyDeleteAllElements(sDim, sCurrHierName);\r\n ElseIf( Scan( '*', sEle ) = 0 & Scan( '?', sEle ) = 0);\r\n If( HierarchyElementExists( sDim,sCurrHierName, sEle ) = 1 );\r\n HierarchyElementDelete( sDim, sCurrHierName,sEle );\r\n If( sCurrHierName @= 'Leaves' );\r\n sMessage = Expand('Element %sEle% deleted from LEAVES hierarchy in dimension %sDim%. This action removes the element from all hierarchies!');\r\n LogOutput( cMsgInfoLevel, Expand( cMsgInfoContent ) );\r\n ElseIf( pLogOutput = 1 );\r\n sMessage = Expand( 'Element %sEle% deleted from hierarchy %sCurrHierName% in dimension %sDim%.' );\r\n LogOutput( cMsgInfoLevel, Expand( cMsgInfoContent ) );\r\n EndIf;\r\n Else;\r\n If( pLogOutput >= 1 );\r\n sMessage = Expand('The Hierarchy %sCurrHier% does not contain element %sEle%.');\r\n LogOutput( cMsgInfoLevel, Expand( cMsgInfoContent ) );\r\n EndIf;\r\n Endif;\r\n Else;\r\n # Wildcard search string\r\n sEle = '\"'|sEle|'\"';\r\n sProc = '}bedrock.hier.sub.create.bymdx';\r\n sMdxEle = '{TM1FILTERBYPATTERN( {TM1SUBSETALL([ ' | sCurrHier |' ])},'| sEle| ')}';\r\n\r\n If( HierarchySubsetExists( sDim, sCurrHierName, cTempSubEle ) = 1 );\r\n # If a delimited list of ele names includes wildcards then we may have to re-use the subset multiple times\r\n HierarchySubsetMDXSet( sDim, sCurrHierName, cTempSubEle, sMDXEle );\r\n Else;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSubEle, sMDXEle, sCurrHier, 1 );\r\n EndIf;\r\n\r\n # Loop through subset of hierarchy elements created based on wildcard\r\n nCountElems = HierarchySubsetGetSize(sDim, sCurrHierName, cTempSubEle);\r\n While( nCountElems >= 1 );\r\n sElement = HierarchySubsetGetElementName(sDim, sCurrHierName, cTempSubEle, nCountElems);\r\n HierarchyElementDelete( sDim, sCurrHierName,sElement );\r\n If( pLogOutput = 1 );\r\n sMessage = Expand( 'Element %sElement% deleted from hierarchy %sCurrHierName% in dimension %sDim%.' );\r\n LogOutput( cMsgInfoLevel, Expand( cMsgInfoContent ) );\r\n EndIf;\r\n nCountElems = nCountElems - 1;\r\n End;\r\n EndIf;\r\n \r\n End;\r\n Endif;\r\n \r\n nCountHier = nCountHier - 1;\r\n End;\r\n \r\n EndIf;\r\n \r\n nCountDim = nCountDim - 1;\r\nEnd;\r\n\r\n\r\n\r\n### End Prolog ###", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully deleted the appropriate elements in hierarchy %pDim%:%pHier%.' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n### End Epilog ###", @@ -10,41 +10,47 @@ "Type": "None" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pDim", - "Prompt": "REQUIRED: dimension name, accepts wildcards (if = *, then all the dimensions)", + "Prompt": "REQUIRED: Delimited list of dimensions", "Value": "", "Type": "String" }, { "Name": "pHier", - "Prompt": "OPTIONAL: hierarchy name (if blank then same named hierarchy as dimension is assumed), accepts wildcards (if = *, then all hierarchies)", + "Prompt": "OPTIONAL: Hierarchy name (Default = pDim)", "Value": "", "Type": "String" }, { "Name": "pEle", - "Prompt": "OPTIONAL: filter on elements (delimiter separated list of elements, accepts wildcards (if = *, then all the elements in hierarchy get deleted))", - "Value": "", + "Prompt": "OPTIONAL: Delimited list of elements (Default = '*')", + "Value": "*", "Type": "String" }, { "Name": "pDelim", - "Prompt": "OPTIONAL: delimiter character for element list (default value if blank = '&')", + "Prompt": "OPTIONAL: Delimiter for list parameters (Default = '&')", "Value": "&", "Type": "String" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [], diff --git a/bedrock_processes_json/}bedrock.hier.element.move.json b/bedrock_processes_json/}bedrock.hier.element.move.json index 31d3d65..1f79338 100644 --- a/bedrock_processes_json/}bedrock.hier.element.move.json +++ b/bedrock_processes_json/}bedrock.hier.element.move.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.hier.element.move", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.element.move', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pDim', '', 'pHier', '', 'pEle', '',\r\n \t'pTgtConsol', '', 'pMode', 'Add', 'pWeight', 1\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will Add or Remove Element from a Consolidation in a Hierarchy.\r\n\r\n# Note:\r\n# Valid dimension name (pDim), consolidated element name (pTgtConsol) and element name (pEle)\r\n# otherwise the process will abort. Mode can be either Add to add or Remove to remove the element\r\n# from a consolidation. \r\n\r\n# Caution: Target hierarchy cannot be `Leaves`.\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent= 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pHier:%pHier%, pEle:%pEle%, pTgtConsol:%pTgtConsol%, pMode:%pMode%, pWeight:%pWeight%.';\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\nIf( Scan( ':', pDim ) > 0 & pHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pHier = SubSt( pDim, Scan( ':', pDim ) + 1, Long( pDim ) );\r\n pDim = SubSt( pDim, 1, Scan( ':', pDim ) - 1 );\r\nEndIf;\r\n\r\n# Validate dimension\r\nIf( Trim( pDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( DimensionExists( pDim ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Dimension ' | pDim | ' does not exist on server.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate Hierarchy\r\nIf( Trim( pHier ) @= '' );\r\n sHier = Trim( pDim );\r\nElse;\r\n sHier = Trim( pHier );\r\nEndIf;\r\nIf( sHier @= 'Leaves' );\r\n nErrors = 1;\r\n sMessage = 'Invalid Hierarchy: ' | pDim |':'|sHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( HierarchyExists( pDim, sHier ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'The Hierachy ' | sHier | ' does not exist in dimension ' | pDim;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate Element\r\nIf( Trim( pEle ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No element specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( ElementIndex ( pDim, sHier, pEle ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Element: ' | pEle | ' does not exist in dimension: ' | pDim|':'| sHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate target consol\r\nIf( ElementIndex ( pDim, sHier, pTgtConsol ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Consolidated Element: ' | pTgtConsol | ' does not exist in dimension: ' | pDim|':'| sHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( ElementType( pDim, sHier, pTgtConsol ) @<> 'C' );\r\n nErrors = 1;\r\n sMessage = 'Target Consolidation: ' | pTgtConsol | ' has incorrect element type.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\nIf( ElementIsAncestor( pDim, sHier, pEle, pTgtConsol ) = 1 );\r\n nErrors = 1;\r\n sMessage = 'Cannot add element: ' | pEle | ' to consolidation: ' | pTgtConsol | ' due to circular reference.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate action\r\nIf( pMode @<> 'Add' & pMode @<> 'Remove' );\r\n nErrors = 1;\r\n sMessage = 'Invalid action: ' | pMode | '. Valid actions are Add or Remove';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n\r\n### Insert Element into consolidation ###\r\nIf( pMode @= 'Add' );\r\n HierarchyElementComponentAdd( pDim, sHier, pTgtConsol, pEle, pWeight );\r\nEndIf;\r\n\r\n\r\n### Remove Element from consolidation ###\r\nIf( pMode @= 'Remove' );\r\n # Check that element is actually a child of target consol\r\n If( ElementIsComponent ( pDim, sHier, pEle, pTgtConsol ) = 1 );\r\n HierarchyElementComponentDelete( pDim, sHier, pTgtConsol, pEle );\r\n Else;\r\n nErrors = 1;\r\n sMessage = 'Element: ' | pEle | ' is not a child of consolidation: ' | pTgtConsol;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n EndIf;\r\nEndIf;\r\n\r\n\r\n### End Prolog ###", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.element.move', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pDim', '', 'pHier', '', 'pEle', '',\r\n \t'pTgtConsol', '', 'pMode', 'Add', 'pWeight', 1\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will Add or Remove Element from a Consolidation in a Hierarchy.\r\n\r\n# Note:\r\n# Valid dimension name (pDim), consolidated element name (pTgtConsol) and element name (pEle)\r\n# otherwise the process will abort. Mode can be either Add to add or Remove to remove the element\r\n# from a consolidation. \r\n\r\n# Caution: Target hierarchy cannot be `Leaves`.\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent= 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pHier:%pHier%, pEle:%pEle%, pTgtConsol:%pTgtConsol%, pMode:%pMode%, pWeight:%pWeight%.';\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pDim\": null,\r\n \"pEle\": null,\r\n \"pHier\": \"\",\r\n \"pMode\": null,\r\n \"pTgtConsol\": \"\",\r\n \"pLogOutput\": 0,\r\n \"pStrictErrorHandling\": 0,\r\n \"pWeight\": 1\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pDim\": '|StringToJson ( pDim )|',\r\n \"pEle\": '|StringToJson ( pEle )|',\r\n \"pHier\": '|StringToJson ( pHier )|',\r\n \"pMode\": '|StringToJson ( pMode )|',\r\n \"pTgtConsol\": '|StringToJson ( pTgtConsol )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|',\r\n \"pWeight\": '|NumberToString( pWeight )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npDim = JsonToString( JsonGet( pJson, 'pDim' ) );\r\npEle = JsonToString( JsonGet( pJson, 'pEle' ) );\r\npHier = JsonToString( JsonGet( pJson, 'pHier' ) );\r\npMode = JsonToString( JsonGet( pJson, 'pMode' ) );\r\npTgtConsol = JsonToString( JsonGet( pJson, 'pTgtConsol' ) );\r\n# Numeric Parameters\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\npWeight = StringToNumber( JsonToString( JsonGet( pJson, 'pWeight' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\nIf( Scan( ':', pDim ) > 0 & pHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pHier = SubSt( pDim, Scan( ':', pDim ) + 1, Long( pDim ) );\r\n pDim = SubSt( pDim, 1, Scan( ':', pDim ) - 1 );\r\nEndIf;\r\n\r\n# Validate dimension\r\nIf( Trim( pDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( DimensionExists( pDim ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Dimension ' | pDim | ' does not exist on server.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate Hierarchy\r\nIf( Trim( pHier ) @= '' );\r\n sHier = Trim( pDim );\r\nElse;\r\n sHier = Trim( pHier );\r\nEndIf;\r\nIf( sHier @= 'Leaves' );\r\n nErrors = 1;\r\n sMessage = 'Invalid Hierarchy: ' | pDim |':'|sHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( HierarchyExists( pDim, sHier ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'The Hierachy ' | sHier | ' does not exist in dimension ' | pDim;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate Element\r\nIf( Trim( pEle ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No element specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( ElementIndex ( pDim, sHier, pEle ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Element: ' | pEle | ' does not exist in dimension: ' | pDim|':'| sHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate target consol\r\nIf( ElementIndex ( pDim, sHier, pTgtConsol ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Consolidated Element: ' | pTgtConsol | ' does not exist in dimension: ' | pDim|':'| sHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( ElementType( pDim, sHier, pTgtConsol ) @<> 'C' );\r\n nErrors = 1;\r\n sMessage = 'Target Consolidation: ' | pTgtConsol | ' has incorrect element type.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\nIf( ElementIsAncestor( pDim, sHier, pEle, pTgtConsol ) = 1 );\r\n nErrors = 1;\r\n sMessage = 'Cannot add element: ' | pEle | ' to consolidation: ' | pTgtConsol | ' due to circular reference.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate action\r\nIf( pMode @<> 'Add' & pMode @<> 'Remove' );\r\n nErrors = 1;\r\n sMessage = 'Invalid action: ' | pMode | '. Valid actions are Add or Remove';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n\r\n### Insert Element into consolidation ###\r\nIf( pMode @= 'Add' );\r\n HierarchyElementComponentAdd( pDim, sHier, pTgtConsol, pEle, pWeight );\r\nEndIf;\r\n\r\n\r\n### Remove Element from consolidation ###\r\nIf( pMode @= 'Remove' );\r\n # Check that element is actually a child of target consol\r\n If( ElementIsComponent ( pDim, sHier, pEle, pTgtConsol ) = 1 );\r\n HierarchyElementComponentDelete( pDim, sHier, pTgtConsol, pEle );\r\n Else;\r\n nErrors = 1;\r\n sMessage = 'Element: ' | pEle | ' is not a child of consolidation: ' | pTgtConsol;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n EndIf;\r\nEndIf;\r\n\r\n\r\n### End Prolog ###", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n### If errors occurred terminate process with a major error status ###\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 major error and consequently aborted. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% aborted. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nEndIf;\r\n\r\n### Return Code\r\nsProcessAction = Expand( 'Process:%cThisProcName% successfully %pMode%ed element %pEle% to/from %pTgtConsol% in the %pDim%:%pHier% dimension:hierarchy.' );\r\nsProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\nnProcessReturnCode = 1;\r\nIf( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\nEndIf;\r\n\r\n\r\n### End Epilog ###", @@ -10,53 +10,59 @@ "Type": "None" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pDim", - "Prompt": "REQUIRED: Dimension Name", + "Prompt": "REQUIRED: Delimited list of dimensions", "Value": "", "Type": "String" }, { "Name": "pHier", - "Prompt": "OPTIONAL: Hierarchy Name", + "Prompt": "OPTIONAL: Hierarchy name (Default = pDim)", "Value": "", "Type": "String" }, { "Name": "pEle", - "Prompt": "REQUIRED: Element Name", + "Prompt": "REQUIRED: Element name", "Value": "", "Type": "String" }, { "Name": "pTgtConsol", - "Prompt": "REQUIRED: Target Consolidation", + "Prompt": "OPTIONAL: Target consolidated element name", "Value": "", "Type": "String" }, { "Name": "pMode", - "Prompt": "REQUIRED: Add or Remove Element from Hierarchy", + "Prompt": "REQUIRED: Add or remove element from Hierarchy ('Add' or 'Remove'. Default = 'Add')", "Value": "Add", "Type": "String" }, { "Name": "pWeight", - "Prompt": "OPTIONAL: Element Weight (for Add only)", + "Prompt": "OPTIONAL: Component weight (Default = 1)", "Value": 1, "Type": "Numeric" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [], diff --git a/bedrock_processes_json/}bedrock.hier.elements.validate.json b/bedrock_processes_json/}bedrock.hier.elements.validate.json index 92abc68..6e70c85 100644 --- a/bedrock_processes_json/}bedrock.hier.elements.validate.json +++ b/bedrock_processes_json/}bedrock.hier.elements.validate.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.hier.elements.validate", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.elements.validate', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pDim', '', 'pHier', '*', \r\n \t'pFirst', 1, 'pDelim', '&'\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will review all elements in selected dimensions (you can specify a single dimension,\r\n# multiple dimensions or wildcards to match dimensions) and hierarchies and will generate a `csv` \r\n# file listing all elements with unusual characters.\r\n# Control dimensions are ignored.\r\n\r\n# Note:\r\n# - pDim: Specify which dimensions to validate. When specifying a dimension name, wildcards can\r\n# be specified by using the `*` and `?` characters. A list of dimensions can also be entered with\r\n# a delimiter (e.g. `v*&plan*` will process all dimensions starting with `v` and `plan`). If \r\n# * is entered then it ignores anything entered for hierarchy (pHier) and processes all dimensions\r\n# - pHier: Specify which hierarchies to validate. To validate ALL hierachies, enter *. \r\n# When specifying a hierarchy name, wildcards can be specified by using the\r\n# `*` and `?` characters. A list of hierachies can also be entered with a delimiter. If pHier\r\n# has a value then it does not make sense that pDim can be set up as a list or with wildcards.\r\n# - pDelim: The delimiter is used when specifying multiple dimensions or multiple hierachies. The\r\n# default delimiter is `&`. Any delimiter can be used by specifying a value for pDelim. Choose\r\n# a delimiter that won't be used in either the wildcard search strings or dimension names.\r\n# - pFirst:\r\n# - When set to `1`: all requirements for all characters are validated.\r\n# - ELSE: ignores stringent requirements for 1st character.\r\n#EndRegion @DOC\r\n\r\n\r\n### Global Variables\r\nStringGlobalVariable ('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode = 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncSubset = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = '%cThisProcName% : %sMessage% : %cUserName%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pHier:%pHier%, pFirst:%pFirst%, pDelim:%pDelim%';\r\ncDim = '}Dimensions';\r\ncFile = GetProcessErrorFileDirectory | 'Element Issues.csv';\r\n\r\n# Variables\r\nnMeta = 0;\r\n\r\n## LogOutput parameters\r\nIF ( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\nIf( Scan( '*', pDim ) = 0 & Scan( '?', pDim ) = 0 & Scan( pDelim, pDim ) = 0 & Scan( ':', pDim ) > 0 & pHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pHier = SubSt( pDim, Scan( ':', pDim ) + 1, Long( pDim ) );\r\n pDim = SubSt( pDim, 1, Scan( ':', pDim ) - 1 );\r\nEndIf;\r\n\r\n# Validate dimension\r\nIf( Trim( pDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No dimension specified. Use * to process all dimensions';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate hierarchy\r\nIf( Trim( pHier ) @= '' );\r\n ## use same name as Dimension. Since wildcards are allowed, this is managed inside the code below\r\nEndIf;\r\n\r\nIf( pDelim @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\n## Validate dimension\r\nIF( Trim( pDim ) @= '*' );\r\n sMDX = Expand('{ TM1SUBSETALL( [}Dimensions] ) }');\r\nElseIf( Trim( pHier ) @= '*' );\r\n IF( Scan( pDelim , pDim )>0 );\r\n # delimiter in pDim. Seperate and add MDX for each part separately\r\n sMDX = '';\r\n sDims = Trim( pDim );\r\n nDelimiterIndex = 1;\r\n While( nDelimiterIndex <> 0 ); \r\n nDelimiterIndex = Scan( pDelim, sDims );\r\n If( nDelimiterIndex = 0 );\r\n sDim = sDims;\r\n ELSE;\r\n sDim = Trim( SubSt( sDims, 1, nDelimiterIndex - 1 ) );\r\n sDims = Trim( Subst( sDims, nDelimiterIndex + Long(pDelim), Long( sDims ) ) );\r\n ENDIF;\r\n IF(DimensionExists(sDim)=1 );\r\n sMDX = Expand('TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) ,\"%sDim%*\")');\r\n ELSEIF(Scan( '*', sDim )=0 & Scan( '?', sDim )=0 );\r\n #nErrors = 1;\r\n sMessage= Expand('Dimension %sDim% does not exist.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n ELSE;\r\n sMDX = sMDX | IF( sMDX @<> '',\r\n Expand(',TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) ,\"%sDim%\")'),\r\n Expand(' TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) ,\"%sDim%\")')); \r\n ENDIF;\r\n END;\r\n sMDX ='{ ' | sMDX | ' }';\r\n ELSE;\r\n IF(DimensionExists(pDim)=1 );\r\n sMDX = Expand('{TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) ,\"%pDim%*\")}');\r\n ELSEIF(Scan( '*', pDim )=0 & Scan( '?', pDim )=0 );\r\n nErrors = 1;\r\n sMessage= Expand('Dimension %pDim% does not exist.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n ELSE;\r\n sMDX = Expand('{TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) ,\"%pDim%\")}');\r\n ENDIF;\r\n ENDIF;\r\n \r\nElseIf( HierarchyExists( pDim , pHier ) = 1 & Trim( pHier ) @<>'' );\r\n sMDX = Expand('{TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) ,\"%pDim%:%pHier%\")}');\r\n \r\nElseIf( Scan( pDelim , pHier )>0 % Scan( '*' , pHier )>0 % Scan( '?' , pHier )>0);\r\n IF( Scan( pDelim , pHier )>0 );\r\n sMDX = '';\r\n # delimiter in pHier. Seperate and add MDX for each part separately\r\n sHiers = Trim( pHier );\r\n nDelimiterIndex = 1;\r\n While( nDelimiterIndex <> 0 ); \r\n nDelimiterIndex = Scan( pDelim, sHiers );\r\n If( nDelimiterIndex = 0 );\r\n sHier = sHiers;\r\n ELSE;\r\n sHier = Trim( SubSt( sHiers, 1, nDelimiterIndex - 1 ) );\r\n sHiers = Trim( Subst( sHiers, nDelimiterIndex + Long(pDelim), Long( sHiers ) ) );\r\n ENDIF;\r\n IF(HierarchyExists( pDim, sHier )=1 );\r\n sMDX = sMDX | IF(sMDX @<> '',\r\n Expand(',TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) ,\"%pDim%:%sHier%\")'),\r\n Expand(' TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) ,\"%pDim%:%sHier%\")')); \r\n ELSEIF(Scan( '*', sHier )=0 & Scan( '?', sHier )=0 );\r\n nErrors = 1;\r\n sMessage= Expand('Dimension:Hierarchy %pDim%:%sHier% does not exist.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n ELSE;\r\n sMDX = sMDX | IF(sMDX @<> '',\r\n Expand(',TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) ,\"%pDim%:%sHier%\")'),\r\n Expand(' TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) ,\"%pDim%:%sHier%\")')); \r\n ENDIF;\r\n \r\n END;\r\n sMDX ='{ ' | sMDX | ' }';\r\n ELSE;\r\n # No delimiters but with wildcards in hierachy\r\n IF(HierarchyExists( pDim, pHier )=1 );\r\n sMDX = Expand('{TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) ,\"%pDim%:%pHier%\")}');\r\n ELSEIF(Scan( '*', pHier )=0 & Scan( '?', pHier )=0 );\r\n nErrors = 1;\r\n sMessage= Expand('Dimension:Hierarchy %pDim%:%pHier% does not exist.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n ELSE;\r\n sMDX = Expand('{TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) ,\"%pDim%:%pHier%\")}');\r\n ENDIF;\r\n \r\n ENDIF;\r\n\r\nElseIf( Trim( pHier ) @='' );\r\n ## Use main hierarchy for each dimension processed\r\n pHier = Trim( pDim );\r\n IF( Scan( pDelim , pHier )>0 );\r\n # delimiter in pHier. Seperate and add MDX for each part separately\r\n sMDX = '';\r\n sHiers = Trim( pHier );\r\n nDelimiterIndex = 1;\r\n While( nDelimiterIndex <> 0 ); \r\n nDelimiterIndex = Scan( pDelim, sHiers );\r\n If( nDelimiterIndex = 0 );\r\n sHier = sHiers;\r\n ELSE;\r\n sHier = Trim( SubSt( sHiers, 1, nDelimiterIndex - 1 ) );\r\n sHiers = Trim( Subst( sHiers, nDelimiterIndex + Long(pDelim), Long( sHiers ) ) );\r\n ENDIF;\r\n IF(HierarchyExists( sHier, sHier )=1 );\r\n sMDX = sMDX | IF(sMDX @<> '',\r\n Expand(',TM1FILTERBYPATTERN( EXCEPT( TM1SUBSETALL( [}Dimensions] ) , TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) , \"*:*\") ) ,\"%sHier%\")'),\r\n Expand(' TM1FILTERBYPATTERN( EXCEPT( TM1SUBSETALL( [}Dimensions] ) , TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) , \"*:*\") ) ,\"%sHier%\")')); \r\n ELSEIF(Scan( '*', sHier )=0 & Scan( '?', sHier )=0 );\r\n nErrors = 1;\r\n sMessage= Expand('Dimension:Hierarchy %sHier%:%sHier% does not exist.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n ELSE;\r\n sMDX = sMDX | IF(sMDX @<> '',\r\n Expand(',TM1FILTERBYPATTERN( EXCEPT( TM1SUBSETALL( [}Dimensions] ) , TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) , \"*:*\") ) ,\"%sHier%\")'),\r\n Expand(' TM1FILTERBYPATTERN( EXCEPT( TM1SUBSETALL( [}Dimensions] ) , TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) , \"*:*\") ) ,\"%sHier%\")')); \r\n ENDIF;\r\n \r\n END;\r\n sMDX ='{ ' | sMDX | ' }';\r\n ELSE;\r\n # No delimiters but with wildcards in hierachy\r\n IF(HierarchyExists( pDim, pHier )=1 );\r\n sMDX = Expand('{TM1FILTERBYPATTERN( EXCEPT( TM1SUBSETALL( [}Dimensions] ) , TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) , \"*:*\") ) ,\"%pDim%\")}');\r\n ELSEIF(Scan( '*', pHier )=0 & Scan( '?', pHier )=0 );\r\n nErrors = 1;\r\n sMessage= Expand('Dimension:Hierarchy %pDim%:%pHier% does not exist.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n ELSE;\r\n sMDX = Expand('{TM1FILTERBYPATTERN( EXCEPT( TM1SUBSETALL( [}Dimensions] ) , TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) , \"*:*\") ) ,\"%pDim%\")}');\r\n ENDIF;\r\n \r\n ENDIF;\r\n \r\nELSE;\r\n nErrors = 1;\r\n sMessage= Expand('Dimension:Hierarchy %pDim%:%pHier% does not exist.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n DatasourceType = 'NULL';\r\n ProcessBreak;\r\nEndIf;\r\n\r\n# Create temporary subset\r\nSubsetCreatebyMDX(cSubset, sMDX , 1 );\r\nTextOutput( 'INFO.txt', sMDX );\r\n\r\n### Set data source for process ### \r\nDatasourceType = 'SUBSET';\r\nDatasourceNameForServer = cDim; \r\nDatasourceNameForClient = cDim;\r\nDatasourceDimensionSubset = cSubset;\r\n\r\n### End Prolog ###", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.elements.validate', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pDim', '', 'pHier', '*', \r\n \t'pFirst', 1, 'pDelim', '&'\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will review all elements in selected dimensions (you can specify a single dimension,\r\n# multiple dimensions or wildcards to match dimensions) and hierarchies and will generate a `csv` \r\n# file listing all elements with unusual characters.\r\n# Control dimensions are ignored.\r\n\r\n# Note:\r\n# - pDim: Specify which dimensions to validate. When specifying a dimension name, wildcards can\r\n# be specified by using the `*` and `?` characters. A list of dimensions can also be entered with\r\n# a delimiter (e.g. `v*&plan*` will process all dimensions starting with `v` and `plan`). If \r\n# * is entered then it ignores anything entered for hierarchy (pHier) and processes all dimensions\r\n# - pHier: Specify which hierarchies to validate. To validate ALL hierachies, enter *. \r\n# When specifying a hierarchy name, wildcards can be specified by using the\r\n# `*` and `?` characters. A list of hierachies can also be entered with a delimiter. If pHier\r\n# has a value then it does not make sense that pDim can be set up as a list or with wildcards.\r\n# - pDelim: The delimiter is used when specifying multiple dimensions or multiple hierachies. The\r\n# default delimiter is `&`. Any delimiter can be used by specifying a value for pDelim. Choose\r\n# a delimiter that won't be used in either the wildcard search strings or dimension names.\r\n# - pFirst:\r\n# - When set to `1`: all requirements for all characters are validated.\r\n# - ELSE: ignores stringent requirements for 1st character.\r\n#EndRegion @DOC\r\n\r\n\r\n### Global Variables\r\nStringGlobalVariable ('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode = 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncSubset = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = '%cThisProcName% : %sMessage% : %cUserName%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pHier:%pHier%, pFirst:%pFirst%, pDelim:%pDelim%';\r\ncDim = '}Dimensions';\r\ncFile = GetProcessErrorFileDirectory | 'Element Issues.csv';\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pDelim\": \"&\",\r\n \"pDim\": null,\r\n \"pHier\": \"\",\r\n \"pFirst\": 1,\r\n \"pForV12\": 0,\r\n \"pLogOutput\": 0,\r\n \"pStrictErrorHandling\": 0\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pDelim\": '|StringToJson ( pDelim )|',\r\n \"pDim\": '|StringToJson ( pDim )|',\r\n \"pHier\": '|StringToJson ( pHier )|',\r\n \"pFirst\": '|NumberToString( pFirst )|',\r\n \"pForV12\": '|NumberToString( pForV12 )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npDelim = JsonToString( JsonGet( pJson, 'pDelim' ) );\r\npDim = JsonToString( JsonGet( pJson, 'pDim' ) );\r\npHier = JsonToString( JsonGet( pJson, 'pHier' ) );\r\n# Numeric Parameters\r\npFirst = StringToNumber( JsonToString( JsonGet( pJson, 'pFirst' ) ) );\r\npForV12 = StringToNumber( JsonToString( JsonGet( pJson, 'pForV12' ) ) );\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n# Variables\r\nnMeta = 0;\r\n\r\n## LogOutput parameters\r\nIF ( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\nIf( Scan( '*', pDim ) = 0 & Scan( '?', pDim ) = 0 & Scan( pDelim, pDim ) = 0 & Scan( ':', pDim ) > 0 & pHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pHier = SubSt( pDim, Scan( ':', pDim ) + 1, Long( pDim ) );\r\n pDim = SubSt( pDim, 1, Scan( ':', pDim ) - 1 );\r\nEndIf;\r\n\r\n# Validate dimension\r\nIf( Trim( pDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No dimension specified. Use * to process all dimensions';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate hierarchy\r\nIf( Trim( pHier ) @= '' );\r\n ## use same name as Dimension. Since wildcards are allowed, this is managed inside the code below\r\nEndIf;\r\n\r\nIf( pDelim @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\n## Validate dimension\r\nIF( Trim( pDim ) @= '*' );\r\n sMDX = Expand('{ TM1SUBSETALL( [}Dimensions] ) }');\r\nElseIf( Trim( pHier ) @= '*' );\r\n IF( Scan( pDelim , pDim )>0 );\r\n # delimiter in pDim. Seperate and add MDX for each part separately\r\n sMDX = '';\r\n sDims = Trim( pDim );\r\n nDelimiterIndex = 1;\r\n While( nDelimiterIndex <> 0 ); \r\n nDelimiterIndex = Scan( pDelim, sDims );\r\n If( nDelimiterIndex = 0 );\r\n sDim = sDims;\r\n ELSE;\r\n sDim = Trim( SubSt( sDims, 1, nDelimiterIndex - 1 ) );\r\n sDims = Trim( Subst( sDims, nDelimiterIndex + Long(pDelim), Long( sDims ) ) );\r\n ENDIF;\r\n IF(DimensionExists(sDim)=1 );\r\n sMDX = Expand('TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) ,\"%sDim%*\")');\r\n ELSEIF(Scan( '*', sDim )=0 & Scan( '?', sDim )=0 );\r\n #nErrors = 1;\r\n sMessage= Expand('Dimension %sDim% does not exist.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n ELSE;\r\n sMDX = sMDX | IF( sMDX @<> '',\r\n Expand(',TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) ,\"%sDim%\")'),\r\n Expand(' TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) ,\"%sDim%\")')); \r\n ENDIF;\r\n END;\r\n sMDX ='{ ' | sMDX | ' }';\r\n ELSE;\r\n IF(DimensionExists(pDim)=1 );\r\n sMDX = Expand('{TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) ,\"%pDim%*\")}');\r\n ELSEIF(Scan( '*', pDim )=0 & Scan( '?', pDim )=0 );\r\n nErrors = 1;\r\n sMessage= Expand('Dimension %pDim% does not exist.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n ELSE;\r\n sMDX = Expand('{TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) ,\"%pDim%\")}');\r\n ENDIF;\r\n ENDIF;\r\n \r\nElseIf( HierarchyExists( pDim , pHier ) = 1 & Trim( pHier ) @<>'' );\r\n sMDX = Expand('{TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) ,\"%pDim%:%pHier%\")}');\r\n \r\nElseIf( Scan( pDelim , pHier )>0 % Scan( '*' , pHier )>0 % Scan( '?' , pHier )>0);\r\n IF( Scan( pDelim , pHier )>0 );\r\n sMDX = '';\r\n # delimiter in pHier. Seperate and add MDX for each part separately\r\n sHiers = Trim( pHier );\r\n nDelimiterIndex = 1;\r\n While( nDelimiterIndex <> 0 ); \r\n nDelimiterIndex = Scan( pDelim, sHiers );\r\n If( nDelimiterIndex = 0 );\r\n sHier = sHiers;\r\n ELSE;\r\n sHier = Trim( SubSt( sHiers, 1, nDelimiterIndex - 1 ) );\r\n sHiers = Trim( Subst( sHiers, nDelimiterIndex + Long(pDelim), Long( sHiers ) ) );\r\n ENDIF;\r\n IF(HierarchyExists( pDim, sHier )=1 );\r\n sMDX = sMDX | IF(sMDX @<> '',\r\n Expand(',TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) ,\"%pDim%:%sHier%\")'),\r\n Expand(' TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) ,\"%pDim%:%sHier%\")')); \r\n ELSEIF(Scan( '*', sHier )=0 & Scan( '?', sHier )=0 );\r\n nErrors = 1;\r\n sMessage= Expand('Dimension:Hierarchy %pDim%:%sHier% does not exist.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n ELSE;\r\n sMDX = sMDX | IF(sMDX @<> '',\r\n Expand(',TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) ,\"%pDim%:%sHier%\")'),\r\n Expand(' TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) ,\"%pDim%:%sHier%\")')); \r\n ENDIF;\r\n \r\n END;\r\n sMDX ='{ ' | sMDX | ' }';\r\n ELSE;\r\n # No delimiters but with wildcards in hierachy\r\n IF(HierarchyExists( pDim, pHier )=1 );\r\n sMDX = Expand('{TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) ,\"%pDim%:%pHier%\")}');\r\n ELSEIF(Scan( '*', pHier )=0 & Scan( '?', pHier )=0 );\r\n nErrors = 1;\r\n sMessage= Expand('Dimension:Hierarchy %pDim%:%pHier% does not exist.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n ELSE;\r\n sMDX = Expand('{TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) ,\"%pDim%:%pHier%\")}');\r\n ENDIF;\r\n \r\n ENDIF;\r\n\r\nElseIf( Trim( pHier ) @='' );\r\n ## Use main hierarchy for each dimension processed\r\n pHier = Trim( pDim );\r\n IF( Scan( pDelim , pHier )>0 );\r\n # delimiter in pHier. Seperate and add MDX for each part separately\r\n sMDX = '';\r\n sHiers = Trim( pHier );\r\n nDelimiterIndex = 1;\r\n While( nDelimiterIndex <> 0 ); \r\n nDelimiterIndex = Scan( pDelim, sHiers );\r\n If( nDelimiterIndex = 0 );\r\n sHier = sHiers;\r\n ELSE;\r\n sHier = Trim( SubSt( sHiers, 1, nDelimiterIndex - 1 ) );\r\n sHiers = Trim( Subst( sHiers, nDelimiterIndex + Long(pDelim), Long( sHiers ) ) );\r\n ENDIF;\r\n IF(HierarchyExists( sHier, sHier )=1 );\r\n sMDX = sMDX | IF(sMDX @<> '',\r\n Expand(',TM1FILTERBYPATTERN( EXCEPT( TM1SUBSETALL( [}Dimensions] ) , TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) , \"*:*\") ) ,\"%sHier%\")'),\r\n Expand(' TM1FILTERBYPATTERN( EXCEPT( TM1SUBSETALL( [}Dimensions] ) , TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) , \"*:*\") ) ,\"%sHier%\")')); \r\n ELSEIF(Scan( '*', sHier )=0 & Scan( '?', sHier )=0 );\r\n nErrors = 1;\r\n sMessage= Expand('Dimension:Hierarchy %sHier%:%sHier% does not exist.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n ELSE;\r\n sMDX = sMDX | IF(sMDX @<> '',\r\n Expand(',TM1FILTERBYPATTERN( EXCEPT( TM1SUBSETALL( [}Dimensions] ) , TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) , \"*:*\") ) ,\"%sHier%\")'),\r\n Expand(' TM1FILTERBYPATTERN( EXCEPT( TM1SUBSETALL( [}Dimensions] ) , TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) , \"*:*\") ) ,\"%sHier%\")')); \r\n ENDIF;\r\n \r\n END;\r\n sMDX ='{ ' | sMDX | ' }';\r\n ELSE;\r\n # No delimiters but with wildcards in hierachy\r\n IF(HierarchyExists( pDim, pHier )=1 );\r\n sMDX = Expand('{TM1FILTERBYPATTERN( EXCEPT( TM1SUBSETALL( [}Dimensions] ) , TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) , \"*:*\") ) ,\"%pDim%\")}');\r\n ELSEIF(Scan( '*', pHier )=0 & Scan( '?', pHier )=0 );\r\n nErrors = 1;\r\n sMessage= Expand('Dimension:Hierarchy %pDim%:%pHier% does not exist.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n ELSE;\r\n sMDX = Expand('{TM1FILTERBYPATTERN( EXCEPT( TM1SUBSETALL( [}Dimensions] ) , TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) , \"*:*\") ) ,\"%pDim%\")}');\r\n ENDIF;\r\n \r\n ENDIF;\r\n \r\nELSE;\r\n nErrors = 1;\r\n sMessage= Expand('Dimension:Hierarchy %pDim%:%pHier% does not exist.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n DatasourceType = 'NULL';\r\n ProcessBreak;\r\nEndIf;\r\n\r\n# Create temporary subset\r\nSubsetCreatebyMDX(cSubset, sMDX , 1 );\r\nTextOutput( 'INFO.txt', sMDX );\r\n\r\n### Set data source for process ### \r\nDatasourceType = 'SUBSET';\r\nDatasourceNameForServer = cDim; \r\nDatasourceNameForClient = cDim;\r\nDatasourceDimensionSubset = cSubset;\r\n\r\n### End Prolog ###", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock Ver 4.0.0~~##\r\n################################################################################################# \r\n\r\n# Validates characters in elements\r\n\r\n# Increment nMeta\r\nnMeta = nMeta + 1;\r\n\r\n# Output 1st line\r\nIF( nMeta = 1 );\r\n sOutput = 'Dimension:Hierarchy\"' |','| '\"Element\"' |','| '\"Type\"' |','| '\"Comments';\r\n TextOutput ( cFile , sOutput );\r\nEndIf;\r\n\r\n### Skip Control dimensions###\r\nIF(Subst(vDim , 1 , 1 ) @= '}' );\r\n ItemSkip;\r\nENDIF;\r\n\r\n# Set Dim name & hierachy name\r\nIF( SCAN( ':' , vDim )=0 );\r\n sDim = vDim ;\r\n sHier = sDim ;\r\nELSE;\r\n sDim = SUBST( vDim, 1 , SCAN( ':' , vDim ) -1 );\r\n sHier = SUBST( vDim, SCAN( ':' , vDim ) +1, 99 );\r\nENDIF;\r\n\r\nnDimSize = ElementCount( sDim , sHier );\r\nnCount = 1;\r\nWhile( nCount <= nDimSize );\r\n sEle = ElementName( sDim , sHier , nCount );\r\n sEleType = ElementType( sDim , sHier , sEle );\r\n sEleNew = '';\r\n nEleSiz = Long(sEle);\r\n nParentCount= ElementParentCount( sDim, sHier, sEle );\r\n nChar = 1;\r\n While( nChar <= nEleSiz & ElementIndex( sDim , sHier , sEle ) > 0 );\r\n sChar = NumberToString( nChar );\r\n sEleChar = Subst( sEle , nChar , 1 );\r\n nCode = CODE( sEle , nChar );\r\n sCode = NumberToString( nCode );\r\n IF( vDim @= sDim );\r\n IF( nChar=1 & pFirst=1 & (nCode=39 % nCode=45 % nCode=91 % nCode=34 % nCode=64 % nCode=33 % nCode=43 % nCode=123 % nCode=37));\r\n sOutput = Expand('%vDim%\" , %sEle% , %sEleType% ,Has an illegal 1st character \"%sEleChar%\" with an AscII code of %sCode%.');\r\n TextOutput ( cFile , sOutput );\r\n EndIf;\r\n IF( sEleChar@='/' % sEleChar@='|' % sEleChar@='\"' % sEleChar@='\\' % sEleChar@='>' % \r\n sEleChar@='<' % sEleChar@=':' % sEleChar@='?' % sEleChar@='*'); \r\n sOutput = Expand('%vDim%\" , %sEle% , %sEleType% ,Has a forbidden character #%sChar% \"%sEleChar%\" with an AscII code of %sCode%.');\r\n TextOutput ( cFile , sOutput );\r\n ENDIF;\r\n ELSEIF( ElementType( sDim, sHier, sEle)@='C' % pHier@<>'' );\r\n IF( nChar=1 & pFirst=1 & (nCode=39 % nCode=45 % nCode=91 % nCode=34 % nCode=64 % nCode=33 % nCode=43 % nCode=123 % nCode=37));\r\n sOutput = Expand('%vDim%\" , %sEle% , %sEleType% ,Has an illegal 1st character \"%sEleChar%\" with an AscII code of %sCode%.');\r\n TextOutput ( cFile , sOutput );\r\n EndIf;\r\n IF( sEleChar@='/' % sEleChar@='|' % sEleChar@='\"' % sEleChar@='\\' % sEleChar@='>' % \r\n sEleChar@='<' % sEleChar@=':' % sEleChar@='?' % sEleChar@='*'); \r\n sOutput = Expand('%vDim%\" , %sEle% , %sEleType% ,Has a forbidden character #%sChar% \"%sEleChar%\" with an AscII code of %sCode%.');\r\n TextOutput ( cFile , sOutput );\r\n ENDIF;\r\n ENDIF;\r\n\r\n nChar = nChar + 1;\r\n End;\r\n \r\n # V12 Check\r\n IF( pForV12 <> 0 );\r\n # Check if S Type element is part of a consolidation\r\n IF( sEleType @= 'S' & nParentCount <> 0 );\r\n sParentCount = NumberToString( nParentCount );\r\n sOutput = Expand('%vDim%\" , %sEle% , %sEleType%, is part of %sParentCount% consolidations, which is forbidden in V12.');\r\n TextOutput ( cFile , sOutput );\r\n ENDIF;\r\n \r\n # Check if Element has different type in Leaves hierarchy\r\n IF( HierarchyExists( sDim, 'Leaves' ) = 1 & sHier @<> 'Leaves' );\r\n sEleTypeInLeaves = ElementType( sDim , sHier , sEle );\r\n IF( sEleTypeInLeaves @<> sEleType );\r\n sOutput = Expand('%vDim%\" , %sHier%, %sEle% , %sEleType%, has a different type in the Leaves hierarchy, \"%sEleTypeInLeaves%\", which is forbidden in V12.');\r\n TextOutput ( cFile , sOutput );\r\n ENDIF;\r\n ENDIF;\r\n ENDIF;\r\n \r\n nCount = nCount + 1;\r\nEnd;\r\n\r\n### End MetaData ###", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock Ver 4.0.0~~##\r\n################################################################################################# \r\n\r\n### If errors occurred terminate process with a major error status ###\r\nIf( nErrors <> 0 );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% incurred at least 1 major error and consequently aborted.' );\r\n nProcessReturnCode = 0;\r\n LogOutput( 'ERROR', Expand( sProcessReturnCode | ' Please see above lines in this file for more details.' ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nEndIf;\r\n\r\n#Return Code\r\nsProcessAction = Expand( 'Process:%cThisProcName% has validated all the elements for %pDim% dimension and generated a csv report: %cFile%.' );\r\nsProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\nnProcessReturnCode = 1;\r\nIF ( pLogoutput = 1 );\r\n LogOutput('INFO', sProcessAction ); \r\nENDIF;\r\n\r\n### End Epilog ###", @@ -13,47 +13,53 @@ "subset": "}Export.All" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pDim", - "Prompt": "OPTIONAL: Dimension name or list? (accepts wildcards). Will process ALL if = *", + "Prompt": "REQUIRED: Delimited list of dimensions", "Value": "", "Type": "String" }, { "Name": "pHier", - "Prompt": "OPTIONAL: Hierarchy name or list? (accepts wildcards). Will process ALL if = *", - "Value": "*", + "Prompt": "OPTIONAL: Hierarchy name (Default = pDim)", + "Value": "", "Type": "String" }, { "Name": "pFirst", - "Prompt": "OPTIONAL: 0 = Ignore 1st character requirements, 1 = Validate 1st character more stringently than other characters (e.g. for MDX no \"+\" as 1st character)", + "Prompt": "OPTIONAL: Validate first character more strictly (Boolean. Default = 1)", "Value": 1, "Type": "Numeric" }, { "Name": "pDelim", - "Prompt": "OPTIONAL: Delimiter for dimension list (If blank or not passed then \"&\" will be used as default list delimiter)", + "Prompt": "OPTIONAL: Delimiter for list parameters (Default = '&')", "Value": "&", "Type": "String" }, { "Name": "pForV12", - "Prompt": "OPTIONAL: Some element configurations are valid in V11 but not in V12. If specified, the process will check for those invalid configurations. (Boolean True = 1)", + "Prompt": "OPTIONAL: Some element configurations are valid in V11 but not in V12. If specified, the process will check for those invalid configurations (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [ @@ -65,7 +71,5 @@ "EndByte": 0 } ], - "VariablesUIData": [ - "VarType=32\fColType=827\f" - ] + "VariablesUIData": [] } \ No newline at end of file diff --git a/bedrock_processes_json/}bedrock.hier.emptyconsols.delete.json b/bedrock_processes_json/}bedrock.hier.emptyconsols.delete.json index 753a842..0613c7c 100644 --- a/bedrock_processes_json/}bedrock.hier.emptyconsols.delete.json +++ b/bedrock_processes_json/}bedrock.hier.emptyconsols.delete.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.hier.emptyconsols.delete", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.emptyconsols.delete', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n\t 'pDim', '', 'pHier', ''\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will delete all consolidated elements with no children in the target Hierarchy.\r\n\r\n# Use case:\r\n# - Service process to clean-up consolidations after dimension changes.\r\n\r\n# Note:\r\n# Valid target dimension (pDim) must be supplied otherwise the process will terminate.\r\n\r\n# Caution: Target hierarchy (pHier) cannot be `Leaves`.\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent= 'Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pHier:%pHier%.' ; \r\ncMsgInfoContent = 'User:%cUserName% Process:%cThisProcName% Message:%sMessage%';\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\nIf( Scan( '*', pDim ) = 0 & Scan( '?', pDim ) = 0 & Scan( pDelim, pDim ) = 0 & Scan( ':', pDim ) > 0 & pHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pHier = SubSt( pDim, Scan( ':', pDim ) + 1, Long( pDim ) );\r\n pDim = SubSt( pDim, 1, Scan( ':', pDim ) - 1 );\r\nEndIf;\r\n\r\n# Validate dimension\r\nIf( Trim( pDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate Hierarchy\r\nIf( Trim( pHier ) @= '' );\r\n ## use same name as Dimension. Since wildcards are allowed this is managed inside the code below\r\nEndIf;\r\n\r\n# If blank delimiter specified then convert to default\r\nIf( pDelim @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n# Loop through dimensions in pDim\r\nsDims = pDim;\r\nnDimDelimiterIndex = 1;\r\nsMdx = '';\r\n# Get 1st dimension\r\nWhile( nDimDelimiterIndex <> 0 );\r\n # Extract 1st dimension > sDim\r\n nDimDelimiterIndex = Scan( pDelim, sDims );\r\n If( nDimDelimiterIndex = 0 );\r\n sDim = sDims;\r\n Else;\r\n sDim = Trim( SubSt( sDims, 1, nDimDelimiterIndex - 1 ) );\r\n sDims = Trim( Subst( sDims, nDimDelimiterIndex + Long(pDelim), Long( sDims ) ) );\r\n EndIf;\r\n \r\n # Create subset of dimensions using Wildcard to loop through dimensions in pDim with wildcard\r\n sDimExp = '\"'|sDim|'\"';\r\n sMdxPart = '{TM1FILTERBYPATTERN( EXCEPT( TM1SUBSETALL( [}Dimensions] ) , TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) , \"*:*\") ) ,'| sDimExp | ')}';\r\n IF( sMdx @= ''); \r\n sMdx = sMdxPart; \r\n ELSE;\r\n sMdx = sMdx | ' + ' | sMdxPart;\r\n ENDIF;\r\nEnd;\r\n\r\nIf( SubsetExists( '}Dimensions' , cTempSub ) = 1 );\r\n # If a delimited list of dim names includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( '}Dimensions' , cTempSub, sMDX );\r\nElse;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSub, sMDX, '}Dimensions' , 1 );\r\nEndIf;\r\n\r\n# Loop through dimensions in subset created based on wildcard\r\nnCountDim = SubsetGetSize( '}Dimensions' , cTempSub );\r\nWhile( nCountDim >= 1 );\r\n sDim = SubsetGetElementName( '}Dimensions' , cTempSub, nCountDim );\r\n # Validate dimension name\r\n If( DimensionExists(sDim) = 0 );\r\n nErrors = 1;\r\n sMessage = Expand( 'Dimension %sDim% does not exist.' );\r\n LogOutput( 'ERROR', Expand( cMsgErrorContent ) );\r\n Else;\r\n If( pLogOutput = 1 );\r\n sMessage = Expand( 'Dimension %sDim% being processed....' );\r\n LogOutput( 'INFO', Expand( cMsgInfoContent ) );\r\n EndIf;\r\n # Loop through hierarchies in pHier\r\n If( Trim( pHier ) @= '' );\r\n ### Use main hierarchy for each dimension if pHier is empty\r\n sHierarchies = sDim;\r\n Else;\r\n sHierarchies = pHier;\r\n EndIf;\r\n nDelimiterIndexA = 1;\r\n sHierDim = '}Dimensions';\r\n \r\n sMdxHier = '';\r\n While( nDelimiterIndexA <> 0 );\r\n\r\n nDelimiterIndexA = Scan( pDelim, sHierarchies );\r\n If( nDelimiterIndexA = 0 );\r\n sHierarchy = sHierarchies;\r\n Else;\r\n sHierarchy = Trim( SubSt( sHierarchies, 1, nDelimiterIndexA - 1 ) );\r\n sHierarchies = Trim( Subst( sHierarchies, nDelimiterIndexA + Long(pDelim), Long( sHierarchies ) ) );\r\n EndIf;\r\n \r\n ## If no wildcard specified and current hierarchy does not exist in dimension, create it\r\n If( Scan( '*', sHierarchy ) = 0 & Scan( '?', sHierarchy ) = 0);\r\n If( HierarchyExists( sDim, sHierarchy ) = 0 );\r\n HierarchyCreate( sDim, sHierarchy );\r\n EndIf;\r\n EndIf;\r\n\r\n # Create subset of Hierarchies using Wildcard\r\n If( sHierarchy @= sDim );\r\n sHierExp = '\"'| sHierarchy |'\"';\r\n Else;\r\n sHierExp = '\"'|sDim|':'|sHierarchy|'\"';\r\n EndIf;\r\n sMdxHierPart = '{TM1FILTERBYPATTERN( {TM1SUBSETALL([ ' |sHierDim| '])},'| sHierExp | ')}';\r\n IF( sMdxHier @= ''); \r\n sMdxHier = sMdxHierPart; \r\n ELSE;\r\n sMdxHier = sMdxHier | ' + ' | sMdxHierPart;\r\n ENDIF;\r\n End;\r\n IF(Trim(pHier) @= '*');\r\n sMdxHier = '{ UNION ( ' | sMdxHier |' , {[}Dimensions].[' | sDim | ']} )}';\r\n ENDIF;\r\n \r\n If( SubsetExists( sHierDim, cTempSub ) = 1 );\r\n # If a delimited list of attr names includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( sHierDim, cTempSub, sMdxHier );\r\n Else;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSub, sMdxHier, sHierDim, 1 );\r\n EndIf;\r\n \r\n # Loop through subset of hierarchies created based on wildcard\r\n nCountHier = SubsetGetSize( sHierDim, cTempSub );\r\n While( nCountHier >= 1 );\r\n sCurrHier = SubsetGetElementName( sHierDim, cTempSub, nCountHier );\r\n sCurrHierName = Subst( sCurrHier, Scan(':', sCurrHier)+1, Long(sCurrHier) );\r\n # Validate hierarchy name in dimension\r\n If( Dimix( sHierDim , sCurrHier ) = 0 );\r\n sMessage = Expand('The %sCurrHier% hierarchy does NOT exist in the %sDim% dimension.');\r\n LogOutput( 'INFO' , Expand( cMsgInfoContent ) );\r\n Else;\r\n If( pLogOutput = 1 );\r\n sMessage = Expand( 'Hierarchy %sCurrHierName% in Dimension %sDim% being processed....' );\r\n LogOutput( 'INFO', Expand( cMsgInfoContent ) );\r\n EndIf;\r\n \r\n ### Go through dimension and delete consols with no children ###\r\n nElementCount = ElementCount( sDim, sCurrHierName );\r\n While( nElementCount >= 1 );\r\n sElement = ElementName( sDim, sCurrHierName, nElementCount );\r\n sElementType = ElementType( sDim, sCurrHierName, sElement );\r\n If( sElementType @= 'C' );\r\n nChildCount = ElementComponentCount( sDim, sCurrHierName, sElement );\r\n If( nChildCount = 0 );\r\n HierarchyElementDelete( sDim, sCurrHierName, sElement );\r\n EndIf;\r\n EndIf;\r\n nElementCount = nElementCount - 1;\r\n End;\r\n\r\n Endif;\r\n \r\n nCountHier = nCountHier - 1;\r\n End;\r\n \r\n EndIf;\r\n \r\n nCountDim = nCountDim - 1;\r\nEnd;\r\n\r\n### End Prolog ###", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.emptyconsols.delete', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n\t 'pDim', '', 'pHier', ''\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will delete all consolidated elements with no children in the target Hierarchy.\r\n\r\n# Use case:\r\n# - Service process to clean-up consolidations after dimension changes.\r\n\r\n# Note:\r\n# Valid target dimension (pDim) must be supplied otherwise the process will terminate.\r\n\r\n# Caution: Target hierarchy (pHier) cannot be `Leaves`.\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent= 'Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pHier:%pHier%.' ; \r\ncMsgInfoContent = 'User:%cUserName% Process:%cThisProcName% Message:%sMessage%';\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pDelim\": \"&\",\r\n \"pDim\": null,\r\n \"pHier\": \"\",\r\n \"pLogOutput\": 0,\r\n \"pStrictErrorHandling\": 0\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pDelim\": '|StringToJson ( pDelim )|',\r\n \"pDim\": '|StringToJson ( pDim )|',\r\n \"pHier\": '|StringToJson ( pHier )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npDelim = JsonToString( JsonGet( pJson, 'pDelim' ) );\r\npDim = JsonToString( JsonGet( pJson, 'pDim' ) );\r\npHier = JsonToString( JsonGet( pJson, 'pHier' ) );\r\n# Numeric Parameters\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\nIf( Scan( '*', pDim ) = 0 & Scan( '?', pDim ) = 0 & Scan( pDelim, pDim ) = 0 & Scan( ':', pDim ) > 0 & pHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pHier = SubSt( pDim, Scan( ':', pDim ) + 1, Long( pDim ) );\r\n pDim = SubSt( pDim, 1, Scan( ':', pDim ) - 1 );\r\nEndIf;\r\n\r\n# Validate dimension\r\nIf( Trim( pDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate Hierarchy\r\nIf( Trim( pHier ) @= '' );\r\n ## use same name as Dimension. Since wildcards are allowed this is managed inside the code below\r\nEndIf;\r\n\r\n# If blank delimiter specified then convert to default\r\nIf( pDelim @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n# Loop through dimensions in pDim\r\nsDims = pDim;\r\nnDimDelimiterIndex = 1;\r\nsMdx = '';\r\n# Get 1st dimension\r\nWhile( nDimDelimiterIndex <> 0 );\r\n # Extract 1st dimension > sDim\r\n nDimDelimiterIndex = Scan( pDelim, sDims );\r\n If( nDimDelimiterIndex = 0 );\r\n sDim = sDims;\r\n Else;\r\n sDim = Trim( SubSt( sDims, 1, nDimDelimiterIndex - 1 ) );\r\n sDims = Trim( Subst( sDims, nDimDelimiterIndex + Long(pDelim), Long( sDims ) ) );\r\n EndIf;\r\n \r\n # Create subset of dimensions using Wildcard to loop through dimensions in pDim with wildcard\r\n sDimExp = '\"'|sDim|'\"';\r\n sMdxPart = '{TM1FILTERBYPATTERN( EXCEPT( TM1SUBSETALL( [}Dimensions] ) , TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) , \"*:*\") ) ,'| sDimExp | ')}';\r\n IF( sMdx @= ''); \r\n sMdx = sMdxPart; \r\n ELSE;\r\n sMdx = sMdx | ' + ' | sMdxPart;\r\n ENDIF;\r\nEnd;\r\n\r\nIf( SubsetExists( '}Dimensions' , cTempSub ) = 1 );\r\n # If a delimited list of dim names includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( '}Dimensions' , cTempSub, sMDX );\r\nElse;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSub, sMDX, '}Dimensions' , 1 );\r\nEndIf;\r\n\r\n# Loop through dimensions in subset created based on wildcard\r\nnCountDim = SubsetGetSize( '}Dimensions' , cTempSub );\r\nWhile( nCountDim >= 1 );\r\n sDim = SubsetGetElementName( '}Dimensions' , cTempSub, nCountDim );\r\n # Validate dimension name\r\n If( DimensionExists(sDim) = 0 );\r\n nErrors = 1;\r\n sMessage = Expand( 'Dimension %sDim% does not exist.' );\r\n LogOutput( 'ERROR', Expand( cMsgErrorContent ) );\r\n Else;\r\n If( pLogOutput = 1 );\r\n sMessage = Expand( 'Dimension %sDim% being processed....' );\r\n LogOutput( 'INFO', Expand( cMsgInfoContent ) );\r\n EndIf;\r\n # Loop through hierarchies in pHier\r\n If( Trim( pHier ) @= '' );\r\n ### Use main hierarchy for each dimension if pHier is empty\r\n sHierarchies = sDim;\r\n Else;\r\n sHierarchies = pHier;\r\n EndIf;\r\n nDelimiterIndexA = 1;\r\n sHierDim = '}Dimensions';\r\n \r\n sMdxHier = '';\r\n While( nDelimiterIndexA <> 0 );\r\n\r\n nDelimiterIndexA = Scan( pDelim, sHierarchies );\r\n If( nDelimiterIndexA = 0 );\r\n sHierarchy = sHierarchies;\r\n Else;\r\n sHierarchy = Trim( SubSt( sHierarchies, 1, nDelimiterIndexA - 1 ) );\r\n sHierarchies = Trim( Subst( sHierarchies, nDelimiterIndexA + Long(pDelim), Long( sHierarchies ) ) );\r\n EndIf;\r\n \r\n ## If no wildcard specified and current hierarchy does not exist in dimension, create it\r\n If( Scan( '*', sHierarchy ) = 0 & Scan( '?', sHierarchy ) = 0);\r\n If( HierarchyExists( sDim, sHierarchy ) = 0 );\r\n HierarchyCreate( sDim, sHierarchy );\r\n EndIf;\r\n EndIf;\r\n\r\n # Create subset of Hierarchies using Wildcard\r\n If( sHierarchy @= sDim );\r\n sHierExp = '\"'| sHierarchy |'\"';\r\n Else;\r\n sHierExp = '\"'|sDim|':'|sHierarchy|'\"';\r\n EndIf;\r\n sMdxHierPart = '{TM1FILTERBYPATTERN( {TM1SUBSETALL([ ' |sHierDim| '])},'| sHierExp | ')}';\r\n IF( sMdxHier @= ''); \r\n sMdxHier = sMdxHierPart; \r\n ELSE;\r\n sMdxHier = sMdxHier | ' + ' | sMdxHierPart;\r\n ENDIF;\r\n End;\r\n IF(Trim(pHier) @= '*');\r\n sMdxHier = '{ UNION ( ' | sMdxHier |' , {[}Dimensions].[' | sDim | ']} )}';\r\n ENDIF;\r\n \r\n If( SubsetExists( sHierDim, cTempSub ) = 1 );\r\n # If a delimited list of attr names includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( sHierDim, cTempSub, sMdxHier );\r\n Else;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSub, sMdxHier, sHierDim, 1 );\r\n EndIf;\r\n \r\n # Loop through subset of hierarchies created based on wildcard\r\n nCountHier = SubsetGetSize( sHierDim, cTempSub );\r\n While( nCountHier >= 1 );\r\n sCurrHier = SubsetGetElementName( sHierDim, cTempSub, nCountHier );\r\n sCurrHierName = Subst( sCurrHier, Scan(':', sCurrHier)+1, Long(sCurrHier) );\r\n # Validate hierarchy name in dimension\r\n If( Dimix( sHierDim , sCurrHier ) = 0 );\r\n sMessage = Expand('The %sCurrHier% hierarchy does NOT exist in the %sDim% dimension.');\r\n LogOutput( 'INFO' , Expand( cMsgInfoContent ) );\r\n Else;\r\n If( pLogOutput = 1 );\r\n sMessage = Expand( 'Hierarchy %sCurrHierName% in Dimension %sDim% being processed....' );\r\n LogOutput( 'INFO', Expand( cMsgInfoContent ) );\r\n EndIf;\r\n \r\n ### Go through dimension and delete consols with no children ###\r\n nElementCount = ElementCount( sDim, sCurrHierName );\r\n While( nElementCount >= 1 );\r\n sElement = ElementName( sDim, sCurrHierName, nElementCount );\r\n sElementType = ElementType( sDim, sCurrHierName, sElement );\r\n If( sElementType @= 'C' );\r\n nChildCount = ElementComponentCount( sDim, sCurrHierName, sElement );\r\n If( nChildCount = 0 );\r\n HierarchyElementDelete( sDim, sCurrHierName, sElement );\r\n EndIf;\r\n EndIf;\r\n nElementCount = nElementCount - 1;\r\n End;\r\n\r\n Endif;\r\n \r\n nCountHier = nCountHier - 1;\r\n End;\r\n \r\n EndIf;\r\n \r\n nCountDim = nCountDim - 1;\r\nEnd;\r\n\r\n### End Prolog ###", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully deleted all C level items that did not have children.' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n### End Epilog ###", @@ -10,35 +10,41 @@ "Type": "None" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pDim", - "Prompt": "REQUIRED: Target Dimension (accepts wildcards and delimited list)", + "Prompt": "REQUIRED: Delimited list of dimensions", "Value": "", "Type": "String" }, { "Name": "pHier", - "Prompt": "OPTIONAL: Target Hierarchy (accepts wildcards and delimited list, uses default hierarchy if left blank)", + "Prompt": "OPTIONAL: Hierarchy name (Default = pDim)", "Value": "", "Type": "String" }, { "Name": "pDelim", - "Prompt": "OPTIONAL: Delimiter character for dimension or hierarchy list (default value if blank = '&')", + "Prompt": "OPTIONAL: Delimiter for list parameters (Default = '&')", "Value": "&", "Type": "String" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [], diff --git a/bedrock_processes_json/}bedrock.hier.export.json b/bedrock_processes_json/}bedrock.hier.export.json index 9b90d86..9e75455 100644 --- a/bedrock_processes_json/}bedrock.hier.export.json +++ b/bedrock_processes_json/}bedrock.hier.export.json @@ -1,11 +1,11 @@ { "Name": "}bedrock.hier.export", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.export', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pDim', '', 'pHier', '',\r\n \t'pTgtDir', '', 'pTgtFile', '',\r\n \t'pTitleRecord', 1, 'pDelim', ',', 'pQuote', '\"',\r\n \t'pLegacy', 0\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will Export all Dimension elements in a Hierarchy to a File. Export file maintains\r\n# all data that can be used to completely reconstruct the dimension. Custom record delimiter\r\n# (specified by a character or its ASCII code) can be used.\r\n# __Format of the file:__ \r\n# - 1st line: File metadata contains summary information about the dimension, hierarchy, number of\r\n# elements and date/time when file was generated.\r\n# - 2nd line: Source dimension and hierarchy.\r\n# - 3rd line: Dimension sort order.\r\n# - 4th and 5th line: Reserved for future development.\r\n# - 6th line: Header for elements export.\r\n# - 7th line and forth: Elements export data.\r\n\r\n# Use case:\r\n# 1. Backup of dimension before changes in productive environment.\r\n# 2. Quick replication of a large dimension.\r\n\r\n# Note:\r\n# Valid dimension name (pDim), inclusion of header (pTitleRecord) and legacy export format (pLegacy)\r\n# are mandatory otherwise the process will abort.\r\n# If needed, custom delimiter might be used by specifying parameter pDelim value as either exactly one\r\n# character or as a 3-digit (decimal) ASCII code. For example to use TAB as a delimiter, use 009.\r\n\r\n# Caution: Process was redesigned in Bedrock4 but is able to process dimension extracts from prior\r\n# versions of Bedrock in legacy mode (pLegacy = 1).\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent= 'Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pHier:%pHier%, pTgtDir:%pTgtDir%, pTgtFile:%pTgtFile%, pTitleRecord:%pTitleRecord%, pDelim:%pDelim%, pQuote:%pQuote%, pLegacy:%pLegacy%.';\r\ncType = 'Type-';\r\ncParent = 'Parent-';\r\ncIndex = 'Index-';\r\ncWeight = 'Weight-';\r\ncAttrName = 'Attr Name-';\r\ncAttrValue = 'Attr Value-';\r\ncLenASCIICode = 3;\r\n\r\npDelim = TRIM(pDelim);\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Initialise ###\r\nnRecordCount = 0;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\nIf( Scan( ':', pDim ) > 0 & pHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pHier = SubSt( pDim, Scan( ':', pDim ) + 1, Long( pDim ) );\r\n pDim = SubSt( pDim, 1, Scan( ':', pDim ) - 1 );\r\nEndIf;\r\n\r\n# Validate dimension\r\nIf( Trim( pDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( DimensionExists( pDim ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Dimension: ' | pDim | ' does not exist.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate Hierarchy\r\nIf( Trim( pHier ) @= '' );\r\n sHier = pDim;\r\nElse;\r\n sHier = pHier;\r\nEndIf;\r\n\r\nIf( HierarchyExists( pDim, sHier ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'The Hierachy ' | sHier | ' does not exist.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n## check operating system\r\nIf( SubSt( GetProcessErrorFileDirectory, 2, 1 ) @= ':' );\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nElseIf( Scan( '/', GetProcessErrorFileDirectory ) > 0 );\r\n sOS = 'Linux';\r\n sOSDelim = '/';\r\nElse;\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nEndIf;\r\n\r\n# Validate export path\r\nIf( Trim( pTgtDir ) @= '' );\r\n pTgtDir = GetProcessErrorFileDirectory;\r\n sMessage = 'Target folder defaulted to error file directory.';\r\n LogOutput( 'INFO', Expand( cMsgErrorContent ) );\r\nEndIf;\r\nIf( SubSt( pTgtDir, Long( pTgtDir ), 1 ) @= sOSDelim );\r\n pTgtDir = SubSt( pTgtDir, 1, Long( pTgtDir ) -1 );\r\nEndIf;\r\nIf( FileExists( pTgtDir ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid export path specified. Folder does not exist.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\npTgtDir = pTgtDir | sOSDelim;\r\n\r\n# Validate export filename\r\nIf( pTgtFile @= '' );\r\n pTgtFile = pDim | If( pLegacy = 1,'',' '|sHier ) | '_Export.csv';\r\nElseIf( Scan( '.', pTgtFile ) = 0 );\r\n # No file extension specified\r\n pTgtFile = pTgtFile | '.csv';\r\nEndIf;\r\n\r\n# Validate file delimiter & quote character\r\nIf( pDelim @= '' );\r\n pDelim = ',';\r\nElse;\r\n # If length of pDelim is exactly 3 chars and each of them is decimal digit, then the pDelim is entered as ASCII code\r\n nValid = 0;\r\n If ( LONG(pDelim) = cLenASCIICode );\r\n nChar = 1;\r\n While ( nChar <= cLenASCIICode );\r\n If( CODE( pDelim, nChar )>=CODE( '0', 1 ) & CODE( pDelim, nChar )<=CODE( '9', 1 ) );\r\n nValid = 1;\r\n Else;\r\n nValid = 0;\r\n EndIf;\r\n nChar = nChar + 1;\r\n End;\r\n EndIf;\r\n If ( nValid<>0 );\r\n pDelim=CHAR(StringToNumber( pDelim ));\r\n Else;\r\n pDelim = SubSt( Trim( pDelim ), 1, 1 );\r\n EndIf;\r\nEndIf;\r\nIf( pQuote @= '' );\r\n ## Use no quote character \r\nElse;\r\n # If length of pQuote is exactly 3 chars and each of them is decimal digit, then the pQuote is entered as ASCII code\r\n nValid = 0;\r\n If ( LONG(pQuote) = cLenASCIICode );\r\n nChar = 1;\r\n While ( nChar <= cLenASCIICode );\r\n If( CODE( pQuote, nChar ) >= CODE( '0', 1 ) & CODE( pQuote, nChar ) <= CODE( '9', 1 ) );\r\n nValid = 1;\r\n Else;\r\n nValid = 0;\r\n EndIf;\r\n nChar = nChar + 1;\r\n End;\r\n EndIf;\r\n If ( nValid<>0 );\r\n pQuote=CHAR(StringToNumber( pQuote ));\r\n Else;\r\n pQuote = SubSt( Trim( pQuote ), 1, 1 );\r\n EndIf;\r\nEndIf;\r\n\r\n# Validate Character Set\r\nIf(Trim( pCharacterSet ) @= '' );\r\n pCharacterSet = 'TM1CS_UTF8';\r\nEndIf;\r\n\r\n# Construct full export filename including path\r\nsFilename = pTgtDir | pTgtFile;\r\nsLocAttFile = 'Localized_' | pTgtFile;\r\nsAttrDimName = '}ElementAttributes_' | pDim ;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### Assign Data Source ###\r\nDatasourceNameForServer = pDim | IF(pHier@='','',':'|pHier) ;\r\nDatasourceNameForClient = DatasourceNameForServer ;\r\nDataSourceType = 'SUBSET';\r\nDatasourceDimensionSubset = 'ALL';\r\nDatasourceAsciiDelimiter= pDelim;\r\nDatasourceAsciiQuoteCharacter = pQuote;\r\n\r\n### End Prolog ###", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.export', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pDim', '', 'pHier', '',\r\n \t'pTgtDir', '', 'pTgtFile', '',\r\n \t'pTitleRecord', 1, 'pDelim', ',', 'pQuote', '\"',\r\n \t'pLegacy', 0\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will Export all Dimension elements in a Hierarchy to a File. Export file maintains\r\n# all data that can be used to completely reconstruct the dimension. Custom record delimiter\r\n# (specified by a character or its ASCII code) can be used.\r\n# __Format of the file:__ \r\n# - 1st line: File metadata contains summary information about the dimension, hierarchy, number of\r\n# elements and date/time when file was generated.\r\n# - 2nd line: Source dimension and hierarchy.\r\n# - 3rd line: Dimension sort order.\r\n# - 4th and 5th line: Reserved for future development.\r\n# - 6th line: Header for elements export.\r\n# - 7th line and forth: Elements export data.\r\n\r\n# Use case:\r\n# 1. Backup of dimension before changes in productive environment.\r\n# 2. Quick replication of a large dimension.\r\n\r\n# Note:\r\n# Valid dimension name (pDim), inclusion of header (pTitleRecord) and legacy export format (pLegacy)\r\n# are mandatory otherwise the process will abort.\r\n# If needed, custom delimiter might be used by specifying parameter pDelim value as either exactly one\r\n# character or as a 3-digit (decimal) ASCII code. For example to use TAB as a delimiter, use 009.\r\n\r\n# Caution: Process was redesigned in Bedrock4 but is able to process dimension extracts from prior\r\n# versions of Bedrock in legacy mode (pLegacy = 1).\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent= 'Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pHier:%pHier%, pTgtDir:%pTgtDir%, pTgtFile:%pTgtFile%, pTitleRecord:%pTitleRecord%, pDelim:%pDelim%, pQuote:%pQuote%, pLegacy:%pLegacy%.';\r\ncType = 'Type-';\r\ncParent = 'Parent-';\r\ncIndex = 'Index-';\r\ncWeight = 'Weight-';\r\ncAttrName = 'Attr Name-';\r\ncAttrValue = 'Attr Value-';\r\ncLenASCIICode = 3;\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pCharacterSet\": \"TM1CS_UTF8\",\r\n \"pDelim\": \"&\",\r\n \"pDim\": null,\r\n \"pHier\": \"\",\r\n \"pQuote\": \"\"\",\r\n \"pTgtDir\": \"\",\r\n \"pTgtFile\": \"\",\r\n \"pLegacy\": 0,\r\n \"pLogOutput\": 0,\r\n \"pStrictErrorHandling\": 0,\r\n \"pTitleRecord\": 1\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pCharacterSet\": '|StringToJson ( pCharacterSet )|',\r\n \"pDelim\": '|StringToJson ( pDelim )|',\r\n \"pDim\": '|StringToJson ( pDim )|',\r\n \"pHier\": '|StringToJson ( pHier )|',\r\n \"pQuote\": '|StringToJson ( pQuote )|',\r\n \"pTgtDir\": '|StringToJson ( pTgtDir )|',\r\n \"pTgtFile\": '|StringToJson ( pTgtFile )|',\r\n \"pLegacy\": '|NumberToString( pLegacy )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|',\r\n \"pTitleRecord\": '|NumberToString( pTitleRecord )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npCharacterSet = JsonToString( JsonGet( pJson, 'pCharacterSet' ) );\r\npDelim = JsonToString( JsonGet( pJson, 'pDelim' ) );\r\npDim = JsonToString( JsonGet( pJson, 'pDim' ) );\r\npHier = JsonToString( JsonGet( pJson, 'pHier' ) );\r\npQuote = JsonToString( JsonGet( pJson, 'pQuote' ) );\r\npTgtDir = JsonToString( JsonGet( pJson, 'pTgtDir' ) );\r\npTgtFile = JsonToString( JsonGet( pJson, 'pTgtFile' ) );\r\n# Numeric Parameters\r\npLegacy = StringToNumber( JsonToString( JsonGet( pJson, 'pLegacy' ) ) );\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\npTitleRecord = StringToNumber( JsonToString( JsonGet( pJson, 'pTitleRecord' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\npDelim = TRIM(pDelim);\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Initialise ###\r\nnRecordCount = 0;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\nIf( Scan( ':', pDim ) > 0 & pHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pHier = SubSt( pDim, Scan( ':', pDim ) + 1, Long( pDim ) );\r\n pDim = SubSt( pDim, 1, Scan( ':', pDim ) - 1 );\r\nEndIf;\r\n\r\n# Validate dimension\r\nIf( Trim( pDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( DimensionExists( pDim ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Dimension: ' | pDim | ' does not exist.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate Hierarchy\r\nIf( Trim( pHier ) @= '' );\r\n sHier = pDim;\r\nElse;\r\n sHier = pHier;\r\nEndIf;\r\n\r\nIf( HierarchyExists( pDim, sHier ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'The Hierachy ' | sHier | ' does not exist.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n## check operating system\r\nIf( SubSt( GetProcessErrorFileDirectory, 2, 1 ) @= ':' );\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nElseIf( Scan( '/', GetProcessErrorFileDirectory ) > 0 );\r\n sOS = 'Linux';\r\n sOSDelim = '/';\r\nElse;\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nEndIf;\r\n\r\n# Validate export path\r\nIf( Trim( pTgtDir ) @= '' );\r\n pTgtDir = GetProcessErrorFileDirectory;\r\n sMessage = 'Target folder defaulted to error file directory.';\r\n LogOutput( 'INFO', Expand( cMsgErrorContent ) );\r\nEndIf;\r\nIf( SubSt( pTgtDir, Long( pTgtDir ), 1 ) @= sOSDelim );\r\n pTgtDir = SubSt( pTgtDir, 1, Long( pTgtDir ) -1 );\r\nEndIf;\r\nIf( FileExists( pTgtDir ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid export path specified. Folder does not exist.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\npTgtDir = pTgtDir | sOSDelim;\r\n\r\n# Validate export filename\r\nIf( pTgtFile @= '' );\r\n pTgtFile = pDim | If( pLegacy = 1,'',' '|sHier ) | '_Export.csv';\r\nElseIf( Scan( '.', pTgtFile ) = 0 );\r\n # No file extension specified\r\n pTgtFile = pTgtFile | '.csv';\r\nEndIf;\r\n\r\n# Validate file delimiter & quote character\r\nIf( pDelim @= '' );\r\n pDelim = ',';\r\nElse;\r\n # If length of pDelim is exactly 3 chars and each of them is decimal digit, then the pDelim is entered as ASCII code\r\n nValid = 0;\r\n If ( LONG(pDelim) = cLenASCIICode );\r\n nChar = 1;\r\n While ( nChar <= cLenASCIICode );\r\n If( CODE( pDelim, nChar )>=CODE( '0', 1 ) & CODE( pDelim, nChar )<=CODE( '9', 1 ) );\r\n nValid = 1;\r\n Else;\r\n nValid = 0;\r\n EndIf;\r\n nChar = nChar + 1;\r\n End;\r\n EndIf;\r\n If ( nValid<>0 );\r\n pDelim=CHAR(StringToNumber( pDelim ));\r\n Else;\r\n pDelim = SubSt( Trim( pDelim ), 1, 1 );\r\n EndIf;\r\nEndIf;\r\nIf( pQuote @= '' );\r\n ## Use no quote character \r\nElse;\r\n # If length of pQuote is exactly 3 chars and each of them is decimal digit, then the pQuote is entered as ASCII code\r\n nValid = 0;\r\n If ( LONG(pQuote) = cLenASCIICode );\r\n nChar = 1;\r\n While ( nChar <= cLenASCIICode );\r\n If( CODE( pQuote, nChar ) >= CODE( '0', 1 ) & CODE( pQuote, nChar ) <= CODE( '9', 1 ) );\r\n nValid = 1;\r\n Else;\r\n nValid = 0;\r\n EndIf;\r\n nChar = nChar + 1;\r\n End;\r\n EndIf;\r\n If ( nValid<>0 );\r\n pQuote=CHAR(StringToNumber( pQuote ));\r\n Else;\r\n pQuote = SubSt( Trim( pQuote ), 1, 1 );\r\n EndIf;\r\nEndIf;\r\n\r\n# Validate Character Set\r\nIf(Trim( pCharacterSet ) @= '' );\r\n pCharacterSet = 'TM1CS_UTF8';\r\nEndIf;\r\n\r\n# Construct full export filename including path\r\nsFilename = pTgtDir | pTgtFile;\r\nsLocAttFile = 'Localized_' | pTgtFile;\r\nsAttrDimName = '}ElementAttributes_' | pDim ;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### Assign Data Source ###\r\nDatasourceNameForServer = pDim | IF(pHier@='','',':'|pHier) ;\r\nDatasourceNameForClient = DatasourceNameForServer ;\r\nDataSourceType = 'SUBSET';\r\nDatasourceDimensionSubset = 'ALL';\r\nDatasourceAsciiDelimiter= pDelim;\r\nDatasourceAsciiQuoteCharacter = pQuote;\r\n\r\n### End Prolog ###", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n# Set the output character set\r\nSetOutputCharacterSet( sFileName, pCharacterSet );\r\n\r\n### Record Count\r\nnRecordCount = nRecordCount + 1;\r\n\r\n### Export Header Information\r\n## Line 1: File Metadata information\r\nIf( nRecordCount = 1 & pTitleRecord = 1 );\r\n TextOutput( sFilename, 'Export from dimension Hierarchy: ' | pDim|':'|sHier | ', all elements in index order. Total elements=' |\r\n NumberToString( ElementCount( pDim, sHier ) ) | '. On ' | Date( Now, 1 ) | ' at ' | Time );\r\n\r\n## Line 2: Source Dimension\r\n TextOutput( sFilename, pDim, sHier );\r\n\r\n## Line 3: Sort Order Information\r\n# Placeholder as expecting a TI function to be made available to be able to read these properties\r\n# sSortElementType = CELLGETS( cCubeS1, pDim, 'SORTELEMENTSTYPE' );\r\n# sSortComponentType = CELLGETS( cCubeS1, pDim, 'SORTCOMPONENTSTYPE' );\r\n# sSortElementSense = CELLGETS( cCubeS1, pDim, 'SORTELEMENTSSENSE' );\r\n# sSortComponentSense = CELLGETS( cCubeS1, pDim, 'SORTCOMPONENTSSENSE' );\r\n# If( pLegacy = 1 );\r\n# TextOutput( sFilename, sSortElementType , sSortComponentType , sSortElementSense , sSortComponentSense );\r\n# Else;\r\n# TextOutput( sFilename, 'Sort parameters :', sSortElementType , sSortComponentType , sSortElementSense , sSortComponentSense );\r\n# EndIf;\r\n \r\n## Line 4 (and 5?): Header Information\r\n If( pLegacy = 1 );\r\n TextOutput( sFilename, 'Reserved' );\r\n EndIf;\r\n TextOutput( sFilename, 'Reserved' );\r\n \r\n## Line 5 or 6: Header Information\r\n TextOutput( sFilename, 'Line_Type', 'Element', 'Value_1', 'Value_2', 'Value_3' );\r\n\r\n### Attribute Information \r\n If( DimensionExists( sAttrDimName ) = 1 );\r\n nIndex = 1;\r\n nLimit = DIMSIZ ( sAttrDimName );\r\n WHILE( nIndex <= nLimit );\r\n sElName = DIMNM( sAttrDimName, nIndex );\r\n sElType = DTYPE( sAttrDimName, sElName);\r\n TextOutput( sFilename, 'A', sElName, sElType );\r\n nIndex = nIndex + 1;\r\n END; \r\n EndIf;\r\n# TextOutput( sFilename, '' );\r\nEndIf;\r\n\r\n### Element Information\r\nnElIndex = ElementIndex( pDim, sHier, vEle );\r\nsElType = ElementTYPE( pDim, sHier, vEle );\r\nTextOutput( sFilename,'E', vEle, If( pLegacy = 1,'', cType ) | sElType, If( pLegacy = 1,'', cIndex ) | NumberToString( nElIndex ) );\r\n\r\n### Element Parents\r\nnElPar = ElementParentCount( pDim, sHier, vEle );\r\nIF( nElPar > 0 );\r\n nIndex = 1;\r\n nLimit = nElPar;\r\n WHILE( nIndex <= nLimit );\r\n sElPar = ElementParent( pDim, sHier, vEle, nIndex );\r\n sElType = ElementTYPE( pDim, sHier, sElPar );\r\n nElWgt = ElementWeight( pDim, sHier, sElPar, vEle );\r\n TextOutput( sFilename, 'P', vEle, If( pLegacy = 1,'', cParent ) | sElPar, If( pLegacy = 1,'', cType ) | sElType, If( pLegacy = 1,'', cWeight ) | NumberToString( nElWgt ) );\r\n nIndex = nIndex + 1;\r\n END;\r\nENDIF;\r\n\r\n### Attribute Value \r\nIF( CubeExists(sAttrDimName) = 1 & DimensionExists(sAttrDimName) = 1 );\r\n nIndex = 1;\r\n nLimit = DIMSIZ( sAttrDimName );\r\n WHILE( nIndex <= nLimit );\r\n sElName = DIMNM( sAttrDimName, nIndex );\r\n sElType = DTYPE( sAttrDimName, sElName);\r\n IF( sElType @= 'AN' );\r\n nAttrValue = ElementAttrN( pDim , sHier , vEle , sElName );\r\n IF( nAttrValue <> 0 );\r\n sAttrValue = NumberToString( nAttrValue );\r\n TextOutput( sFilename, 'V', vEle, If( pLegacy = 1,'', cAttrName ) | sElName, If( pLegacy = 1,'', cAttrValue ) | sAttrValue );\r\n ENDIF;\r\n ELSE;\r\n sAttrValue = ElementAttrS( pDim , sHier , vEle , sElName ); \r\n IF( sAttrValue @<> '' );\r\n TextOutput( sFilename, 'V', vEle, If( pLegacy = 1,'', cAttrName ) | sElName, If( pLegacy = 1,'', cAttrValue ) | sAttrValue );\r\n ENDIF;\r\n ENDIF;\r\n\r\n nIndex = nIndex + 1;\r\n END;\r\nENDIF;\r\n\r\n### End Data ###", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n\r\n### If errors occurred terminate process with a major error status ###\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 major error and consequently aborted. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% aborted. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElseIf( CubeExists('}LocalizedElementAttributes_' | pDim) = 1 );\r\n # if attributes have been localized then export the cube (NOTE: values stored against C elements of alternate hierarchies will not be included in the file)\r\n ExecuteProcess('}bedrock.cube.data.export', 'pLogoutput', pLogoutput, 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pCube', '}LocalizedElementAttributes_' | pDim, 'pView', '', 'pFilter', '', 'pFilterParallel', '', 'pParallelThreads', 0,\r\n 'pDimDelim', '&', 'pEleStartDelim', '\u00a6', 'pEleDelim', '+',\r\n 'pSuppressZero', 1, 'pSuppressConsol', 0, 'pSuppressRules', 0, 'pSuppressConsolStrings', 0,\r\n 'pZeroSource', 0, 'pCubeLogging', 2, 'pTemp', 1, \r\n 'pFilePath', pTgtDir, 'pFileName', sLocAttFile,\r\n 'pDelim', pDelim, 'pDecimalSeparator', DatasourceASCIIDecimalSeparator, 'pThousandSeparator', DatasourceASCIIThousandSeparator, 'pQuote', pQuote,\r\n 'pTitleRecord', 1, 'pSandbox', '', 'pSubN', 0, 'pCharacterSet', '', 'pCubeNameExport', 1\r\n );\r\nEndIf;\r\n\r\n### Return Code\r\nsProcessAction = Expand( 'Process:%cThisProcName% successfully exported the %pDim%:%pHier% dimension:hierarchy to %sFileName%.' );\r\nsProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\nnProcessReturnCode = 1;\r\nIf ( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\nEndIf;\r\n\r\n### End Epilog ###", "HasSecurityAccess": true, - "UIData": "_ParameterConstraints=e30=\f", + "UIData": "", "DataSource": { "Type": "TM1DimensionSubset", "dataSourceNameForClient": "}Cubes", @@ -13,70 +13,76 @@ "subset": "All" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pDim", - "Prompt": "REQUIRED: Dimension", + "Prompt": "REQUIRED: Delimited list of dimensions", "Value": "", "Type": "String" }, { "Name": "pHier", - "Prompt": "OPTIONAL: Hierarchy (defaults to dimension name if blank)", + "Prompt": "OPTIONAL: Hierarchy name (Default = pDim)", "Value": "", "Type": "String" }, { "Name": "pTgtDir", - "Prompt": "OPTIONAL: Target Directory Path (defaults to Error File Directory)", + "Prompt": "OPTIONAL: Target file directory (Default = GetProcessErrorFileDirectory)", "Value": "", "Type": "String" }, { "Name": "pTgtFile", - "Prompt": "OPTIONAL: Target File Name (defaults to Dimension Hierarchy_Export.csv if blank)", + "Prompt": "OPTIONAL: Target file name (Default = pDim |' ' | pHier | '_Export.csv')", "Value": "", "Type": "String" }, { "Name": "pTitleRecord", - "Prompt": "REQUIRED: Boolean 1 = Yes - Include header row", + "Prompt": "OPTIONAL: Delete temporary view and subsets (0 = Retain View and Subsets, 1 = Delete View and Subsets, 2 = Delete View only. Default = 1)", "Value": 1, "Type": "Numeric" }, { "Name": "pDelim", - "Prompt": "OPTIONAL: AsciiOutput delimiter character (Default=comma, exactly 3 digits = ASCII code)", - "Value": ",", + "Prompt": "OPTIONAL: Delimiter for list parameters (Default = '&')", + "Value": "&", "Type": "String" }, { "Name": "pQuote", - "Prompt": "OPTIONAL: AsciiOutput quote character (Accepts empty quote, exactly 3 digits = ASCII code)", + "Prompt": "OPTIONAL: Quote character (2 or 3 digits = ASCII code. Default = '\"')", "Value": "\"", "Type": "String" }, { "Name": "pLegacy", - "Prompt": "REQUIRED: Boolean 1 = Legacy format", + "Prompt": "OPTIONAL: Use legacy format (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { "Name": "pCharacterSet", - "Prompt": "OPTIONAL: The output character set (defaults to TM1CS_UTF8 if blank)", - "Value": "", + "Prompt": "OPTIONAL: The output character set (Default = 'TM1CS_UTF8')", + "Value": "TM1CS_UTF8", + "Type": "String" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", "Type": "String" } ], @@ -89,7 +95,5 @@ "EndByte": 0 } ], - "VariablesUIData": [ - "VarType=32\fColType=827\f" - ] + "VariablesUIData": [] } \ No newline at end of file diff --git a/bedrock_processes_json/}bedrock.hier.export.script.json b/bedrock_processes_json/}bedrock.hier.export.script.json index e1c68ff..62838db 100644 --- a/bedrock_processes_json/}bedrock.hier.export.script.json +++ b/bedrock_processes_json/}bedrock.hier.export.script.json @@ -1,11 +1,11 @@ { "Name": "}bedrock.hier.export.script", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.export.script', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pDim', '', 'pEle', '', 'pDelim', '&', \r\n 'pTgtDir', '', 'pTitleRecord', 1,\r\n 'pDimInfo', 1, 'pAttr', 1, 'pAttrVal', 1, 'pSub', 0\r\n );\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process exports a dimension hierarchies as _TurboIntegrator script_. This is rather than creating a CSV which can be read by a generic \r\n# TurboIntegrator process this process creates a _**hardcoded**_ TurboIntegrator process to create a dimension/hierarchy complete with rollup \r\n# structure, attribute values, subsets and metadata information such as sort order, MDX hierarchy names and levels and captions.\r\n#\r\n# Use case:\r\n# The specific use case where this process will be useful is to automate the creation of TurboIntegrator script for promotion/migration purposes\r\n# as 100% stand-alone without need for data source o any parameters for the process. This can be useful in situations where DevOps has no file system access\r\n# to an environment and for manually defined dimensions such as measures.\r\n#\r\n# Note:\r\n# Several parameters control the scope of what is exported.\r\n# * pDim accepts wildcard and lists of dimensions and/or hierarchies to filter the **}Dimensions** dimension. There is no separate **pHier** parameter for this process\r\n# * pEle accepts wildcard and lists of _elements_. This can be used to limit the scope of the export of dimension structure and attribute values to a subset of elements\r\n# * pDimInfo 1/0 numeric Boolean whether to include metadata relevant to the dimensions/hierarchies defined in pDim from }DimensionProperties, }HierarchyProperties and }DimensionAttributes\r\n# * pAttr 1/0 numeric Boolean whether to include attribute creation\r\n# * pAttrVal 1/0 numeric Boolean whether to include attribute values (for the elements defined in pEle )\r\n# * pSub 1/0 numeric Boolean whether to include subset definitions for dynamic and static subsets\r\n# * There is no Boolean for exporting dimension structure, this is determined by pEle. To export all elements use pEle=\"*\". To suppress export of rollup structure (and attribute values) use pEle=\"\"\r\n# * 2 scripts are produced. One to copy/paste into prolog and one for epilog as Direct functions are not used for creation of elements and parent-child relationships\r\n#\r\n# Caution: \r\n# This process is designed for _**smaller (typically manually defined) dimensions**_. No check is implemented for upper limit of the set of elements defined by pEle if run on a large \r\n# dimension then the export script will be correspondingly large. \r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncTimeStampPrint = TimSt( Now, '\\Y-\\m-\\d \\h:\\i:\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent= 'Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pEle:%pEle%, pDelim:%pDelim%, pTgtDir:%pTgtDir%, pTgtFile:%pTgtFile%, pTitleRecord:%pTitleRecord%, pDimInfo:%pDimInfo%, pAttr:%pAttr%, pAttrVal:%pAttrVal%, pSub:%pSub%';\r\npDelim = Trim( pDelim );\r\ncLenASCIICode = 3;\r\ncHashLine = '#################################################################################################';\r\nsAttrDone = '';\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Initialise ###\r\nnRecordCount = 0;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\n## Validate Source dimension\r\nIF( Trim( pDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIF( Scan( '*', pDim ) = 0 & Scan( '?', pDim ) = 0 & Scan( pDelim, pDim ) = 0 & DimensionExists( pDim ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid dimension: ' | pDim;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate element\r\nIf( pEle @<> '');\r\n If( Scan( '*', pEle ) = 0 & Scan( '?', pEle ) = 0 & Scan( pDelim, pEle ) = 0 & DimIx( pDim, pEle ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Item ' | pEle | ' does NOT exist. Please enter a valid element in the ' |pDim| ' dimension.'; \r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n Endif;\r\nEndif;\r\n\r\n## check operating system\r\nIf( SubSt( GetProcessErrorFileDirectory, 2, 1 ) @= ':' );\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nElseIf( Scan( '/', GetProcessErrorFileDirectory ) > 0 );\r\n sOS = 'Linux';\r\n sOSDelim = '/';\r\nElse;\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nEndIf;\r\n\r\n# Validate export path\r\nIf( Trim( pTgtDir ) @= '' );\r\n pTgtDir = GetProcessErrorFileDirectory;\r\n sMessage = 'Target folder defaulted to error file directory.';\r\n LogOutput( 'INFO', Expand( cMsgErrorContent ) );\r\nEndIf;\r\nIf( SubSt( pTgtDir, Long( pTgtDir ), 1 ) @= sOSDelim );\r\n pTgtDir = SubSt( pTgtDir, 1, Long( pTgtDir ) -1 );\r\nEndIf;\r\nIf( FileExists( pTgtDir ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid export path specified. Folder does not exist.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\npTgtDir = pTgtDir | sOSDelim;\r\n\r\n# Validate export filename\r\nIf( pTgtFile @= '' );\r\n pTgtFile1 = 'bedrock_dimension_script_prolog.txt';\r\n pTgtFile2 = 'bedrock_dimension_script_epilog.txt';\r\nElse;\r\n If( SubSt( pTgtFile, Long( pTgtFile ) - 4, 1 ) @= '.' );\r\n pTgtFile = SubSt( pTgtFile, 1, Long( pTgtFile ) - 5 );\r\n EndIf;\r\n If( SubSt( pTgtFile, Long( pTgtFile ), 1 ) @= '_' );\r\n pTgtFile = SubSt( pTgtFile, 1, Long( pTgtFile ) - 1 );\r\n EndIf;\r\n pTgtFile1 = pTgtFile | '_prolog.txt';\r\n pTgtFile2 = pTgtFile | '_epilog.txt';\r\n\r\nEndIf;\r\n\r\n# Validate file delimiter & quote character\r\nIf( pDelim @= '' );\r\n pDelim = '&';\r\nElse;\r\n # If length of pDelim is exactly 3 chars and each of them is decimal digit, then the pDelim is entered as ASCII code\r\n nValid = 0;\r\n If ( LONG(pDelim) = cLenASCIICode );\r\n nChar = 1;\r\n While ( nChar <= cLenASCIICode );\r\n If( CODE( pDelim, nChar )>=CODE( '0', 1 ) & CODE( pDelim, nChar )<=CODE( '9', 1 ) );\r\n nValid = 1;\r\n Else;\r\n nValid = 0;\r\n EndIf;\r\n nChar = nChar + 1;\r\n End;\r\n EndIf;\r\n If ( nValid<>0 );\r\n pDelim = Char( StringToNumber( pDelim ) );\r\n Else;\r\n pDelim = SubSt( Trim( pDelim ), 1, 1 );\r\n EndIf;\r\nEndIf;\r\n\r\n# Validate Character Set\r\nIf(Trim( pCharacterSet ) @= '' );\r\n pCharacterSet = 'TM1CS_UTF8';\r\nEndIf;\r\n\r\n# Use no quote character \r\npQuote = '';\r\n\r\n# Construct full export filename including path\r\nsFileName = pTgtDir | pTgtFile1;\r\nsFileName2 = pTgtDir | pTgtFile2;\r\n\r\n# If blank delimiter specified then convert to default\r\nIf( pDelim @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n# Loop through dimensions in pDim\r\nsDims = pDim;\r\nnDimDelimiterIndex = 1;\r\nsMdx = '';\r\n# Get 1st dimension\r\nWhile( nDimDelimiterIndex <> 0 );\r\n # Extract 1st dimension > sDim\r\n nDimDelimiterIndex = Scan( pDelim, sDims );\r\n If( nDimDelimiterIndex = 0 );\r\n sDim = sDims;\r\n Else;\r\n sDim = Trim( SubSt( sDims, 1, nDimDelimiterIndex - 1 ) );\r\n sDims = Trim( Subst( sDims, nDimDelimiterIndex + Long(pDelim), Long( sDims ) ) );\r\n EndIf;\r\n \r\n # Create subset of dimensions using Wildcard to loop through dimensions in pDim with wildcard\r\n sDimExp = '\"'|sDim|'\"';\r\n sMdxPart = Expand('{TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions].[}Dimensions] ), %sDimExp% )}');\r\n If( sMdx @= ''); \r\n sMdx = sMdxPart; \r\n Else;\r\n sMdx = sMdx | ' + ' | sMdxPart;\r\n EndIf;\r\nEnd;\r\n\r\nIf( SubsetExists( '}Dimensions' , cTempSub ) = 1 );\r\n # If a delimited list of dim names includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( '}Dimensions' , cTempSub, sMDX );\r\nElse;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSub, sMDX, '}Dimensions' , 1 );\r\nEndIf;\r\n\r\n# Assign Data Source\r\nDataSourceType = 'SUBSET';\r\nDatasourceNameForServer = '}Dimensions';\r\nDatasourceDimensionSubset = cTempSub;\r\nDatasourceASCIIQuoteCharacter = pQuote;\r\n\r\n### End Prolog ###", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.export.script', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pDim', '', 'pEle', '', 'pDelim', '&', \r\n 'pTgtDir', '', 'pTitleRecord', 1,\r\n 'pDimInfo', 1, 'pAttr', 1, 'pAttrVal', 1, 'pSub', 0\r\n );\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process exports a dimension hierarchies as _TurboIntegrator script_. This is rather than creating a CSV which can be read by a generic \r\n# TurboIntegrator process this process creates a _**hardcoded**_ TurboIntegrator process to create a dimension/hierarchy complete with rollup \r\n# structure, attribute values, subsets and metadata information such as sort order, MDX hierarchy names and levels and captions.\r\n#\r\n# Use case:\r\n# The specific use case where this process will be useful is to automate the creation of TurboIntegrator script for promotion/migration purposes\r\n# as 100% stand-alone without need for data source o any parameters for the process. This can be useful in situations where DevOps has no file system access\r\n# to an environment and for manually defined dimensions such as measures.\r\n#\r\n# Note:\r\n# Several parameters control the scope of what is exported.\r\n# * pDim accepts wildcard and lists of dimensions and/or hierarchies to filter the **}Dimensions** dimension. There is no separate **pHier** parameter for this process\r\n# * pEle accepts wildcard and lists of _elements_. This can be used to limit the scope of the export of dimension structure and attribute values to a subset of elements\r\n# * pDimInfo 1/0 numeric Boolean whether to include metadata relevant to the dimensions/hierarchies defined in pDim from }DimensionProperties, }HierarchyProperties and }DimensionAttributes\r\n# * pAttr 1/0 numeric Boolean whether to include attribute creation\r\n# * pAttrVal 1/0 numeric Boolean whether to include attribute values (for the elements defined in pEle )\r\n# * pSub 1/0 numeric Boolean whether to include subset definitions for dynamic and static subsets\r\n# * There is no Boolean for exporting dimension structure, this is determined by pEle. To export all elements use pEle=\"*\". To suppress export of rollup structure (and attribute values) use pEle=\"\"\r\n# * 2 scripts are produced. One to copy/paste into prolog and one for epilog as Direct functions are not used for creation of elements and parent-child relationships\r\n#\r\n# Caution: \r\n# This process is designed for _**smaller (typically manually defined) dimensions**_. No check is implemented for upper limit of the set of elements defined by pEle if run on a large \r\n# dimension then the export script will be correspondingly large. \r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncTimeStampPrint = TimSt( Now, '\\Y-\\m-\\d \\h:\\i:\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent= 'Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pEle:%pEle%, pDelim:%pDelim%, pTgtDir:%pTgtDir%, pTgtFile:%pTgtFile%, pTitleRecord:%pTitleRecord%, pDimInfo:%pDimInfo%, pAttr:%pAttr%, pAttrVal:%pAttrVal%, pSub:%pSub%';\r\npDelim = Trim( pDelim );\r\ncLenASCIICode = 3;\r\ncHashLine = '#################################################################################################';\r\nsAttrDone = '';\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pCharacterSet\": \"TM1CS_UTF8\",\r\n \"pDelim\": \"&\",\r\n \"pDim\": null,\r\n \"pEle\": null,\r\n \"pTgtDir\": \"\",\r\n \"pTgtFile\": \"bedrock_dimension_script\",\r\n \"pAttr\": 1,\r\n \"pAttrVal\": 1,\r\n \"pDimInfo\": 1,\r\n \"pLogOutput\": 0,\r\n \"pStrictErrorHandling\": 0,\r\n \"pSub\": 0,\r\n \"pTitleRecord\": 1\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pCharacterSet\": '|StringToJson ( pCharacterSet )|',\r\n \"pDelim\": '|StringToJson ( pDelim )|',\r\n \"pDim\": '|StringToJson ( pDim )|',\r\n \"pEle\": '|StringToJson ( pEle )|',\r\n \"pTgtDir\": '|StringToJson ( pTgtDir )|',\r\n \"pTgtFile\": '|StringToJson ( pTgtFile )|',\r\n \"pAttr\": '|NumberToString( pAttr )|',\r\n \"pAttrVal\": '|NumberToString( pAttrVal )|',\r\n \"pDimInfo\": '|NumberToString( pDimInfo )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|',\r\n \"pSub\": '|NumberToString( pSub )|',\r\n \"pTitleRecord\": '|NumberToString( pTitleRecord )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npCharacterSet = JsonToString( JsonGet( pJson, 'pCharacterSet' ) );\r\npDelim = JsonToString( JsonGet( pJson, 'pDelim' ) );\r\npDim = JsonToString( JsonGet( pJson, 'pDim' ) );\r\npEle = JsonToString( JsonGet( pJson, 'pEle' ) );\r\npTgtDir = JsonToString( JsonGet( pJson, 'pTgtDir' ) );\r\npTgtFile = JsonToString( JsonGet( pJson, 'pTgtFile' ) );\r\n# Numeric Parameters\r\npAttr = StringToNumber( JsonToString( JsonGet( pJson, 'pAttr' ) ) );\r\npAttrVal = StringToNumber( JsonToString( JsonGet( pJson, 'pAttrVal' ) ) );\r\npDimInfo = StringToNumber( JsonToString( JsonGet( pJson, 'pDimInfo' ) ) );\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\npSub = StringToNumber( JsonToString( JsonGet( pJson, 'pSub' ) ) );\r\npTitleRecord = StringToNumber( JsonToString( JsonGet( pJson, 'pTitleRecord' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Initialise ###\r\nnRecordCount = 0;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\n## Validate Source dimension\r\nIF( Trim( pDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIF( Scan( '*', pDim ) = 0 & Scan( '?', pDim ) = 0 & Scan( pDelim, pDim ) = 0 & DimensionExists( pDim ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid dimension: ' | pDim;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate element\r\nIf( pEle @<> '');\r\n If( Scan( '*', pEle ) = 0 & Scan( '?', pEle ) = 0 & Scan( pDelim, pEle ) = 0 & DimIx( pDim, pEle ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Item ' | pEle | ' does NOT exist. Please enter a valid element in the ' |pDim| ' dimension.'; \r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n Endif;\r\nEndif;\r\n\r\n## check operating system\r\nIf( SubSt( GetProcessErrorFileDirectory, 2, 1 ) @= ':' );\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nElseIf( Scan( '/', GetProcessErrorFileDirectory ) > 0 );\r\n sOS = 'Linux';\r\n sOSDelim = '/';\r\nElse;\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nEndIf;\r\n\r\n# Validate export path\r\nIf( Trim( pTgtDir ) @= '' );\r\n pTgtDir = GetProcessErrorFileDirectory;\r\n sMessage = 'Target folder defaulted to error file directory.';\r\n LogOutput( 'INFO', Expand( cMsgErrorContent ) );\r\nEndIf;\r\nIf( SubSt( pTgtDir, Long( pTgtDir ), 1 ) @= sOSDelim );\r\n pTgtDir = SubSt( pTgtDir, 1, Long( pTgtDir ) -1 );\r\nEndIf;\r\nIf( FileExists( pTgtDir ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid export path specified. Folder does not exist.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\npTgtDir = pTgtDir | sOSDelim;\r\n\r\n# Validate export filename\r\nIf( pTgtFile @= '' );\r\n pTgtFile1 = 'bedrock_dimension_script_prolog.txt';\r\n pTgtFile2 = 'bedrock_dimension_script_epilog.txt';\r\nElse;\r\n If( SubSt( pTgtFile, Long( pTgtFile ) - 4, 1 ) @= '.' );\r\n pTgtFile = SubSt( pTgtFile, 1, Long( pTgtFile ) - 5 );\r\n EndIf;\r\n If( SubSt( pTgtFile, Long( pTgtFile ), 1 ) @= '_' );\r\n pTgtFile = SubSt( pTgtFile, 1, Long( pTgtFile ) - 1 );\r\n EndIf;\r\n pTgtFile1 = pTgtFile | '_prolog.txt';\r\n pTgtFile2 = pTgtFile | '_epilog.txt';\r\n\r\nEndIf;\r\n\r\n# Validate file delimiter & quote character\r\nIf( pDelim @= '' );\r\n pDelim = '&';\r\nElse;\r\n # If length of pDelim is exactly 3 chars and each of them is decimal digit, then the pDelim is entered as ASCII code\r\n nValid = 0;\r\n If ( LONG(pDelim) = cLenASCIICode );\r\n nChar = 1;\r\n While ( nChar <= cLenASCIICode );\r\n If( CODE( pDelim, nChar )>=CODE( '0', 1 ) & CODE( pDelim, nChar )<=CODE( '9', 1 ) );\r\n nValid = 1;\r\n Else;\r\n nValid = 0;\r\n EndIf;\r\n nChar = nChar + 1;\r\n End;\r\n EndIf;\r\n If ( nValid<>0 );\r\n pDelim = Char( StringToNumber( pDelim ) );\r\n Else;\r\n pDelim = SubSt( Trim( pDelim ), 1, 1 );\r\n EndIf;\r\nEndIf;\r\n\r\n# Validate Character Set\r\nIf(Trim( pCharacterSet ) @= '' );\r\n pCharacterSet = 'TM1CS_UTF8';\r\nEndIf;\r\n\r\n# Use no quote character \r\npQuote = '';\r\n\r\n# Construct full export filename including path\r\nsFileName = pTgtDir | pTgtFile1;\r\nsFileName2 = pTgtDir | pTgtFile2;\r\n\r\n# If blank delimiter specified then convert to default\r\nIf( pDelim @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n# Loop through dimensions in pDim\r\nsDims = pDim;\r\nnDimDelimiterIndex = 1;\r\nsMdx = '';\r\n# Get 1st dimension\r\nWhile( nDimDelimiterIndex <> 0 );\r\n # Extract 1st dimension > sDim\r\n nDimDelimiterIndex = Scan( pDelim, sDims );\r\n If( nDimDelimiterIndex = 0 );\r\n sDim = sDims;\r\n Else;\r\n sDim = Trim( SubSt( sDims, 1, nDimDelimiterIndex - 1 ) );\r\n sDims = Trim( Subst( sDims, nDimDelimiterIndex + Long(pDelim), Long( sDims ) ) );\r\n EndIf;\r\n \r\n # Create subset of dimensions using Wildcard to loop through dimensions in pDim with wildcard\r\n sDimExp = '\"'|sDim|'\"';\r\n sMdxPart = Expand('{TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions].[}Dimensions] ), %sDimExp% )}');\r\n If( sMdx @= ''); \r\n sMdx = sMdxPart; \r\n Else;\r\n sMdx = sMdx | ' + ' | sMdxPart;\r\n EndIf;\r\nEnd;\r\n\r\nIf( SubsetExists( '}Dimensions' , cTempSub ) = 1 );\r\n # If a delimited list of dim names includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( '}Dimensions' , cTempSub, sMDX );\r\nElse;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSub, sMDX, '}Dimensions' , 1 );\r\nEndIf;\r\n\r\n# Assign Data Source\r\nDataSourceType = 'SUBSET';\r\nDatasourceNameForServer = '}Dimensions';\r\nDatasourceDimensionSubset = cTempSub;\r\nDatasourceASCIIQuoteCharacter = pQuote;\r\n\r\n### End Prolog ###", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n# Set the output character set\r\nSetOutputCharacterSet( sFileName, pCharacterSet );\r\n\r\n### Record Count\r\nnRecordCount = nRecordCount + 1;\r\n\r\n### Set dimension & hierarchy variables\r\nIf( Scan( ':', vDim ) = 0 );\r\n sDim = vDim;\r\n sHier = vDim;\r\nElse;\r\n sDim = SubSt( vDim, 1, Scan( ':', vDim ) - 1 );\r\n sHier = SubSt( vDim, Scan( ':', vDim ) + 1, Long( vDim ) - ( Long( sDim ) + 1 ) );\r\nEndIf;\r\nsDimAttr = '}ElementAttributes_' | sDim;\r\nsDimSub = '}Subsets_' | sDim;\r\n\r\n### Export Header Information\r\nIf( nRecordCount = 1 & pTitleRecord = 1 );\r\n sHeader = Expand('# Export dimensions as script pDim=%pDim% pEle=%pEle% On %cTimeStampPrint%');\r\n TextOutput( sFileName, sHeader );\r\n If( ( pAttrVal = 1 & DimensionExists( sDimAttr ) = 1 & pEle @<> '' ) % ( pSub = 1 & DimensionExists( sDimSub ) = 1 ) );\r\n sHeader = Expand('# Export dimensions as script pDim=%pDim% pEle=%pEle% On %cTimeStampPrint%');\r\n TextOutput( sFileName2, sHeader );\r\n EndIf;\r\nEndIf;\r\n\r\n### Dimension write open\r\nTextOutput( sFileName, '' );\r\nTextOutput( sFileName, cHashLine );\r\nTextOutput( sFileName, Expand('#Region Dimension/Hierarchy: %vDim%') );\r\nIf( ( pAttrVal = 1 & DimensionExists( sDimAttr ) = 1 & pEle @<> '' ) % ( pSub = 1 & DimensionExists( sDimSub ) = 1 ) );\r\n TextOutput( sFileName2, '' );\r\n TextOutput( sFileName2, cHashLine );\r\n TextOutput( sFileName2, Expand('#Region Dimension/Hierarchy: %vDim% (EPILOG)') );\r\nEndIf;\r\n\r\n#################################################################################################\r\n#Region Create Dimension (PROLOG)\r\nTextOutput( sFileName, '' );\r\nTextOutput( sFileName, Expand('sDimHier = ''%vDim%'';') );\r\nTextOutput( sFileName, Expand('sDim = ''%sDim%'';') );\r\nTextOutput( sFileName, Expand('sHier = ''%sHier%'';') );\r\nTextOutput( sFileName, Expand('sDimAttr = ''%sDimAttr%'';') );\r\nTextOutput( sFileName, 'If( DimensionExists( sDim ) = 0 );');\r\nTextOutput( sFileName, ' DimensionCreate( sDim );');\r\nTextOutput( sFileName, ' If( sDim @<> sHier );');\r\nTextOutput( sFileName, ' HierarchyCreate( sDim, sHier );');\r\nTextOutput( sFileName, ' EndIf;' );\r\nTextOutput( sFileName, 'ElseIf( sDim @<> sHier );');\r\nTextOutput( sFileName, ' If( HierarchyExists( sDim, sHier ) = 0 );');\r\nTextOutput( sFileName, ' HierarchyCreate( sDim, sHier );');\r\nTextOutput( sFileName, ' EndIf;' );\r\nTextOutput( sFileName, 'EndIf;' );\r\n#EndRegion Create Dimension\r\n#################################################################################################\r\n\r\n#################################################################################################\r\n#Region Dimension Info (PROLOG)\r\nIf( pDimInfo = 1 );\r\n TextOutput( sFileName, '' );\r\n TextOutput( sFileName, cHashLine );\r\n TextOutput( sFileName, Expand('#Region Dimension Info: %vDim%') );\r\n# Placeholder as expecting a TI function to be made available to be able to read these properties\r\n# sSORTELEMENTSTYPE = CellGetS( '}DimensionProperties', vDim, 'SORTELEMENTSTYPE' );\r\n# sSORTCOMPONENTSTYPE = CellGetS( '}DimensionProperties', vDim, 'SORTCOMPONENTSTYPE' );\r\n# sSORTELEMENTSSENSE = CellGetS( '}DimensionProperties', vDim, 'SORTELEMENTSSENSE' );\r\n# sSORTCOMPONENTSSENSE= CellGetS( '}DimensionProperties', vDim, 'SORTCOMPONENTSSENSE' );\r\n# sDefHier = CellGetS( '}DimensionProperties', vDim, 'DEFAULT_HIERARCHY' );\r\n# sDefMember = CellGetS( '}HierarchyProperties', vDim, 'hierarchy0', 'defaultMember' );\r\n# sHierLevels = NumberToString( CellGetN( '}HierarchyProperties', vDim, 'hierarchy0', 'LevelsToHierarchize' ) );\r\n# sLevel000 = CellGetS( '}HierarchyProperties', vDim, 'hierarchy0', 'level000' );\r\n# sLevel001 = CellGetS( '}HierarchyProperties', vDim, 'hierarchy0', 'level001' );\r\n# sLevel002 = CellGetS( '}HierarchyProperties', vDim, 'hierarchy0', 'level002' );\r\n# sLevel003 = CellGetS( '}HierarchyProperties', vDim, 'hierarchy0', 'level003' );\r\n# sLevel004 = CellGetS( '}HierarchyProperties', vDim, 'hierarchy0', 'level004' );\r\n# sLevel005 = CellGetS( '}HierarchyProperties', vDim, 'hierarchy0', 'level005' );\r\n# sLevel006 = CellGetS( '}HierarchyProperties', vDim, 'hierarchy0', 'level006' );\r\n# sLevel007 = CellGetS( '}HierarchyProperties', vDim, 'hierarchy0', 'level007' );\r\n# sLevel008 = CellGetS( '}HierarchyProperties', vDim, 'hierarchy0', 'level008' );\r\n# sLevel009 = CellGetS( '}HierarchyProperties', vDim, 'hierarchy0', 'level009' );\r\n# sLevel010 = CellGetS( '}HierarchyProperties', vDim, 'hierarchy0', 'level010' );\r\n# sLevel011 = CellGetS( '}HierarchyProperties', vDim, 'hierarchy0', 'level011' );\r\n# sLevel012 = CellGetS( '}HierarchyProperties', vDim, 'hierarchy0', 'level012' );\r\n# sLevel013 = CellGetS( '}HierarchyProperties', vDim, 'hierarchy0', 'level013' );\r\n# sLevel014 = CellGetS( '}HierarchyProperties', vDim, 'hierarchy0', 'level014' );\r\n# sLevel015 = CellGetS( '}HierarchyProperties', vDim, 'hierarchy0', 'level015' );\r\n# sLevel016 = CellGetS( '}HierarchyProperties', vDim, 'hierarchy0', 'level016' );\r\n# sLevel017 = CellGetS( '}HierarchyProperties', vDim, 'hierarchy0', 'level017' );\r\n# sLevel018 = CellGetS( '}HierarchyProperties', vDim, 'hierarchy0', 'level018' );\r\n# sLevel019 = CellGetS( '}HierarchyProperties', vDim, 'hierarchy0', 'level019' );\r\n# sLevel020 = CellGetS( '}HierarchyProperties', vDim, 'hierarchy0', 'level020' );\r\n# TextOutput( sFileName, Expand('DimensionSortOrder( sDimHier, ''%sSORTCOMPONENTSTYPE%'', ''%sSORTCOMPONENTSSENSE%'', ''%sSORTELEMENTSTYPE%'', ''%sSORTELEMENTSSENSE%'' );') );\r\n# TextOutput( sFileName, Expand('CellPutS( ''%sDefHier%'', ''}DimensionProperties'', sDimHier, ''DEFAULT_HIERARCHY'' );') );\r\n# TextOutput( sFileName, Expand('CellPutS( ''%sDefMember%'', ''}HierarchyProperties'', sDimHier, ''hierarchy0'', ''defaultMember'' );') );\r\n# TextOutput( sFileName, Expand('CellPutN( %sHierLevels%, ''}HierarchyProperties'', sDimHier, ''hierarchy0'', ''LevelsToHierarchize'' );') );\r\n# nCtr = 0;\r\n# While( nCtr <= 20 );\r\n# sLvl = 'Level0' | If( nCtr < 10, '0', '' ) | NumberToString( nCtr ); \r\n# sLvlVal = Expand('%'| Expand('s%sLvl%') |'%');\r\n# If( sLvlVal @<> '' );\r\n# TextOutput( sFileName, Expand('CellPutS( ''%sLvlVal%'', ''}HierarchyProperties'', sDimHier, ''hierarchy0'', ''%sLvl%'' );') );\r\n# EndIf;\r\n# nCtr = nCtr + 1;\r\n# End;\r\n If( CubeExists( '}DimensionAttributes' ) = 1 );\r\n nCtr = 1;\r\n While( nCtr <= DimSiz( '}DimensionAttributes' ) );\r\n sAttr = DimNm( '}DimensionAttributes', nCtr );\r\n sAttrTyp = SubSt( DType( '}DimensionAttributes', sAttr ), 2, 1 );\r\n sAttrVal = If( sAttrTyp @= 'N', NumberToString( DimensionAttrN( vDim, sAttr ) ), DimensionAttrS( vDim, sAttr ) );\r\n TextOutput( sFileName, Expand('DimensionAttrInsert( '''', ''%sAttr%'', ''%sAttrTyp%'' );') );\r\n If( sAttrTyp @= 'N' );\r\n TextOutput( sFileName, Expand('DimensionAttrPutN( %sAttrVal%, sDimHier, ''%sAttr%'' );') );\r\n Else;\r\n TextOutput( sFileName, Expand('DimensionAttrPutS( ''%sAttrVal%'', sDimHier, ''%sAttr%'' );') );\r\n EndIf;\r\n nCtr = nCtr + 1;\r\n End;\r\n EndIf;\r\n TextOutput( sFileName, Expand('#EndRegion Dimension Info: %vDim%') );\r\n TextOutput( sFileName, cHashLine );\r\nEndIf;\r\n#EndRegion Dimension Info\r\n#################################################################################################\r\n\r\n#################################################################################################\r\n#Region Create Attributes (PROLOG)\r\nIf( pAttr = 1 & DimensionExists( sDimAttr ) = 1 & Scan( sDim|pDelim, sAttrDone ) = 0 );\r\n sAttrDone = sAttrDone | sDim | pDelim;\r\n TextOutput( sFileName, '' );\r\n TextOutput( sFileName, cHashLine );\r\n TextOutput( sFileName, Expand('#Region Create Attributes: %sDim%') );\r\n nCtr = 1;\r\n While( nCtr <= DimSiz( sDimAttr ) );\r\n sAttr = DimNm( sDimAttr, nCtr );\r\n sAttrTyp = SubSt( DType( sDimAttr, sAttr ), 2, 1 );\r\n # Escape potential single apostrophes to avoid parsing errors in attribute names\r\n nChar = 1;\r\n nCount = 0;\r\n sAttrStrOut = '';\r\n While( nChar <= LONG( sAttr ) + 1 );\r\n If( nChar <= LONG( sAttr ) );\r\n sChar = SUBST( sAttr, nChar, 1 );\r\n Else;\r\n sChar = '';\r\n EndIf;\r\n If( sChar @= '''' );\r\n nCount = nCount + 1;\r\n ElseIf( nCount > 0 );\r\n If( MOD( nCount, 2 ) <> 0 );\r\n sAttrStrOut = sAttrStrOut | '''';\r\n EndIf;\r\n nCount = 0;\r\n EndIf;\r\n sAttrStrOut = sAttrStrOut | sChar;\r\n nChar = nChar + 1;\r\n End;\r\n If( nCtr = 1 );\r\n TextOutput( sFileName, 'If( DimensionExists( sDimAttr ) = 0 % CubeExists( sDimAttr ) = 0 );');\r\n TextOutput( sFileName, Expand(' AttrInsert( sDim, '''', ''%sAttrStrOut%'', ''%sAttrTyp%'' );') );\r\n TextOutput( sFileName, 'EndIf;' );\r\n EndIf;\r\n TextOutput( sFileName, Expand('If( DimIx( sDimAttr, ''%sAttrStrOut%'' ) = 0 );') );\r\n TextOutput( sFileName, Expand(' AttrInsert( sDim, '''', ''%sAttrStrOut%'', ''%sAttrTyp%'' );') );\r\n TextOutput( sFileName, 'Else;' );\r\n TextOutput( sFileName, Expand(' If( DType( sDimAttr, ''%sAttrStrOut%'' ) @<> ''A%sAttrTyp%'' );') );\r\n TextOutput( sFileName, Expand(' AttrDelete( sDim, ''%sAttrStrOut%'' );') );\r\n TextOutput( sFileName, Expand(' AttrInsert( sDim, '''', ''%sAttrStrOut%'', ''%sAttrTyp%'' );') );\r\n TextOutput( sFileName, ' EndIf;' );\r\n TextOutput( sFileName, 'EndIf;' );\r\n nCtr = nCtr + 1;\r\n End;\r\n TextOutput( sFileName, Expand('#EndRegion Create Attributes: %sDim%') );\r\n TextOutput( sFileName, cHashLine );\r\nEndIf;\r\n#EndRegion Create Attributes\r\n#################################################################################################\r\n\r\n#################################################################################################\r\n#Region Create Dimension/Hierarchy Structure (PROLOG)\r\nIf( pEle @<> '' );\r\n sMDX = '';\r\n If( pEle @= '*' );\r\n sMDX = Expand('{TM1SubsetAll([%sDim%].[%sHier%])}');\r\n Else;\r\n # Loop through elements (inc. wildcard expressions) in pEle\r\n sEles = pEle;\r\n nEleDelimiterIndex = 1;\r\n # Get 1st ele\r\n While( nEleDelimiterIndex <> 0 );\r\n # Extract 1st ele in sEles\r\n nEleDelimiterIndex = Scan( pDelim, sEles );\r\n If( nEleDelimiterIndex = 0 );\r\n sEle = sEles;\r\n Else;\r\n sEle = Trim( SubSt( sEles, 1, nEleDelimiterIndex - 1 ) );\r\n sEles = Trim( Subst( sEles, nEleDelimiterIndex + Long( pDelim ), Long( sEles ) ) );\r\n EndIf;\r\n If( Scan( '*', sEle ) > 0 % Scan( '?', sEle ) > 0 );\r\n # Create MDX for subset of eles using Wildcard Pattern filter (means pEle entry MUST use principal name)\r\n sEleExp = '\"'|sEle|'\"';\r\n sMdxPart = Expand('{TM1FILTERBYPATTERN( TM1SUBSETALL( [%sDim%].[%sHier%] ), %sEleExp% )}');\r\n Else;\r\n # Create MDX of single element and all descendants\r\n sMDXPart = Expand('{TM1DRILLDOWNMEMBER( {[%sDim%].[%sHier%].[%sEle%]}, ALL, RECURSIVE )}');\r\n EndIf;\r\n If( sMDX @= ''); \r\n sMDX = sMdxPart; \r\n Else;\r\n sMDX = sMDX | ' + ' | sMdxPart;\r\n EndIf;\r\n End;\r\n EndIf;\r\n If( SubsetExists( vDim, cTempSub ) = 1 );\r\n SubsetMDXSet( vDim, cTempSub, sMDX );\r\n Else;\r\n SubsetCreatebyMDX( cTempSub, sMDX, vDim, 1 );\r\n EndIf;\r\n nMax = SubsetGetSize( vDim, cTempSub );\r\n If( nMax >= 1 );\r\n TextOutput( sFileName, '' );\r\n TextOutput( sFileName, cHashLine );\r\n TextOutput( sFileName, Expand('#Region Create Elements: %vDim%') );\r\n nCtr = 1;\r\n While( nCtr <= nMax );\r\n # 1st insert all elements to get correct order\r\n sEle = SubsetGetElementName( vDim, cTempSub, nCtr );\r\n # Escape potential single apostrophes to avoid parsing errors in element names\r\n nChar = 1;\r\n nCount = 0;\r\n sEleStrOut = '';\r\n While( nChar <= LONG( sEle ) + 1 );\r\n If( nChar <= LONG( sEle ) );\r\n sChar = SUBST( sEle, nChar, 1 );\r\n Else;\r\n sChar = '';\r\n EndIf;\r\n If( sChar @= '''' );\r\n nCount = nCount + 1;\r\n ElseIf( nCount > 0 );\r\n If( MOD( nCount, 2 ) <> 0 );\r\n sEleStrOut = sEleStrOut | '''';\r\n EndIf;\r\n nCount = 0;\r\n EndIf;\r\n sEleStrOut = sEleStrOut | sChar;\r\n nChar = nChar + 1;\r\n End;\r\n sEleTyp = DType( vDim, sEle );\r\n TextOutput( sFileName, Expand('DimensionElementInsert( sDimHier, '''', ''%sEleStrOut%'', ''%sEleTyp%'' );') );\r\n nCtr = nCtr + 1;\r\n End;\r\n nCtr = 1;\r\n While( nCtr <= nMax );\r\n # 2nd loop again and create parent linkages\r\n sEle = SubsetGetElementName( vDim, cTempSub, nCtr );\r\n # Escape potential single apostrophes to avoid parsing errors in element names\r\n nChar = 1;\r\n nCount = 0;\r\n sEleStrOut = '';\r\n While( nChar <= LONG( sEle ) + 1 );\r\n If( nChar <= LONG( sEle ) );\r\n sChar = SUBST( sEle, nChar, 1 );\r\n Else;\r\n sChar = '';\r\n EndIf;\r\n If( sChar @= '''' );\r\n nCount = nCount + 1;\r\n ElseIf( nCount > 0 );\r\n If( MOD( nCount, 2 ) <> 0 );\r\n sEleStrOut = sEleStrOut | '''';\r\n EndIf;\r\n nCount = 0;\r\n EndIf;\r\n sEleStrOut = sEleStrOut | sChar;\r\n nChar = nChar + 1;\r\n End;\r\n nPar = 1;\r\n While( nPar <= ElParN( vDim, sEle ) );\r\n sPar = ElPar( vDim, sEle, nPar );\r\n # Escape potential single apostrophes to avoid parsing errors in parent element names\r\n nChar = 1;\r\n nCount = 0;\r\n sParStrOut = '';\r\n While( nChar <= LONG( sPar ) + 1 );\r\n If( nChar <= LONG( sPar ) );\r\n sChar = SUBST( sPar, nChar, 1 );\r\n Else;\r\n sChar = '';\r\n EndIf;\r\n If( sChar @= '''' );\r\n nCount = nCount + 1;\r\n ElseIf( nCount > 0 );\r\n If( MOD( nCount, 2 ) <> 0 );\r\n sParStrOut = sParStrOut | '''';\r\n EndIf;\r\n nCount = 0;\r\n EndIf;\r\n sParStrOut = sParStrOut | sChar;\r\n nChar = nChar + 1;\r\n End;\r\n sWht = NumberToString( ElWeight( vDim, sPar, sEle ) );\r\n If( pEle @<> '*' );\r\n TextOutput( sFileName, Expand('DimensionElementInsert( sDimHier, '''', ''%sParStrOut%'', ''C'' );') );\r\n EndIf;\r\n TextOutput( sFileName, Expand('DimensionElementComponentAdd( sDimHier, ''%sParStrOut%'', ''%sEleStrOut%'', %sWht% );') );\r\n nPar = nPar + 1;\r\n End;\r\n nCtr = nCtr + 1;\r\n End;\r\n TextOutput( sFileName, Expand('#EndRegion Create Elements: %vDim%') );\r\n TextOutput( sFileName, cHashLine );\r\n EndIf;\r\nEndIf;\r\n#EndRegion Create Structure\r\n#################################################################################################\r\n\r\n#################################################################################################\r\n#Region Attribute Values (EPILOG)\r\nIf( pAttrVal = 1 & DimensionExists( sDimAttr ) = 1 & nMax >=1 );\r\n TextOutput( sFileName2, '' );\r\n TextOutput( sFileName2, cHashLine );\r\n TextOutput( sFileName2, Expand('#Region Attribute Values: %vDim%') );\r\n TextOutput( sFileName2, Expand('sDimHier = ''%vDim%'';') );\r\n TextOutput( sFileName2, Expand('sDim = ''%sDim%'';') );\r\n TextOutput( sFileName2, Expand('sHier = ''%sHier%'';') );\r\n TextOutput( sFileName2, Expand('sDimAttr = ''%sDimAttr%'';') );\r\n nCtr = 1;\r\n While( nCtr <= nMax );\r\n # loop elements again and internally loop attributes\r\n sEle = SubsetGetElementName( vDim, cTempSub, nCtr );\r\n # Escape potential single apostrophes to avoid parsing errors in element names\r\n nChar = 1;\r\n nCount = 0;\r\n sEleStrOut = '';\r\n While( nChar <= LONG( sEle ) + 1 );\r\n If( nChar <= LONG( sEle ) );\r\n sChar = SUBST( sEle, nChar, 1 );\r\n Else;\r\n sChar = '';\r\n EndIf;\r\n If( sChar @= '''' );\r\n nCount = nCount + 1;\r\n ElseIf( nCount > 0 );\r\n If( MOD( nCount, 2 ) <> 0 );\r\n sEleStrOut = sEleStrOut | '''';\r\n EndIf;\r\n nCount = 0;\r\n EndIf;\r\n sEleStrOut = sEleStrOut | sChar;\r\n nChar = nChar + 1;\r\n End;\r\n sEleTyp = DType( vDim, sEle );\r\n nAttr = 1;\r\n While( nAttr <= DimSiz( sDimAttr ) );\r\n sAttr = DimNm( sDimAttr, nAttr );\r\n # Escape potential single apostrophes to avoid parsing errors in attribute names\r\n nChar = 1;\r\n nCount = 0;\r\n sAttrStrOut = '';\r\n While( nChar <= LONG( sAttr ) + 1 );\r\n If( nChar <= LONG( sAttr ) );\r\n sChar = SUBST( sAttr, nChar, 1 );\r\n Else;\r\n sChar = '';\r\n EndIf;\r\n If( sChar @= '''' );\r\n nCount = nCount + 1;\r\n ElseIf( nCount > 0 );\r\n If( MOD( nCount, 2 ) <> 0 );\r\n sAttrStrOut = sAttrStrOut | '''';\r\n EndIf;\r\n nCount = 0;\r\n EndIf;\r\n sAttrStrOut = sAttrStrOut | sChar;\r\n nChar = nChar + 1;\r\n End;\r\n sAttrTyp = SubSt( DType( sDimAttr, sAttr ), 2, 1 );\r\n sAttrVal = '';\r\n If( ( sDim @<> sHier & sEleTyp @<> 'N' ) & sAttrTyp @= 'N' );\r\n sAttrVal= NumberToString( ElementAttrN( sDim, sHier, sEle, sAttr ) );\r\n ElseIf( sDim @<> sHier & sEleTyp @<> 'N' );\r\n sAttrVal= ElementAttrS( sDim, sHier, sEle, sAttr );\r\n ElseIf( sEleTyp @= 'N' & sAttrTyp @= 'N' & DimIx( sDim, sEle ) = 0 );\r\n sAttrVal= NumberToString( ElementAttrN( sDim, sHier, sEle, sAttr ) );\r\n ElseIf( sEleTyp @= 'N' & DimIx( sDim, sEle ) = 0 );\r\n sAttrVal= ElementAttrS( sDim, sHier, sEle, sAttr );\r\n ElseIf( sAttrTyp @= 'N' );\r\n sAttrVal= NumberToString( AttrN( sDim, sEle, sAttr ) );\r\n Else;\r\n sAttrVal= AttrS( sDim, sEle, sAttr );\r\n EndIf;\r\n sAttrValStrOut = '';\r\n If( sAttrVal @<> '' );\r\n If( sAttrTyp @<> 'N' );\r\n # Escape potential single apostrophes to avoid parsing errors in attribute values\r\n nChar = 1;\r\n nCount = 0;\r\n While( nChar <= LONG( sAttrVal ) + 1 );\r\n If( nChar <= LONG( sAttrVal ) );\r\n sChar = SUBST( sAttrVal, nChar, 1 );\r\n Else;\r\n sChar = '';\r\n EndIf;\r\n If( sChar @= '''' );\r\n nCount = nCount + 1;\r\n ElseIf( nCount > 0 );\r\n If( MOD( nCount, 2 ) <> 0 );\r\n sAttrValStrOut = sAttrValStrOut | '''';\r\n EndIf;\r\n nCount = 0;\r\n EndIf;\r\n sAttrValStrOut = sAttrValStrOut | sChar;\r\n nChar = nChar + 1;\r\n End;\r\n Else;\r\n # we won't need any tratment for non-string attributes\r\n sAttrValStrOut = sAttrVal;\r\n EndIf;\r\n If( ( sDim @<> sHier & sEleTyp @<> 'N' ) & sAttrTyp @= 'N' );\r\n TextOutput( sFileName2, Expand('ElementAttrPutN( %sAttrValStrOut%, sDim, sHier, ''%sEleStrOut%'', ''%sAttrStrOut%'' );') );\r\n ElseIf( sDim @<> sHier & sEleTyp @<> 'N' );\r\n TextOutput( sFileName2, Expand('ElementAttrPutS( ''%sAttrValStrOut%'', sDim, sHier, ''%sEleStrOut%'', ''%sAttrStrOut%'' );') );\r\n ElseIf( sEleTyp @= 'N' & sAttrTyp @= 'N' & DimIx( sDim, sEle ) = 0 );\r\n TextOutput( sFileName2, Expand('ElementAttrPutN( %sAttrValStrOut%, sDim, sHier, ''%sEleStrOut%'', ''%sAttrStrOut%'' );') );\r\n ElseIf( sEleTyp @= 'N' & DimIx( sDim, sEle ) = 0 );\r\n TextOutput( sFileName2, Expand('ElementAttrPutS( ''%sAttrValStrOut%'', sDim, sHier, ''%sEleStrOut%'', ''%sAttrStrOut%'' );') );\r\n ElseIf( sAttrTyp @= 'N' );\r\n TextOutput( sFileName2, Expand('AttrPutN( %sAttrValStrOut%, sDim, ''%sEleStrOut%'', ''%sAttrStrOut%'' );') );\r\n Else;\r\n TextOutput( sFileName2, Expand('AttrPutS( ''%sAttrValStrOut%'', sDim, ''%sEleStrOut%'', ''%sAttrStrOut%'' );') );\r\n EndIf;\r\n EndIf;\r\n nAttr = nAttr + 1;\r\n End;\r\n nCtr = nCtr + 1;\r\n End;\r\n TextOutput( sFileName2, Expand('#EndRegion Attribute Values: %vDim%') );\r\n TextOutput( sFileName2, cHashLine );\r\nEndIf;\r\n#EndRegion Attribute Values\r\n#################################################################################################\r\n\r\n#################################################################################################\r\n#Region Subsets (EPILOG)\r\nIf( pSub = 1 & DimensionExists( sDimSub ) = 1 );\r\n If( sDim @= vDim );\r\n sMDX = Expand('{Except( {TM1SubsetAll( [%sDimSub%] )}, {TM1FilterByPattern( {TM1SubsetAll( [%sDimSub%] )}, \"*:*\" )} )}');\r\n Else;\r\n sMDX = Expand('{TM1FilterByPattern( {TM1SubsetAll( [%sDimSub%] )}, \"%sHier%:*\" )}');\r\n EndIf;\r\n If( SubsetExists( sDimSub, cTempSub ) = 1 );\r\n SubsetMDXSet( sDimSub, cTempSub, sMDX );\r\n Else;\r\n SubsetCreatebyMDX( cTempSub, sMDX, sDimSub, 1 );\r\n EndIf;\r\n nMax = SubsetGetSize( sDimSub, cTempSub );\r\n If( nMax >= 1 );\r\n TextOutput( sFileName2, '' );\r\n TextOutput( sFileName2, cHashLine );\r\n TextOutput( sFileName2, Expand('#Region Subsets: %vDim%') );\r\n If( pAttrVal <> 1 % DimensionExists( sDimAttr ) = 0 % pEle @= '' );\r\n TextOutput( sFileName2, Expand('sDimHier = ''%vDim%'';') );\r\n TextOutput( sFileName2, Expand('sDim = ''%sDim%'';') );\r\n TextOutput( sFileName2, Expand('sHier = ''%sHier%'';') );\r\n TextOutput( sFileName2, Expand('sDimAttr = ''%sDimAttr%'';') );\r\n EndIf;\r\n nCtr = 1;\r\n While( nCtr <= nMax );\r\n sSub = SubsetGetElementName( sDimSub, cTempSub, nCtr );\r\n If( Scan( ':', sSub ) > 0 );\r\n sSub = SubSt( sSub, Scan( ':', sSub ) + 1, Long( sSub ) );\r\n EndIf;\r\n sMDX = SubsetMDXGet( vDim, sSub );\r\n # If MDX expression contains TM1SubsetBasis function then treat it as a static subset\r\n If( sMDX @<> '' & Scan( 'TM1SUBSETBASIS()', Upper( sMDX ) ) = 0 );\r\n # create by MDX\r\n TextOutput( sFileName2, Expand('If( SubsetExists( sDimHier, ''%sSub%'' ) = 0 );') );\r\n TextOutput( sFileName2, Expand(' SubsetCreatebyMDX( ''%sSub%'', ''%sMDX%'', sDimHier, 0 );') );\r\n TextOutput( sFileName2, 'Else;' );\r\n TextOutput( sFileName2, Expand(' SubsetMDXSet( sDimHier, ''%sSub%'', ''%sMDX%'' );') );\r\n TextOutput( sFileName2, 'EndIf;' );\r\n Else;\r\n # loop members\r\n TextOutput( sFileName2, Expand('If( SubsetExists( sDimHier, ''%sSub%'' ) = 0 );') );\r\n TextOutput( sFileName2, Expand(' SubsetCreate( sDimHier, ''%sSub%'' );') );\r\n TextOutput( sFileName2, 'Else;' );\r\n TextOutput( sFileName2, Expand(' SubsetDeleteAllElements( sDimHier, ''%sSub%'' );') );\r\n TextOutput( sFileName2, 'EndIf;' );\r\n nEles = SubsetGetSize( vDim, sSub );\r\n nEle = 1;\r\n While( nEle <= nEles );\r\n sEle = SubsetGetElementName( vDim, sSub, nEle );\r\n # Escape potential single apostrophes to avoid parsing errors in element names\r\n nChar = 1;\r\n nCount = 0;\r\n sEleStrOut = '';\r\n While( nChar <= LONG( sEle ) + 1 );\r\n If( nChar <= LONG( sEle ) );\r\n sChar = SUBST( sEle, nChar, 1 );\r\n Else;\r\n sChar = '';\r\n EndIf;\r\n If( sChar @= '''' );\r\n nCount = nCount + 1;\r\n ElseIf( nCount > 0 );\r\n If( MOD( nCount, 2 ) <> 0 );\r\n sEleStrOut = sEleStrOut | '''';\r\n EndIf;\r\n nCount = 0;\r\n EndIf;\r\n sEleStrOut = sEleStrOut | sChar;\r\n nChar = nChar + 1;\r\n End;\r\n TextOutput( sFileName2, Expand('SubsetElementInsert( sDimHier, ''%sSub%'', ''%sEleStrOut%'', 0 );') );\r\n nEle = nEle + 1;\r\n End;\r\n EndIf;\r\n nCtr = nCtr + 1;\r\n End;\r\n TextOutput( sFileName2, Expand('#EndRegion Subsets: %vDim%') );\r\n TextOutput( sFileName2, cHashLine );\r\n EndIf;\r\nEndIf;\r\n#EndRegion Subsets\r\n#################################################################################################\r\n\r\n### Dimension write close\r\nTextOutput( sFileName, '' );\r\nTextOutput( sFileName, Expand('#EndRegion Dimension/Hierarchy: %vDim%') );\r\nTextOutput( sFileName, cHashLine );\r\nIf( ( pAttrVal = 1 & DimensionExists( sDimAttr ) = 1 & pEle @<> '' ) % ( pSub = 1 & DimensionExists( sDimSub ) = 1 ) );\r\n TextOutput( sFileName2, '' );\r\n TextOutput( sFileName2, Expand('#EndRegion Dimension/Hierarchy: %vDim%') );\r\n TextOutput( sFileName2, cHashLine );\r\nEndIf;", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n\r\n### If errors occurred terminate process with a major error status ###\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 major error and consequently aborted. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% aborted. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nEndIf;\r\n\r\n### Return Code\r\nsProcessAction = Expand( 'Process:%cThisProcName% successfully exported %pDim% dimension:hierarchy to %sFileName%.' );\r\nsProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\nnProcessReturnCode = 1;\r\nIf ( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\nEndIf;\r\n\r\n### End Epilog ###", "HasSecurityAccess": true, - "UIData": "_ParameterConstraints=e30=\f", + "UIData": "", "DataSource": { "Type": "TM1DimensionSubset", "dataSourceNameForClient": "}Cubes", @@ -13,82 +13,88 @@ "subset": "All" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pDim", - "Prompt": "REQUIRED: Target Dimension or Hierarchy (as dim:hier), accepts wildcards (if = *, then all the dimensions)", + "Prompt": "REQUIRED: Delimited list of dimensions", "Value": "", "Type": "String" }, { "Name": "pEle", - "Prompt": "OPTIONAL: Target Element(s), accepts wildcards ( * will include ALL)", + "Prompt": "REQUIRED: Delimited list of elements", "Value": "", "Type": "String" }, { "Name": "pDelim", - "Prompt": "OPTIONAL: Delimiter character if list used for pDim, pHier or pEle", + "Prompt": "OPTIONAL: Delimiter for list parameters (Default = '&')", "Value": "&", "Type": "String" }, { "Name": "pTgtDir", - "Prompt": "OPTIONAL: Target Directory Path (defaults to Error File Directory if blank)", + "Prompt": "OPTIONAL: Target file directory (Default = GetProcessErrorFileDirectory)", "Value": "", "Type": "String" }, { "Name": "pTgtFile", - "Prompt": "OPTIONAL: Root file name without file extension. If blank \"bedrock_dimension_script\" will be used", - "Value": "", + "Prompt": "OPTIONAL: Root file name without file extension (Default = 'bedrock_dimension_script')", + "Value": "bedrock_dimension_script", "Type": "String" }, { "Name": "pTitleRecord", - "Prompt": "REQUIRED: Boolean 1 = Yes - Include header row", + "Prompt": "OPTIONAL: Delete temporary view and subsets (0 = Retain View and Subsets, 1 = Delete View and Subsets, 2 = Delete View only. Default = 1)", "Value": 1, "Type": "Numeric" }, { "Name": "pDimInfo", - "Prompt": "OPTIONAL: Include dimension info section (SortOrder, HierarchyProperties, etc.)", + "Prompt": "OPTIONAL: Include dimension info section (SortOrder, HierarchyProperties, etc.) (Boolean. Default = 1)", "Value": 1, "Type": "Numeric" }, { "Name": "pAttr", - "Prompt": "OPTIONAL: Include creation of attributes", + "Prompt": "OPTIONAL: Include creation of attributes (Boolean. Default = 1)", "Value": 1, "Type": "Numeric" }, { "Name": "pSub", - "Prompt": "OPTIONAL: Include subset definitions", + "Prompt": "OPTIONAL: Include subsets (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { "Name": "pAttrVal", - "Prompt": "OPTIONAL: Include attribute values (for selected elements in pEle)", + "Prompt": "OPTIONAL: Include attribute values (Boolean. Default = 1)", "Value": 1, "Type": "Numeric" }, { "Name": "pCharacterSet", - "Prompt": "OPTIONAL: The output character set (defaults to TM1CS_UTF8 if blank)", - "Value": "", + "Prompt": "OPTIONAL: The output character set (Default = 'TM1CS_UTF8')", + "Value": "TM1CS_UTF8", + "Type": "String" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", "Type": "String" } ], @@ -101,7 +107,5 @@ "EndByte": 0 } ], - "VariablesUIData": [ - "VarType=32\fColType=827\f" - ] + "VariablesUIData": [] } \ No newline at end of file diff --git a/bedrock_processes_json/}bedrock.hier.import.json b/bedrock_processes_json/}bedrock.hier.import.json index c492f2d..866a7a0 100644 --- a/bedrock_processes_json/}bedrock.hier.import.json +++ b/bedrock_processes_json/}bedrock.hier.import.json @@ -1,11 +1,11 @@ { "Name": "}bedrock.hier.import", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\nExecuteProcess( '}bedrock.hier.import', 'pLogOutput', pLogOutput\r\n , 'pStrictErrorHandling', pStrictErrorHandling\r\n , 'pDim', '', 'pHier', ''\r\n , 'pSrcDir', '', 'pSrcFile', ''\r\n , 'pDelim', ',', 'pQuote', '\"'\r\n , 'pLegacy', 0, 'pUnwind' , 1, 'pConsol', '*'\r\n);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will import Dimension elements into a specified Hierarchy from a File. The process\r\n# is able to read a file generated by `}bedrock.hier.export`.\r\n# __Format of the file:__ \r\n# - 1st line: File metadata contains summary information about the dimension, hierarchy, number of\r\n# elements and date/time when file was generated.\r\n# - 2nd line: Source dimension and hierarchy.\r\n# - 3rd line: Dimension sort order.\r\n# - 4th and 5th line: Reserved for future development.\r\n# - 6th line: Header for elements export.\r\n# - 7th line and forth: Elements export data.\r\n\r\n# Use case:\r\n# 1. Restore a dimension from a backup.\r\n# 2. Quick replication of a large dimension.\r\n\r\n# Note:\r\n# Valid dimension name (pDim) is mandatory otherwise the process will abort.\r\n# If needed, custom delimiter might be used by specifying parameter pDelim value as either exactly one\r\n# character or as a 3-digit (decimal) ASCII code. For example to use TAB as a delimiter, use 009.\r\n# pUnwind provides the option to 2 (do nothing of add only), 1 (unwind) or 0 (delete) elements in the target dimension. Default is to unwind,\r\n# care should be taken when using option 0 otherwise data loss may occur.\r\n\r\n# Caution: Process was redesigned in Bedrock4 but is able to process dimension extracts from prior\r\n# versions of Bedrock in legacy mode (pLegacy = 1).\r\n#EndRegion @DOC\r\n\r\n# This process will Create Dimension hierarchy from File.\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent= 'Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pHier:%pHier%, pSrcDir:%pSrcDir%, pSrcFile:%pSrcFile%, pDelim:%pDelim%, pQuote:%pQuote%, pLegacy:%pLegacy%, pUnwind:%pUnwind%, pConsol:%pConsol%';\r\ncLenASCIICode = 3;\r\n\r\npDelim = TRIM(pDelim);\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\nnMetaCount = 0;\r\nnDataCount = 0;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\nIf( Scan( ':', pDim ) > 0 & pHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pHier = SubSt( pDim, Scan( ':', pDim ) + 1, Long( pDim ) );\r\n pDim = SubSt( pDim, 1, Scan( ':', pDim ) - 1 );\r\nEndIf;\r\n\r\n# Validate dimension\r\nIf( Trim( pDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( DimensionExists( pDim ) = 0 );\r\n sMessage = 'Dimension: ' | pDim | ' does not exist and will be created.';\r\n LogOutput( 'INFO', Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate Hierarchy\r\nsHier = Trim( pHier );\r\nIf( sHier @= '' );\r\n sHier = pDim;\r\nElseIf( sHier @= 'Leaves' );\r\n If( pUnwind = 1 );\r\n pUnwind = 2;\r\n sMessage = Expand('%cThisProcName%: Leaves hierarchy, unwind is redundant. Changing unwind mode for %pDim%:%pHier% to 2.');\r\n LogOutput( 'INFO', sMessage );\r\n EndIf;\r\nEndIf;\r\n\r\n## check operating system\r\nIf( SubSt( GetProcessErrorFileDirectory, 2, 1 ) @= ':' );\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nElseIf( Scan( '/', GetProcessErrorFileDirectory ) > 0 );\r\n sOS = 'Linux';\r\n sOSDelim = '/';\r\nElse;\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nEndIf;\r\n\r\n## Validate source dir\r\nIf( Trim( pSrcDir ) @= '' );\r\n pSrcDir = GetProcessErrorFileDirectory;\r\n sMessage = 'Source folder defaulted to error file directory.';\r\n LogOutput( 'INFO', Expand( cMsgErrorContent ) );\r\nEndIf;\r\nIf( SubSt( pSrcDir, Long( pSrcDir ), 1 ) @= sOSDelim );\r\n pSrcDir = SubSt( pSrcDir, 1, Long( pSrcDir ) -1 );\r\nEndIf;\r\nIf( FileExists( pSrcDir ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid source path specified. Folder does not exist.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\npSrcDir = pSrcDir | sOSDelim;\r\n\r\n# Validate legacy file format\r\nIf( pLegacy <> 1 );\r\n pLegacy = 0;\r\nEndIf;\r\n\r\n# Validate export filename\r\nIf( pSrcFile @= '' );\r\n pSrcFile = pDim | If( pLegacy = 1, '', ' ' | sHier ) | '_Export.csv';\r\nElseIf( Scan( '.', pSrcFile ) = 0 );\r\n # No file extension specified\r\n pSrcFile = pSrcFile | '.csv';\r\nEndIf;\r\n\r\n# Construct full export filename including path\r\nsFilename = pSrcDir | pSrcFile;\r\nsLocAttFile = 'Localized_' | pSrcFile;\r\nsAttrDimName = '}ElementAttributes_' | pDim ;\r\n\r\nIf( FileExists( sFilename ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid path or file name specified. It does not exist.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate unwind\r\nIf( pUnwind <> 0 & pUnwind <> 2 );\r\n pUnwind = 1;\r\nEndIf;\r\n\r\n# Validate consolidation to unwind\r\nIf( pConsol @= '' );\r\n # Only check if parameter is passed as empty as this is invalid. Validation in case of element not existng in dimension will be evaluated in the unwind sub-process\r\n pConsol = '*';\r\nEndIf;\r\n\r\n# Validate file delimiter & quote character\r\nIf( pDelim @= '' );\r\n pDelim = ',';\r\nElse;\r\n # If length of pDelim is exactly 3 chars and each of them is decimal digit, then the pDelim is entered as ASCII code\r\n nValid = 0;\r\n If ( LONG(pDelim) = cLenASCIICode );\r\n nChar = 1;\r\n While ( nChar <= cLenASCIICode );\r\n If( CODE( pDelim, nChar )>=CODE( '0', 1 ) & CODE( pDelim, nChar )<=CODE( '9', 1 ) );\r\n nValid = 1;\r\n Else;\r\n nValid = 0;\r\n EndIf;\r\n nChar = nChar + 1;\r\n End;\r\n EndIf;\r\n If ( nValid<>0 );\r\n pDelim=CHAR(StringToNumber( pDelim ));\r\n Else;\r\n pDelim = SubSt( Trim( pDelim ), 1, 1 );\r\n EndIf;\r\nEndIf;\r\nIf( pQuote @= '' );\r\n ## Use no quote character \r\nElse;\r\n # If length of pQuote is exactly 3 chars and each of them is decimal digit, then the pQuote is entered as ASCII code\r\n nValid = 0;\r\n If ( LONG(pQuote) = cLenASCIICode );\r\n nChar = 1;\r\n While ( nChar <= cLenASCIICode );\r\n If( CODE( pQuote, nChar ) >= CODE( '0', 1 ) & CODE( pQuote, nChar ) <= CODE( '9', 1 ) );\r\n nValid = 1;\r\n Else;\r\n nValid = 0;\r\n EndIf;\r\n nChar = nChar + 1;\r\n End;\r\n EndIf;\r\n If ( nValid<>0 );\r\n pQuote=CHAR(StringToNumber( pQuote ));\r\n Else;\r\n pQuote = SubSt( Trim( pQuote ), 1, 1 );\r\n EndIf;\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### Prepare target dimension ###\r\nIf( HierarchyExists( pDim, sHier ) = 1 );\r\n If( pUnwind = 1 );\r\n ExecuteProcess('}bedrock.hier.unwind', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pDim', pDim,\r\n \t'pHier', sHier,\r\n \t'pConsol', pConsol,\r\n \t'pRecursive', 1\r\n );\r\n ElseIf( pUnwind = 0 );\r\n If( pDim @= sHier );\r\n DimensionDeleteAllElements( pDim );\r\n Else;\r\n HierarchyDeleteAllElements( pDim, pHier );\r\n EndIf;\r\n EndIf;\r\nElse;\r\n ExecuteProcess('}bedrock.hier.create',\r\n\t'pLogOutput',pLogOutput,\r\n\t'pStrictErrorHandling', pStrictErrorHandling,\r\n\t'pDim',pDim,\r\n\t'pHier',sHier);\r\nEndIf;\r\n\r\nIf( nErrors = 0 );\r\n If( HierarchyExists( pDim, sHier ) = 1 );\r\n IF ( pUnwind = 1 ) ;\r\n sMessage = 'Dimension unwound: ' | pDim|':'|sHier;\r\n ELSEIF ( pUnwind = 0 ) ;\r\n sMessage = 'Dimension rebuilt: ' | pDim|':'|sHier;\r\n ENDIF ;\r\n Else;\r\n sMessage = 'Dimension created: ' | pDim|':'|sHier;\r\n EndIf;\r\nElse;\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### CONSTANTS ###\r\nsAttrDimName = '}ElementAttributes_' | pDim ;\r\n\r\n#Processbreak;\r\n\r\n### Assign Datasource ###\r\nDataSourceType = 'CHARACTERDELIMITED';\r\nDatasourceNameForServer = sFilename;\r\nDatasourceNameForClient = sFilename;\r\nDatasourceAsciiDelimiter= pDelim;\r\nDatasourceAsciiQuoteCharacter = pQuote;\r\n\r\n##### End Prolog #####", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\nExecuteProcess( '}bedrock.hier.import', 'pLogOutput', pLogOutput\r\n , 'pStrictErrorHandling', pStrictErrorHandling\r\n , 'pDim', '', 'pHier', ''\r\n , 'pSrcDir', '', 'pSrcFile', ''\r\n , 'pDelim', ',', 'pQuote', '\"'\r\n , 'pLegacy', 0, 'pUnwind' , 1, 'pConsol', '*'\r\n);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will import Dimension elements into a specified Hierarchy from a File. The process\r\n# is able to read a file generated by `}bedrock.hier.export`.\r\n# __Format of the file:__ \r\n# - 1st line: File metadata contains summary information about the dimension, hierarchy, number of\r\n# elements and date/time when file was generated.\r\n# - 2nd line: Source dimension and hierarchy.\r\n# - 3rd line: Dimension sort order.\r\n# - 4th and 5th line: Reserved for future development.\r\n# - 6th line: Header for elements export.\r\n# - 7th line and forth: Elements export data.\r\n\r\n# Use case:\r\n# 1. Restore a dimension from a backup.\r\n# 2. Quick replication of a large dimension.\r\n\r\n# Note:\r\n# Valid dimension name (pDim) is mandatory otherwise the process will abort.\r\n# If needed, custom delimiter might be used by specifying parameter pDelim value as either exactly one\r\n# character or as a 3-digit (decimal) ASCII code. For example to use TAB as a delimiter, use 009.\r\n# pUnwind provides the option to 2 (do nothing of add only), 1 (unwind) or 0 (delete) elements in the target dimension. Default is to unwind,\r\n# care should be taken when using option 0 otherwise data loss may occur.\r\n\r\n# Caution: Process was redesigned in Bedrock4 but is able to process dimension extracts from prior\r\n# versions of Bedrock in legacy mode (pLegacy = 1).\r\n#EndRegion @DOC\r\n\r\n# This process will Create Dimension hierarchy from File.\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent= 'Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pHier:%pHier%, pSrcDir:%pSrcDir%, pSrcFile:%pSrcFile%, pDelim:%pDelim%, pQuote:%pQuote%, pLegacy:%pLegacy%, pUnwind:%pUnwind%, pConsol:%pConsol%';\r\ncLenASCIICode = 3;\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pConsol\": \"*\",\r\n \"pDelim\": \"&\",\r\n \"pDim\": null,\r\n \"pHier\": \"\",\r\n \"pQuote\": \"\"\",\r\n \"pSrcDir\": \"\",\r\n \"pSrcFile\": \"\",\r\n \"pLegacy\": 0,\r\n \"pLogOutput\": 0,\r\n \"pStrictErrorHandling\": 0,\r\n \"pUnwind\": 0\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pConsol\": '|StringToJson ( pConsol )|',\r\n \"pDelim\": '|StringToJson ( pDelim )|',\r\n \"pDim\": '|StringToJson ( pDim )|',\r\n \"pHier\": '|StringToJson ( pHier )|',\r\n \"pQuote\": '|StringToJson ( pQuote )|',\r\n \"pSrcDir\": '|StringToJson ( pSrcDir )|',\r\n \"pSrcFile\": '|StringToJson ( pSrcFile )|',\r\n \"pLegacy\": '|NumberToString( pLegacy )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|',\r\n \"pUnwind\": '|NumberToString( pUnwind )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npConsol = JsonToString( JsonGet( pJson, 'pConsol' ) );\r\npDelim = JsonToString( JsonGet( pJson, 'pDelim' ) );\r\npDim = JsonToString( JsonGet( pJson, 'pDim' ) );\r\npHier = JsonToString( JsonGet( pJson, 'pHier' ) );\r\npQuote = JsonToString( JsonGet( pJson, 'pQuote' ) );\r\npSrcDir = JsonToString( JsonGet( pJson, 'pSrcDir' ) );\r\npSrcFile = JsonToString( JsonGet( pJson, 'pSrcFile' ) );\r\n# Numeric Parameters\r\npLegacy = StringToNumber( JsonToString( JsonGet( pJson, 'pLegacy' ) ) );\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\npUnwind = StringToNumber( JsonToString( JsonGet( pJson, 'pUnwind' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\npDelim = TRIM(pDelim);\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\nnMetaCount = 0;\r\nnDataCount = 0;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\nIf( Scan( ':', pDim ) > 0 & pHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pHier = SubSt( pDim, Scan( ':', pDim ) + 1, Long( pDim ) );\r\n pDim = SubSt( pDim, 1, Scan( ':', pDim ) - 1 );\r\nEndIf;\r\n\r\n# Validate dimension\r\nIf( Trim( pDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( DimensionExists( pDim ) = 0 );\r\n sMessage = 'Dimension: ' | pDim | ' does not exist and will be created.';\r\n LogOutput( 'INFO', Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate Hierarchy\r\nsHier = Trim( pHier );\r\nIf( sHier @= '' );\r\n sHier = pDim;\r\nElseIf( sHier @= 'Leaves' );\r\n If( pUnwind = 1 );\r\n pUnwind = 2;\r\n sMessage = Expand('%cThisProcName%: Leaves hierarchy, unwind is redundant. Changing unwind mode for %pDim%:%pHier% to 2.');\r\n LogOutput( 'INFO', sMessage );\r\n EndIf;\r\nEndIf;\r\n\r\n## check operating system\r\nIf( SubSt( GetProcessErrorFileDirectory, 2, 1 ) @= ':' );\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nElseIf( Scan( '/', GetProcessErrorFileDirectory ) > 0 );\r\n sOS = 'Linux';\r\n sOSDelim = '/';\r\nElse;\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nEndIf;\r\n\r\n## Validate source dir\r\nIf( Trim( pSrcDir ) @= '' );\r\n pSrcDir = GetProcessErrorFileDirectory;\r\n sMessage = 'Source folder defaulted to error file directory.';\r\n LogOutput( 'INFO', Expand( cMsgErrorContent ) );\r\nEndIf;\r\nIf( SubSt( pSrcDir, Long( pSrcDir ), 1 ) @= sOSDelim );\r\n pSrcDir = SubSt( pSrcDir, 1, Long( pSrcDir ) -1 );\r\nEndIf;\r\nIf( FileExists( pSrcDir ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid source path specified. Folder does not exist.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\npSrcDir = pSrcDir | sOSDelim;\r\n\r\n# Validate legacy file format\r\nIf( pLegacy <> 1 );\r\n pLegacy = 0;\r\nEndIf;\r\n\r\n# Validate export filename\r\nIf( pSrcFile @= '' );\r\n pSrcFile = pDim | If( pLegacy = 1, '', ' ' | sHier ) | '_Export.csv';\r\nElseIf( Scan( '.', pSrcFile ) = 0 );\r\n # No file extension specified\r\n pSrcFile = pSrcFile | '.csv';\r\nEndIf;\r\n\r\n# Construct full export filename including path\r\nsFilename = pSrcDir | pSrcFile;\r\nsLocAttFile = 'Localized_' | pSrcFile;\r\nsAttrDimName = '}ElementAttributes_' | pDim ;\r\n\r\nIf( FileExists( sFilename ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid path or file name specified. It does not exist.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate unwind\r\nIf( pUnwind <> 0 & pUnwind <> 2 );\r\n pUnwind = 1;\r\nEndIf;\r\n\r\n# Validate consolidation to unwind\r\nIf( pConsol @= '' );\r\n # Only check if parameter is passed as empty as this is invalid. Validation in case of element not existng in dimension will be evaluated in the unwind sub-process\r\n pConsol = '*';\r\nEndIf;\r\n\r\n# Validate file delimiter & quote character\r\nIf( pDelim @= '' );\r\n pDelim = ',';\r\nElse;\r\n # If length of pDelim is exactly 3 chars and each of them is decimal digit, then the pDelim is entered as ASCII code\r\n nValid = 0;\r\n If ( LONG(pDelim) = cLenASCIICode );\r\n nChar = 1;\r\n While ( nChar <= cLenASCIICode );\r\n If( CODE( pDelim, nChar )>=CODE( '0', 1 ) & CODE( pDelim, nChar )<=CODE( '9', 1 ) );\r\n nValid = 1;\r\n Else;\r\n nValid = 0;\r\n EndIf;\r\n nChar = nChar + 1;\r\n End;\r\n EndIf;\r\n If ( nValid<>0 );\r\n pDelim=CHAR(StringToNumber( pDelim ));\r\n Else;\r\n pDelim = SubSt( Trim( pDelim ), 1, 1 );\r\n EndIf;\r\nEndIf;\r\nIf( pQuote @= '' );\r\n ## Use no quote character \r\nElse;\r\n # If length of pQuote is exactly 3 chars and each of them is decimal digit, then the pQuote is entered as ASCII code\r\n nValid = 0;\r\n If ( LONG(pQuote) = cLenASCIICode );\r\n nChar = 1;\r\n While ( nChar <= cLenASCIICode );\r\n If( CODE( pQuote, nChar ) >= CODE( '0', 1 ) & CODE( pQuote, nChar ) <= CODE( '9', 1 ) );\r\n nValid = 1;\r\n Else;\r\n nValid = 0;\r\n EndIf;\r\n nChar = nChar + 1;\r\n End;\r\n EndIf;\r\n If ( nValid<>0 );\r\n pQuote=CHAR(StringToNumber( pQuote ));\r\n Else;\r\n pQuote = SubSt( Trim( pQuote ), 1, 1 );\r\n EndIf;\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### Prepare target dimension ###\r\nIf( HierarchyExists( pDim, sHier ) = 1 );\r\n If( pUnwind = 1 );\r\n ExecuteProcess('}bedrock.hier.unwind', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pDim', pDim,\r\n \t'pHier', sHier,\r\n \t'pConsol', pConsol,\r\n \t'pRecursive', 1\r\n );\r\n ElseIf( pUnwind = 0 );\r\n If( pDim @= sHier );\r\n DimensionDeleteAllElements( pDim );\r\n Else;\r\n HierarchyDeleteAllElements( pDim, pHier );\r\n EndIf;\r\n EndIf;\r\nElse;\r\n ExecuteProcess('}bedrock.hier.create',\r\n\t'pLogOutput',pLogOutput,\r\n\t'pStrictErrorHandling', pStrictErrorHandling,\r\n\t'pDim',pDim,\r\n\t'pHier',sHier);\r\nEndIf;\r\n\r\nIf( nErrors = 0 );\r\n If( HierarchyExists( pDim, sHier ) = 1 );\r\n IF ( pUnwind = 1 ) ;\r\n sMessage = 'Dimension unwound: ' | pDim|':'|sHier;\r\n ELSEIF ( pUnwind = 0 ) ;\r\n sMessage = 'Dimension rebuilt: ' | pDim|':'|sHier;\r\n ENDIF ;\r\n Else;\r\n sMessage = 'Dimension created: ' | pDim|':'|sHier;\r\n EndIf;\r\nElse;\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### CONSTANTS ###\r\nsAttrDimName = '}ElementAttributes_' | pDim ;\r\n\r\n#Processbreak;\r\n\r\n### Assign Datasource ###\r\nDataSourceType = 'CHARACTERDELIMITED';\r\nDatasourceNameForServer = sFilename;\r\nDatasourceNameForClient = sFilename;\r\nDatasourceAsciiDelimiter= pDelim;\r\nDatasourceAsciiQuoteCharacter = pQuote;\r\n\r\n##### End Prolog #####", "MetadataProcedure": "#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\nIf( pDim @= sHier);\r\n sDim = pDim;\r\nElse;\r\n sDim = pDim|':'|sHier;\r\nEndif;\r\n\r\n### Metadata Count\r\nnMetaCount = nMetaCount + 1;\r\n\r\nsVar1 = v1;\r\nsVar2 = v2;\r\nsVar3 = If( pLegacy <> 1, Subst( v3 , Scan( '-' , v3 ) + 1 , Long( v3 ) ), v3 );\r\nsVar4 = If( pLegacy <> 1, Subst( v4 , Scan( '-' , v4 ) + 1 , Long( v4 ) ), v4 );\r\nsVar5 = If( pLegacy <> 1, Subst( v5 , Scan( '-' , v5 ) + 1 , Long( v5 ) ), v5 );\r\n\r\n# Placeholder as expecting a TI function to be made available to be able to read & modify these properties\r\n### Set Dimension Sort Order\r\n#IF( v1 @= 'Sort parameters :' );\r\n# CELLPUTS( sVar2, cCubeS1 , sDim, 'SORTELEMENTSTYPE' );\r\n# CELLPUTS( sVar3, cCubeS1 , sDim, 'SORTCOMPONENTSTYPE' );\r\n# CELLPUTS( sVar4, cCubeS1 , sDim, 'SORTELEMENTSSENSE' );\r\n# CELLPUTS( sVar5, cCubeS1 , sDim, 'SORTCOMPONENTSSENSE' );\r\n# DimensionSortOrder( sDim, sVar3, sVar5, sVar2, sVar4 );\r\n#ElseIF( pLegacy = 1 & nDataCount = 3 & ( sVar1 @= 'BYINPUT' % sVar1 @= 'BYNAME' % sVar1 @= 'BYHIERARCHY' % sVar1 @= 'BYLEVEL' ) );\r\n# CELLPUTS( sVar1, cCubeS1 , sDim, 'SORTELEMENTSTYPE' );\r\n# CELLPUTS( sVar2, cCubeS1 , sDim, 'SORTCOMPONENTSTYPE' );\r\n# CELLPUTS( sVar3, cCubeS1 , sDim, 'SORTELEMENTSSENSE' );\r\n# CELLPUTS( sVar4, cCubeS1 , sDim, 'SORTCOMPONENTSSENSE' );\r\n# DimensionSortOrder( sDim, sVar2, sVar4, sVar1, sVar3 );\r\n#ENDIF;\r\n\r\n### Build dimension\r\nIF( V1 @= 'A' );\r\n # insert attributes\r\n ATTRINSERT( pDim, '', sVar2 , SUBST( sVar3, 2, 1 ) );\r\n IF( pLogOutput = 1 );\r\n sMessage = Expand('Attribute %sVar2% created in %sDim% as type %sVar3%.');\r\n LogOutput( 'INFO', Expand( cMsgErrorContent ) ); \r\n ENDIF;\r\nELSEIF( V1 @= 'E' );\r\n # insert elements\r\n If( sHier @= 'Leaves' & sVar3 @<> 'N' );\r\n IF( pLogOutput = 1 );\r\n sMessage = Expand('Invalid element type %sVar3% for Leaves hierachy. Skipping insertion of element %sVar2%.');\r\n LogOutput( 'INFO', Expand( cMsgErrorContent ) ); \r\n ENDIF;\r\n ItemSkip;\r\n EndIf;\r\n HierarchyElementInsert( pDim, sHier, '', sVar2 , sVar3 );\r\n IF( pLogOutput = 1 );\r\n sMessage = Expand('Inserted element %sVar2% into %sDim% as type %sVar3%.');\r\n LogOutput( 'INFO', Expand( cMsgErrorContent ) ); \r\n ENDIF;\r\nELSEIF( V1 @= 'P' );\r\n # create rollups\r\n If( sHier @= 'Leaves' );\r\n IF( pLogOutput = 1 );\r\n sMessage = Expand('Leaves hierarchy! Skipping mapping of %sVar2% into parent %sVar3%.');\r\n LogOutput( 'INFO', Expand( cMsgErrorContent ) ); \r\n ENDIF;\r\n ItemSkip;\r\n EndIf;\r\n HierarchyElementInsert( pDim, sHier, '', sVar3 , sVar4 );\r\n HierarchyElementComponentAdd( pDim, sHier, sVar3 , sVar2 , StringToNumber( sVar5 ) );\r\n IF( pLogOutput = 1 );\r\n sMessage = Expand('Inserted parent %sVar3% into %sDim% as type %sVar4%. Then added %sVar2% to %sVar3% with a weight of %sVar5%.');\r\n sMessage = Expand('Added %sVar2% to %sVar3% with a weight of %sVar5%.');\r\n LogOutput( 'INFO', Expand( cMsgErrorContent ) ); \r\n ENDIF;\r\nENDIF;", "DataProcedure": "#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### Data Count\r\nnDataCount = nDataCount + 1;\r\n\r\nsVar1 = v1;\r\nsVar2 = v2;\r\nsVar3 = If( pLegacy <> 1, Subst( v3 , Scan( '-' , v3 ) + 1 , Long( v3 ) ), v3 );\r\nsVar4 = If( pLegacy <> 1, Subst( v4 , Scan( '-' , v4 ) + 1 , Long( v4 ) ), v4 );\r\nsVar5 = If( pLegacy <> 1, Subst( v5 , Scan( '-' , v5 ) + 1 , Long( v5 ) ), v5 );\r\n\r\nIf( pDim @= sHier);\r\n sDim = pDim;\r\nElse;\r\n sDim = pDim|':'|sHier;\r\nEndif;\r\n\r\n### Load Attribute Values ###\r\nIF( V1 @= 'V' );\r\n sAttrType = DTYPE( sAttrDimName , sVar3 );\r\n IF ( pDim @<> sHier );\r\n IF ( CellIsUpdateable ( '}ElementAttributes_' | pDim, sHier:sVar2, sVar3 ) = 0 ) ;\r\n ItemSkip ;\r\n ENDIF ;\r\n IF( sAttrType @= 'AN' );\r\n ElementAttrPUTN( StringToNumber( sVar4 ), pDim, sHier, sVar2, sVar3 );\r\n ELSEIF( sAttrType @= 'AA' );\r\n ElementATTRPUTS( sVar4, pDim, sHier, sVar2, sVar3, 1 );\r\n ELSE;\r\n ElementATTRPUTS( sVar4, pDim, sHier, sVar2, sVar3 );\r\n ENDIF;\r\n ELSE;\r\n IF ( CellIsUpdateable ( '}ElementAttributes_' | pDim , sVar2, sVar3 ) = 0 ) ;\r\n ItemSkip ;\r\n ENDIF ;\r\n IF( sAttrType @= 'AN' );\r\n AttrPUTN( StringToNumber( sVar4 ), pDim, sVar2, sVar3 );\r\n ELSEIF( sAttrType @= 'AA' );\r\n ATTRPUTS( sVar4, pDim, sVar2, sVar3, 1 );\r\n ELSE;\r\n ATTRPUTS( sVar4, pDim, sVar2, sVar3 );\r\n ENDIF; \r\n ENDIF;\r\nENDIF;", "EpilogProcedure": "#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n### If errors occurred terminate process with a major error status ###\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 major error and consequently aborted. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% aborted. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElseIf( FileExists(pSrcDir | sLocAttFile) = 1 );\r\n # If dimension is localized check for presence of localized attribute file and if it exists load it\r\n If( CubeExists('}LocalizedElementAttributes_' | pDim) = 0 );\r\n # Need to create attribute cube via AttrPut with locale code should it not exist\r\n nAttr = 1; nMax = DimSiz(sAttrDimName);\r\n While( nAttr <= nMax );\r\n sAttr = DimNm(sAttrDimName, nAttr);\r\n If( DType(sAttrDimName, sAttr) @= 'AA' % DType(sAttrDimName, sAttr) @= 'AS' );\r\n AttrPutS(AttrS(pDim, DimNm(pDim, 1), sAttr), pDim, DimNm(pDim, 1), sAttr, 'en');\r\n Break;\r\n EndIf;\r\n nAttr = nAttr + 1;\r\n End;\r\n EndIf;\r\n # proceed with loading localized values\r\n ExecuteProcess('}bedrock.cube.data.import', 'pLogOutput', pLogOutput, 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pCube', '}LocalizedElementAttributes_' | pDim, 'pSrcDir', pSrcDir, 'pSrcFile', sLocAttFile,\r\n 'pDim', '', 'pSrcEle', '', 'pTgtEle', '', 'pTitleRows', 1,\r\n 'pDelim', pDelim, 'pQuote', pQuote, 'pDecimalSeparator', DatasourceASCIIDecimalSeparator, 'pThousandSeparator', DatasourceASCIIThousandSeparator, \r\n 'pCumulate', 0, 'pCubeLogging', 2, 'pSandbox', '', 'pZeroFilter', 0, 'pMappingToNewDims', '',\r\n 'pDimDelim', '&', 'pEleStartDelim', '\u00a6', 'pEleDelim', '+',\r\n 'pCharacterSet', '', 'pFileDelete', 0, 'pSkipInvalidRecords', 1\r\n );\r\nEndIf;\r\n\r\n### Return Code\r\nsProcessAction = Expand( 'Process:%cThisProcName% successfully imported data from %sFileName% and updated the %pDim%:%pHier% dimension:hierarchy.' );\r\nsProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\nnProcessReturnCode = 1;\r\nIf ( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\nEndIf;\r\n\r\n### End Epilog ###", "HasSecurityAccess": true, - "UIData": "_ParameterConstraints=e30=\f", + "UIData": "", "DataSource": { "Type": "ASCII", "asciiDecimalSeparator": ".", @@ -14,75 +14,81 @@ "asciiHeaderRecords": 0, "asciiQuoteCharacter": "\"", "asciiThousandSeparator": ",", - "dataSourceNameForClient": "D:\\TM1Models\\Bedrock.v4\\Log\\Currency Currency 2_Export.csv", + "dataSourceNameForClient": "D:/TM1Models/Bedrock.v4/Log/Currency Currency 2_Export.csv", "dataSourceNameForServer": "D:/TM1Models/Bedrock.v4/Log/Currency Currency 2_Export.csv" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pDim", - "Prompt": "REQUIRED: Dimension", + "Prompt": "REQUIRED: Delimited list of dimensions", "Value": "", "Type": "String" }, { "Name": "pHier", - "Prompt": "OPTIONAL: Target Hierarchy (defaults to dimension name if blank)", + "Prompt": "OPTIONAL: Hierarchy name (Default = pDim)", "Value": "", "Type": "String" }, { "Name": "pSrcDir", - "Prompt": "OPTIONAL: Source Directory Path (defaults to Error File Directory)", + "Prompt": "OPTIONAL: File directory (Default = GetProcessErrorFileDirectory)", "Value": "", "Type": "String" }, { "Name": "pSrcFile", - "Prompt": "OPTIONAL: Source File Name (defaults to 'Dimension Hierarchy _Export.csv' if blank)", + "Prompt": "OPTIONAL: File name (Default = pCube | '_Export.csv')", "Value": "", "Type": "String" }, { "Name": "pDelim", - "Prompt": "OPTIONAL: AsciiOutput delimiter character (Default=comma, exactly 3 digits = ASCII code)", - "Value": ",", + "Prompt": "OPTIONAL: Delimiter for list parameters (Default = '&')", + "Value": "&", "Type": "String" }, { "Name": "pQuote", - "Prompt": "OPTIONAL: AsciiOutput quote character (Accepts empty quote, exactly 3 digits = ASCII code)", + "Prompt": "OPTIONAL: Quote character (2 or 3 digits = ASCII code. Default = '\"')", "Value": "\"", "Type": "String" }, { "Name": "pLegacy", - "Prompt": "OPTIONAL: 1 = Legacy format (bedrock v3) 0 or empty = new bedrock v4 format", + "Prompt": "OPTIONAL: Use legacy format (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { "Name": "pUnwind", - "Prompt": "OPTIONAL: 1 = unwind elements 0 = like for like copy which may result in lost elements / data (2= no clear or unwind, only add)", - "Value": 1, + "Prompt": "OPTIONAL: Unwind target hierarchy before process (0 = Delete all elements, 1 = Unwind existing elements, 2 = Do not change existing elements. Default = 0)", + "Value": 0, "Type": "Numeric" }, { "Name": "pConsol", - "Prompt": "OPTIONAL: Target Consolidation, accepts wildcards ( * will unwind ALL). Note: ignored if pUnwind=0", + "Prompt": "OPTIONAL: Delimited list of target consolidations for Unwinding (Default = '*')", "Value": "*", "Type": "String" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [ diff --git a/bedrock_processes_json/}bedrock.hier.leaves.orphan.check.json b/bedrock_processes_json/}bedrock.hier.leaves.orphan.check.json index e4aa4fe..e6dff5b 100644 --- a/bedrock_processes_json/}bedrock.hier.leaves.orphan.check.json +++ b/bedrock_processes_json/}bedrock.hier.leaves.orphan.check.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.hier.leaves.orphan.check", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.leaves.orphan.check', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pDim', '', 'pHier', '*',\r\n \t'pTgtSubLeaves', 'Bedrock - Orphan Elements - Leaves',\r\n \t'pIncludeNoParentElems', 0,\r\n \t'pTgtSubNoParents', 'Bedrock - No Parents',\r\n \t'pDelim', '&' \r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process checks all leaf elements (in the Leaves hierarchy) of the specified dimension(s).\r\n# Within the Leaves hierarchy for each element *all hierarchies* are scanned for the existance of the leaf element.\r\n# If the leaf element does not exist in all hierarchies except for Leaves then the element is classified as an orphan and added to the \r\n# \"Orphan Leaf Elements\" subset.\r\n# Additionally when running with pIncludeNoParentElems parameter set, elements that have no parent will be stored in No Parents subset\r\n# of matching hierarchy (except `Leaves`) within Leaves. The subset name might be accomodated and will be suffixed by dash and name of the matching hierarchy.\r\n#\r\n# Use case: \r\n# 1. Primarily intended to identify dimensions with maintenance issues during development/prototyping.\r\n# 2. Can also be used for trouble-shooting in productive instances.\r\n#\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\n\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants\r\ncThisProcName = GetProcessName();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub1 = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncTempSub2 = cTempSub1 | '_2';\r\ncTempSubDim = cThisProcName |'_Dim_'| cTimeStamp |'_'| cRandomInt;\r\ncUserName = TM1User();\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgInfoLevel = 'INFO';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%.';\r\ncAll = '*';\r\ncDimDimensions = '}Dimensions';\r\ncHierLeaves = 'Leaves';\r\ncSubMissing = 'Bedrock - Orphan Elements - Leaves';\r\ncSubNoParents = 'Bedrock - No Parents - %sHier%';\r\n\r\n### LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters\r\nnErrors = 0;\r\nnDims = 0;\r\nnDimsWithOrphans = 0;\r\nnDimsWithoutParents = 0;\r\nnElems = 0;\r\nnElemsMissing = 0;\r\nnElemsMissingParent = 0;\r\nsDimPrev = '';\r\n\r\nIf( Scan( '*', pDim ) = 0 & Scan( '?', pDim ) = 0 & Scan( pDelim, pDim ) = 0 & Scan( ':', pDim ) > 0 & pHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pHier = SubSt( pDim, Scan( ':', pDim ) + 1, Long( pDim ) );\r\n pDim = SubSt( pDim, 1, Scan( ':', pDim ) - 1 );\r\nEndIf;\r\n\r\n### Validate delimiter\r\nIf( Trim( pDelim ) @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\nIf( Trim( pTgtSubLeaves ) @= '' );\r\n pTgtSubLeaves = cSubMissing;\r\nEndIf;\r\n\r\nIf( Trim( pTgtSubNoParents ) @= '' );\r\n pTgtSubNoParents = cSubNoParents;\r\nElse;\r\n pTgtSubNoParents = pTgtSubNoParents | ' - %sHier%';\r\nEndIf;\r\n\r\n### Validate dimension\r\nIf( Trim( pDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### If errors occurred terminate process with a major error status ###\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### Handle All dimensions or a dimension list\r\n### We will exclude hierarchies in this step and will filter them in connection with subsets in later steps\r\nIf ( TRIM( pDim ) @= cAll );\r\n sMDX = Expand( '{FILTER(TM1SUBSETALL([%cDimDimensions%]), INSTR([%cDimDimensions%].CurrentMember.Name, '':'' ) = 0 )}' );\r\nElse;\r\n sDimTokenizer = TRIM( pDim );\r\n sMDX = '';\r\n ### Loop and tokenize dimension list\r\n While ( sDimTokenizer @<> '' );\r\n nPos = SCAN( pDelim, sDimTokenizer );\r\n If ( nPos = 0 );\r\n nPos = LONG( sDimTokenizer ) + 1;\r\n EndIf;\r\n sSearchDim = TRIM( SUBST( sDimTokenizer, 1, nPos - 1 ) );\r\n If( sMDX @= '' );\r\n sMDX = Expand( '{TM1FILTERBYPATTERN({FILTER(TM1SUBSETALL([%cDimDimensions%]), INSTR([%cDimDimensions%].CurrentMember.Name, '':'' ) = 0 )}, \"%sSearchDim%\")}' );\r\n Else;\r\n sMDX = Expand( '%sMDX% + {TM1FILTERBYPATTERN({FILTER(TM1SUBSETALL([%cDimDimensions%]), INSTR([%cDimDimensions%].CurrentMember.Name, '':'' ) = 0 )}, \"%sSearchDim%\")}' );\r\n EndIf;\r\n ### Consume dimension and delimiter\r\n sDimTokenizer = TRIM( DELET( sDimTokenizer, 1, nPos + LONG( pDelim ) - 1 ) );\r\n End;\r\n sMDX = Expand( '{%sMDX%}' );\r\nEndIf;\r\n\r\n### Create dimensions subset\r\nIf ( SubsetExists( cDimDimensions, cTempSub1 ) = 0 );\r\n SubsetCreate( cDimDimensions, cTempSub1, 1 );\r\nEndIf;\r\nSubsetMDXSet( cDimDimensions, cTempSub1, sMDX );\r\nSubsetMDXSet( cDimDimensions, cTempSub1, '' );\r\n\r\n### Create hierachies working subset\r\nIf ( SubsetExists( cDimDimensions, cTempSub2 ) = 0 );\r\n SubsetCreate( cDimDimensions, cTempSub2, 1 );\r\nEndIf;\r\n\r\nDatasourceNameForServer = cDimDimensions;\r\nDatasourceNameForClient = cDimDimensions;\r\nDataSourceType = 'SUBSET';\r\nDatasourceDimensionSubset = cTempSub1;", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.leaves.orphan.check', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pDim', '', 'pHier', '*',\r\n \t'pTgtSubLeaves', 'Bedrock - Orphan Elements - Leaves',\r\n \t'pIncludeNoParentElems', 0,\r\n \t'pTgtSubNoParents', 'Bedrock - No Parents',\r\n \t'pDelim', '&' \r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process checks all leaf elements (in the Leaves hierarchy) of the specified dimension(s).\r\n# Within the Leaves hierarchy for each element *all hierarchies* are scanned for the existance of the leaf element.\r\n# If the leaf element does not exist in all hierarchies except for Leaves then the element is classified as an orphan and added to the \r\n# \"Orphan Leaf Elements\" subset.\r\n# Additionally when running with pIncludeNoParentElems parameter set, elements that have no parent will be stored in No Parents subset\r\n# of matching hierarchy (except `Leaves`) within Leaves. The subset name might be accomodated and will be suffixed by dash and name of the matching hierarchy.\r\n#\r\n# Use case: \r\n# 1. Primarily intended to identify dimensions with maintenance issues during development/prototyping.\r\n# 2. Can also be used for trouble-shooting in productive instances.\r\n#\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\n\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants\r\ncThisProcName = GetProcessName();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub1 = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncTempSub2 = cTempSub1 | '_2';\r\ncTempSubDim = cThisProcName |'_Dim_'| cTimeStamp |'_'| cRandomInt;\r\ncUserName = TM1User();\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgInfoLevel = 'INFO';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%.';\r\ncAll = '*';\r\ncDimDimensions = '}Dimensions';\r\ncHierLeaves = 'Leaves';\r\ncSubMissing = 'Bedrock - Orphan Elements - Leaves';\r\ncSubNoParents = 'Bedrock - No Parents - %sHier%';\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pDelim\": \"&\",\r\n \"pDim\": null,\r\n \"pHier\": \"\",\r\n \"pTgtSubLeaves\": \"Bedrock - Orphan Elements - Leaves\",\r\n \"pTgtSubNoParents\": \"Bedrock - No Parents\",\r\n \"pIncludeNoParentElems\": 0,\r\n \"pLogOutput\": 0,\r\n \"pStrictErrorHandling\": 0\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pDelim\": '|StringToJson ( pDelim )|',\r\n \"pDim\": '|StringToJson ( pDim )|',\r\n \"pHier\": '|StringToJson ( pHier )|',\r\n \"pTgtSubLeaves\": '|StringToJson ( pTgtSubLeaves )|',\r\n \"pTgtSubNoParents\": '|StringToJson ( pTgtSubNoParents )|',\r\n \"pIncludeNoParentElems\": '|NumberToString( pIncludeNoParentElems )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npDelim = JsonToString( JsonGet( pJson, 'pDelim' ) );\r\npDim = JsonToString( JsonGet( pJson, 'pDim' ) );\r\npHier = JsonToString( JsonGet( pJson, 'pHier' ) );\r\npTgtSubLeaves = JsonToString( JsonGet( pJson, 'pTgtSubLeaves' ) );\r\npTgtSubNoParents = JsonToString( JsonGet( pJson, 'pTgtSubNoParents' ) );\r\n# Numeric Parameters\r\npIncludeNoParentElems = StringToNumber( JsonToString( JsonGet( pJson, 'pIncludeNoParentElems' ) ) );\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n### LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters\r\nnErrors = 0;\r\nnDims = 0;\r\nnDimsWithOrphans = 0;\r\nnDimsWithoutParents = 0;\r\nnElems = 0;\r\nnElemsMissing = 0;\r\nnElemsMissingParent = 0;\r\nsDimPrev = '';\r\n\r\nIf( Scan( '*', pDim ) = 0 & Scan( '?', pDim ) = 0 & Scan( pDelim, pDim ) = 0 & Scan( ':', pDim ) > 0 & pHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pHier = SubSt( pDim, Scan( ':', pDim ) + 1, Long( pDim ) );\r\n pDim = SubSt( pDim, 1, Scan( ':', pDim ) - 1 );\r\nEndIf;\r\n\r\n### Validate delimiter\r\nIf( Trim( pDelim ) @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\nIf( Trim( pTgtSubLeaves ) @= '' );\r\n pTgtSubLeaves = cSubMissing;\r\nEndIf;\r\n\r\nIf( Trim( pTgtSubNoParents ) @= '' );\r\n pTgtSubNoParents = cSubNoParents;\r\nElse;\r\n pTgtSubNoParents = pTgtSubNoParents | ' - %sHier%';\r\nEndIf;\r\n\r\n### Validate dimension\r\nIf( Trim( pDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### If errors occurred terminate process with a major error status ###\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### Handle All dimensions or a dimension list\r\n### We will exclude hierarchies in this step and will filter them in connection with subsets in later steps\r\nIf ( TRIM( pDim ) @= cAll );\r\n sMDX = Expand( '{FILTER(TM1SUBSETALL([%cDimDimensions%]), INSTR([%cDimDimensions%].CurrentMember.Name, '':'' ) = 0 )}' );\r\nElse;\r\n sDimTokenizer = TRIM( pDim );\r\n sMDX = '';\r\n ### Loop and tokenize dimension list\r\n While ( sDimTokenizer @<> '' );\r\n nPos = SCAN( pDelim, sDimTokenizer );\r\n If ( nPos = 0 );\r\n nPos = LONG( sDimTokenizer ) + 1;\r\n EndIf;\r\n sSearchDim = TRIM( SUBST( sDimTokenizer, 1, nPos - 1 ) );\r\n If( sMDX @= '' );\r\n sMDX = Expand( '{TM1FILTERBYPATTERN({FILTER(TM1SUBSETALL([%cDimDimensions%]), INSTR([%cDimDimensions%].CurrentMember.Name, '':'' ) = 0 )}, \"%sSearchDim%\")}' );\r\n Else;\r\n sMDX = Expand( '%sMDX% + {TM1FILTERBYPATTERN({FILTER(TM1SUBSETALL([%cDimDimensions%]), INSTR([%cDimDimensions%].CurrentMember.Name, '':'' ) = 0 )}, \"%sSearchDim%\")}' );\r\n EndIf;\r\n ### Consume dimension and delimiter\r\n sDimTokenizer = TRIM( DELET( sDimTokenizer, 1, nPos + LONG( pDelim ) - 1 ) );\r\n End;\r\n sMDX = Expand( '{%sMDX%}' );\r\nEndIf;\r\n\r\n### Create dimensions subset\r\nIf ( SubsetExists( cDimDimensions, cTempSub1 ) = 0 );\r\n SubsetCreate( cDimDimensions, cTempSub1, 1 );\r\nEndIf;\r\nSubsetMDXSet( cDimDimensions, cTempSub1, sMDX );\r\nSubsetMDXSet( cDimDimensions, cTempSub1, '' );\r\n\r\n### Create hierachies working subset\r\nIf ( SubsetExists( cDimDimensions, cTempSub2 ) = 0 );\r\n SubsetCreate( cDimDimensions, cTempSub2, 1 );\r\nEndIf;\r\n\r\nDatasourceNameForServer = cDimDimensions;\r\nDatasourceNameForClient = cDimDimensions;\r\nDataSourceType = 'SUBSET';\r\nDatasourceDimensionSubset = cTempSub1;", "MetadataProcedure": "#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n# Skip processing if there is no Leaves hierarchy defined for the dimension or we are processing Leaves\r\nIf ( HierarchyExists( vDim, cHierLeaves ) = 0 );\r\n ItemSkip;\r\nEndIf;\r\n\r\n# Summary information printout\r\nIf ( sDimPrev @<> vDim );\r\n If ( sDimPrev @<> '' & nElemsMissing <> 0 );\r\n sElemsMissing = NumberToString( nElemsMissing );\r\n If ( pLogOutput <> 0 );\r\n LogOutput( cMsgInfoLevel, Expand( 'Dimension [%sDimPrev%] is missing [%sElemsMissing%] elements from [%cHierLeaves%] hierarchy in all of matching hierarchies [%pHier%]. List of elements is available in subset [%pTgtSub%] of [%cHierLeaves%] hierarchy.' ) );\r\n EndIf;\r\n nDimsWithOrphans = nDimsWithOrphans + 1;\r\n EndIf;\r\n If ( sDimPrev @<> '' & nElemsMissingParent <> 0 );\r\n sElemsMissingParent = NumberToString( nElemsMissingParent );\r\n If ( pLogOutput <> 0 );\r\n LogOutput( cMsgInfoLevel, Expand( 'Dimension [%sDimPrev%] contains [%sElemsMissingParent%] elements that are missing parent in matching hierarchies [%pHier%].' ) );\r\n EndIf;\r\n nDimsWithoutParents = nDimsWithoutParents + 1;\r\n EndIf;\r\n nDims = nDims + 1;\r\n nElemsMissing = 0;\r\n nElemsMissingParent = 0;\r\n sDimPrev = vDim;\r\nEndIf;\r\n\r\nIf( pHier @= '' );\r\n sHier = vDim;\r\nElse;\r\n sHier = pHier;\r\nEndIf;\r\n\r\nIf( sHier @= cAll );\r\n sMDX = Expand( '{FILTER(TM1SUBSETALL([%cDimDimensions%]), [%cDimDimensions%].CurrentMember.Name = ''%vDim%'' OR INSTR([%cDimDimensions%].CurrentMember.Name, ''%vDim%:'' ) = 1 )}' );\r\n SubsetMDXSet( cDimDimensions, cTempSub2, sMDX );\r\n # Exclude Leaves from the count\r\n nMaxHier = SubsetGetSize( cDimDimensions, cTempSub2 ) - 1;\r\nElse;\r\n sMDX = Expand( '{TM1FILTERBYPATTERN({TM1SUBSETALL([%cDimDimensions%])}, ''%vDim%:%sHier%'')}' );\r\n SubsetMDXSet( cDimDimensions, cTempSub2, sMDX );\r\n nMaxHier = SubsetGetSize( cDimDimensions, cTempSub2 );\r\nEndIf; \r\n\r\nIf ( nMaxHier <> 0 );\r\n nElem = 1;\r\n nMaxElem = ElementCount( vDim, cHierLeaves );\r\n While ( nElem <= nMaxElem );\r\n sElem = ElementName( vDim, cHierLeaves, nElem );\r\n nElems = 0;\r\n nHier = 1;\r\n While ( nHier <= nMaxHier );\r\n sDimHier = SubsetGetElementName( cDimDimensions, cTempSub2, nHier );\r\n nDelimHier = SCAN( ':', sDimHier );\r\n If ( nDelimHier <> 0 );\r\n sDim = SUBST( sDimHier, 1, nDelimHier - 1);\r\n sHier = SUBST( sDimHier, nDelimHier + 1, LONG( sDimHier ) - nDelimHier );\r\n Else;\r\n sDim = sDimHier;\r\n sHier = sDimHier;\r\n EndIf;\r\n If ( sHier @<> cHierLeaves );\r\n If ( pIncludeNoParentElems <> 0 );\r\n If(ElementIndex( sDim, sHier, sElem ) <> 0 & ElementParentCount( sDim, sHier, sElem ) = 0 & ElementLevel(sDim, sHier, sElem) = 0);\r\n sTgtSubNoParents = Expand(pTgtSubNoParents);\r\n If ( HierarchySubsetExists( sDim, cHierLeaves, sTgtSubNoParents ) = 0 );\r\n HierarchySubsetCreate( sDim, cHierLeaves, sTgtSubNoParents );\r\n ElseIf ( nElemsMissingParent = 0 );\r\n HierarchySubsetDeleteAllElements( sDim, cHierLeaves, sTgtSubNoParents );\r\n EndIf;\r\n If ( HierarchySubsetElementExists( sDim, cHierLeaves, sTgtSubNoParents, sElem ) = 0 );\r\n HierarchySubsetElementInsert( sDim, cHierLeaves, sTgtSubNoParents, sElem, 0 );\r\n EndIf;\r\n If ( pLogOutput > 1 );\r\n LogOutput( cMsgInfoLevel, Expand( 'Element [%sElem%] is missing parent in [%sHier%] of dimension [%vDim%].' ) );\r\n EndIf;\r\n nElemsMissingParent = nElemsMissingParent + 1;\r\n EndIf;\r\n EndIf;\r\n If ( ElementIndex( sDim, sHier, sElem ) = 0 );\r\n nElems = nElems + 1;\r\n EndIf;\r\n EndIf;\r\n nHier = nHier + 1;\r\n End;\r\n # We have scanned all hierarchies and if number of elements missing equals number of hierarchies (excl. Leaves) then the element is orphan in Leaves\r\n If ( nElems = nMaxHier );\r\n If ( HierarchySubsetExists( sDim, cHierLeaves, pTgtSubLeaves ) = 0 );\r\n HierarchySubsetCreate( sDim, cHierLeaves, pTgtSubLeaves );\r\n ElseIf ( nElemsMissing = 0 );\r\n HierarchySubsetDeleteAllElements( sDim, cHierLeaves, pTgtSubLeaves );\r\n EndIf;\r\n If ( HierarchySubsetElementExists( sDim, cHierLeaves, pTgtSubLeaves, sElem ) = 0 );\r\n HierarchySubsetElementInsert( sDim, cHierLeaves, pTgtSubLeaves, sElem, 0 );\r\n EndIf;\r\n If ( pLogOutput > 1 );\r\n LogOutput( cMsgInfoLevel, Expand( 'Element [%sElem%] is missing in all matching hierarchies [%pHier%] of dimension [%vDim%] except [%cHierLeaves%].' ) );\r\n EndIf;\r\n nElemsMissing = nElemsMissing + 1;\r\n EndIf;\r\n nElem = nElem + 1;\r\n End;\r\nEndIf;", "DataProcedure": "#****Begin: Generated Statements***\r\n#****End: Generated Statements****", "EpilogProcedure": "#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n### If errors occurred terminate process with a major error status ###\r\nIf( nErrors <> 0 );\r\n sMessage = 'the process incurred at least 1 major error and consequently aborted. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% aborted. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nEndIf;\r\n\r\n### Return Code\r\nIf ( nDims <> 0 );\r\n sDims = NumberToString( nDims );\r\n ### Regular function - Leaves orphans\r\n If ( nDimsWithOrphans = 0 & nElemsMissing <> 0 );\r\n nDimsWithOrphans = 1;\r\n If ( pLogOutput <> 0 );\r\n sElemsMissing = NumberToString( nElemsMissing );\r\n LogOutput( cMsgInfoLevel, Expand( 'Dimension [%sDimPrev%] is missing [%sElemsMissing%] elements from [%cHierLeaves%] hierarchy in all of matching hierarchies [%pHier%]. List of elements is available in subset [%pTgtSub%] of [%cHierLeaves%] hierarchy.' ) );\r\n EndIf;\r\n EndIf;\r\n sDimsWithOrphans = NumberToString( nDimsWithOrphans );\r\n If ( nDimsWithOrphans <> 0 );\r\n sProcessAction = Expand( 'There are orphan elements in [%sDimsWithOrphans%] dimensions out of [%sDims%] matching.' );\r\n Else;\r\n sProcessAction = Expand( 'Scanned [%sDims%] dimensions, all are OK and contain no Leaves orphans.' );\r\n EndIf;\r\n ### Optional function - elements missing parents\r\n If ( nDimsWithoutParents = 0 & nElemsMissingParent <> 0 );\r\n nDimsWithoutParents = 1;\r\n If ( pLogOutput <> 0 );\r\n sElemsMissingParents = NumberToString( nElemsMissingParent );\r\n LogOutput( cMsgInfoLevel, Expand( 'Dimension [%sDimPrev%] contains [%sElemsMissingParents%] elements that are missing parent in matching hierarchies [%pHier%].' ) );\r\n EndIf;\r\n EndIf;\r\n sDimsWithoutParents = NumberToString( nDimsWithoutParents );\r\n If ( nDimsWithoutParents <> 0 );\r\n sProcessAction = Expand( '%sProcessAction% There are elements having no parent in [%sDimsWithoutParents%] dimensions out of [%sDims%] matching.' );\r\n Else;\r\n sProcessAction = Expand( '%sProcessAction% All scanned dimensions are OK and contain no elements without parents.' );\r\n EndIf;\r\nElse;\r\n sProcessAction = 'No dimensions/hierarchies are matching supplied parameters.';\r\nEndIf;\r\nsProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\nnProcessReturnCode = 1;\r\nIf( pLogoutput <> 0 );\r\n LogOutput( cMsgInfoLevel, Expand( sProcessAction ) ); \r\nEndIf;", @@ -13,53 +13,59 @@ "subset": "All" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pDim", - "Prompt": "REQUIRED: Dimension, accepts wildcards (if = *, then all the dimensions)", + "Prompt": "REQUIRED: Delimited list of dimensions", "Value": "", "Type": "String" }, { "Name": "pHier", - "Prompt": "OPTIONAL: Hierarchy, accepts wildcards (all hierarchies except default and Leaves deleted if = *)", - "Value": "*", + "Prompt": "OPTIONAL: Hierarchy name (Default = pDim)", + "Value": "", "Type": "String" }, { "Name": "pTgtSubLeaves", - "Prompt": "OPTIONAL: Name of target subset to store orphans in Leaves hierarchy", + "Prompt": "OPTIONAL: Name of target subset to store orphans in Leaves hierarchy (Default = 'Bedrock - Orphan Elements - Leaves')", "Value": "Bedrock - Orphan Elements - Leaves", "Type": "String" }, { "Name": "pIncludeNoParentElems", - "Prompt": "OPTIONAL: Include elements that have no parent in any of matching hierarchies", + "Prompt": "OPTIONAL: Include elements that have no parent in any of matching hierarchies (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { "Name": "pTgtSubNoParents", - "Prompt": "OPTIONAL: Name of target subset to store elements that have no parent in any of matching hierarchies", + "Prompt": "OPTIONAL: Name of target subset to store elements that have no parent in any of matching hierarchies (Default = 'Bedrock - No Parents')", "Value": "Bedrock - No Parents", "Type": "String" }, { "Name": "pDelim", - "Prompt": "OPTIONAL: Delimiter character (default value if blank = '&')", + "Prompt": "OPTIONAL: Delimiter for list parameters (Default = '&')", "Value": "&", "Type": "String" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [ diff --git a/bedrock_processes_json/}bedrock.hier.leaves.sync.json b/bedrock_processes_json/}bedrock.hier.leaves.sync.json index 1b75e78..a1bff84 100644 --- a/bedrock_processes_json/}bedrock.hier.leaves.sync.json +++ b/bedrock_processes_json/}bedrock.hier.leaves.sync.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.hier.leaves.sync", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.leaves.sync', 'pLogOutput', pLogOutput, 'pStrictErrorHandling', pStrictErrorHandling,\r\n\t 'pDim', '', 'pHier', '', 'pDelim', '&', 'pReverse', 0\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# In certain circumstances the Leaves hierarchy can become *out of sync* with the same named hierarchy and other alternate hierarchies\r\n# and *not contain all leaf elements*. Should this happen this process will heal such dimensions and restore the synced state where\r\n# the Leaves hierarchy contains the collection of all leaf elements from all hiearchies of a dimension. \r\n# For the set of dimensions and hierarchies defined by the pDim & pHier parameters this process checks that all leaf elements from each\r\n# hierarchy also exists in the Leaves hierarchy of the specified dimension(s).\r\n#\r\n# If the leaf element does not exist in the Leaves hierarchy then the element is inserted into Leaves.\r\n#\r\n# Use case: \r\n# 1. Primarily intended to identify dimensions with maintenance issues during development/prototyping.\r\n# 2. Can also be used for trouble-shooting in productive instances.\r\n#\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants\r\ncThisProcName = GetProcessName();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncTempSubDim = cThisProcName |'_Dim_'| cTimeStamp |'_'| cRandomInt;\r\ncUserName = TM1User();\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgInfoLevel = 'INFO';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pHier:%pHier%.';\r\ncAll = '*';\r\ncDimDimensions = '}Dimensions';\r\ncCharAny = '?';\r\ncStringAny = '*';\r\ncHierLeaves = 'Leaves';\r\ncRollupOrphan = 'ORPHAN LEAVES';\r\n\r\n### LogOutput parameters\r\nIF( pLogoutput >= 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters\r\nsDimPrev = '';\r\nnErrors = 0;\r\nnDims = 0;\r\nnDimsChanged = 0;\r\nnElems = 0;\r\nnLeaves = 0;\r\n\r\nIf( Scan( '*', pDim ) = 0 & Scan( '?', pDim ) = 0 & Scan( pDelim, pDim ) = 0 & Scan( ':', pDim ) > 0 & pHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pHier = SubSt( pDim, Scan( ':', pDim ) + 1, Long( pDim ) );\r\n pDim = SubSt( pDim, 1, Scan( ':', pDim ) - 1 );\r\nEndIf;\r\n\r\n### Validate delimiter\r\nIf( Trim( pDelim ) @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\n### Validate dimension\r\nIf( Trim( pDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### Validate reverse sync option\r\nIf( pReverse <> 1 );\r\n pReverse = 0;\r\nEndIf;\r\n\r\n### If errors occurred terminate process with a major error status ###\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### Handle All dimensions or a dimension list, including all available hierarchies\r\nIf ( TRIM( pDim ) @= cAll );\r\n sMDX1 = Expand( '{TM1SUBSETALL([%cDimDimensions%])}' );\r\nElse;\r\n sDimTokenizer = TRIM( pDim );\r\n sMDX = '';\r\n ### Loop and tokenize dimension list\r\n While ( sDimTokenizer @<> '' );\r\n nPos = SCAN( pDelim, sDimTokenizer );\r\n If ( nPos = 0 );\r\n nPos = LONG( sDimTokenizer ) + 1;\r\n EndIf;\r\n sSearchDim = TRIM( SUBST( sDimTokenizer, 1, nPos - 1 ) );\r\n If( sMDX @= '' );\r\n sMDX = Expand( '{TM1FILTERBYPATTERN( {TM1SUBSETALL([%cDimDimensions%])}, \"%sSearchDim%*\" )}' );\r\n Else;\r\n sMDX = Expand( '%sMDX% + {TM1FILTERBYPATTERN( {TM1SUBSETALL([%cDimDimensions%])}, \"%sSearchDim%\" )}' );\r\n EndIf;\r\n ### Consume dimension and delimiter\r\n sDimTokenizer = TRIM( DELET( sDimTokenizer, 1, nPos + LONG( pDelim ) - 1 ) );\r\n End;\r\n sMDX1 = Expand( '{%sMDX%}' );\r\nEndIf;\r\n\r\n### Handle All hierarchies or a hierarchy list\r\n### We will filter hierarchies in this step from base set created previously\r\nIf ( TRIM( pHier ) @= cAll );\r\n sMDX = sMDX1;\r\nElse;\r\n sHierTokenizer = TRIM( pHier );\r\n If( sHierTokenizer @= '' );\r\n # if pHier blank then we need only same named hierarchies - that means to exclude elements that have : in their names\r\n sMDX = Expand( '{FILTER( %sMDX1%, INSTR([%cDimDimensions%].CurrentMember.Name, '':'' ) = 0 )}' );\r\n Else;\r\n sMDX = '';\r\n ### Loop and tokenize hierarchy list\r\n While ( sHierTokenizer @<> '' );\r\n nPos = SCAN( pDelim, sHierTokenizer );\r\n If ( nPos = 0 );\r\n nPos = LONG( sHierTokenizer ) + 1;\r\n EndIf;\r\n sSearchHier = TRIM( SUBST( sHierTokenizer, 1, nPos - 1 ) );\r\n If( sMDX @= '' );\r\n sMDX = Expand( '{TM1FILTERBYPATTERN( %sMDX1%, \"*:%sSearchHier%\" )}' );\r\n Else;\r\n sMDX = Expand( '%sMDX% + {TM1FILTERBYPATTERN( %sMDX1%, \"*:%sSearchHier%\" )}' );\r\n EndIf;\r\n ### Consume hierarchy and delimiter\r\n sHierTokenizer = TRIM( DELET( sHierTokenizer, 1, nPos + LONG( pDelim ) - 1 ) );\r\n End;\r\n sMDX = Expand( '{%sMDX%}' );\r\n EndIf;\r\nEndIf;\r\n\r\nsMDX = Expand(' {EXCEPT( %sMDX%, {TM1FILTERBYPATTERN( {TM1SUBSETALL([%cDimDimensions%])}, \"*:Leaves\" )} )}');\r\nsMDXF = Expand( '{ORDER( %sMDX%, [%cDimDimensions%].CurrentMember.Name, ASC )}' );\r\n\r\n### Create dimension:hierarchy subset\r\nIf ( SubsetExists( cDimDimensions, cTempSub ) = 0 );\r\n SubsetCreatebyMDX( cTempSub, sMDXF, cDimDimensions, 1 );\r\nElse;\r\n SubsetMDXSet( cDimDimensions, cTempSub, sMDXF );\r\nEndIf;\r\n\r\nDatasourceNameForServer = cDimDimensions;\r\nDatasourceNameForClient = cDimDimensions;\r\nDataSourceType = 'SUBSET';\r\nDatasourceDimensionSubset = cTempSub;\r\n\r\n### END PROLOG\r\n", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.leaves.sync', 'pLogOutput', pLogOutput, 'pStrictErrorHandling', pStrictErrorHandling,\r\n\t 'pDim', '', 'pHier', '', 'pDelim', '&', 'pReverse', 0\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# In certain circumstances the Leaves hierarchy can become *out of sync* with the same named hierarchy and other alternate hierarchies\r\n# and *not contain all leaf elements*. Should this happen this process will heal such dimensions and restore the synced state where\r\n# the Leaves hierarchy contains the collection of all leaf elements from all hiearchies of a dimension. \r\n# For the set of dimensions and hierarchies defined by the pDim & pHier parameters this process checks that all leaf elements from each\r\n# hierarchy also exists in the Leaves hierarchy of the specified dimension(s).\r\n#\r\n# If the leaf element does not exist in the Leaves hierarchy then the element is inserted into Leaves.\r\n#\r\n# Use case: \r\n# 1. Primarily intended to identify dimensions with maintenance issues during development/prototyping.\r\n# 2. Can also be used for trouble-shooting in productive instances.\r\n#\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants\r\ncThisProcName = GetProcessName();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncTempSubDim = cThisProcName |'_Dim_'| cTimeStamp |'_'| cRandomInt;\r\ncUserName = TM1User();\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgInfoLevel = 'INFO';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pHier:%pHier%.';\r\ncAll = '*';\r\ncDimDimensions = '}Dimensions';\r\ncCharAny = '?';\r\ncStringAny = '*';\r\ncHierLeaves = 'Leaves';\r\ncRollupOrphan = 'ORPHAN LEAVES';\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pDelim\": \"&\",\r\n \"pDim\": null,\r\n \"pHier\": \"\",\r\n \"pLogOutput\": 0,\r\n \"pReverse\": 0,\r\n \"pStrictErrorHandling\": 0\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pDelim\": '|StringToJson ( pDelim )|',\r\n \"pDim\": '|StringToJson ( pDim )|',\r\n \"pHier\": '|StringToJson ( pHier )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pReverse\": '|NumberToString( pReverse )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npDelim = JsonToString( JsonGet( pJson, 'pDelim' ) );\r\npDim = JsonToString( JsonGet( pJson, 'pDim' ) );\r\npHier = JsonToString( JsonGet( pJson, 'pHier' ) );\r\n# Numeric Parameters\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npReverse = StringToNumber( JsonToString( JsonGet( pJson, 'pReverse' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n### LogOutput parameters\r\nIF( pLogoutput >= 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters\r\nsDimPrev = '';\r\nnErrors = 0;\r\nnDims = 0;\r\nnDimsChanged = 0;\r\nnElems = 0;\r\nnLeaves = 0;\r\n\r\nIf( Scan( '*', pDim ) = 0 & Scan( '?', pDim ) = 0 & Scan( pDelim, pDim ) = 0 & Scan( ':', pDim ) > 0 & pHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pHier = SubSt( pDim, Scan( ':', pDim ) + 1, Long( pDim ) );\r\n pDim = SubSt( pDim, 1, Scan( ':', pDim ) - 1 );\r\nEndIf;\r\n\r\n### Validate delimiter\r\nIf( Trim( pDelim ) @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\n### Validate dimension\r\nIf( Trim( pDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### Validate reverse sync option\r\nIf( pReverse <> 1 );\r\n pReverse = 0;\r\nEndIf;\r\n\r\n### If errors occurred terminate process with a major error status ###\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### Handle All dimensions or a dimension list, including all available hierarchies\r\nIf ( TRIM( pDim ) @= cAll );\r\n sMDX1 = Expand( '{TM1SUBSETALL([%cDimDimensions%])}' );\r\nElse;\r\n sDimTokenizer = TRIM( pDim );\r\n sMDX = '';\r\n ### Loop and tokenize dimension list\r\n While ( sDimTokenizer @<> '' );\r\n nPos = SCAN( pDelim, sDimTokenizer );\r\n If ( nPos = 0 );\r\n nPos = LONG( sDimTokenizer ) + 1;\r\n EndIf;\r\n sSearchDim = TRIM( SUBST( sDimTokenizer, 1, nPos - 1 ) );\r\n If( sMDX @= '' );\r\n sMDX = Expand( '{TM1FILTERBYPATTERN( {TM1SUBSETALL([%cDimDimensions%])}, \"%sSearchDim%*\" )}' );\r\n Else;\r\n sMDX = Expand( '%sMDX% + {TM1FILTERBYPATTERN( {TM1SUBSETALL([%cDimDimensions%])}, \"%sSearchDim%\" )}' );\r\n EndIf;\r\n ### Consume dimension and delimiter\r\n sDimTokenizer = TRIM( DELET( sDimTokenizer, 1, nPos + LONG( pDelim ) - 1 ) );\r\n End;\r\n sMDX1 = Expand( '{%sMDX%}' );\r\nEndIf;\r\n\r\n### Handle All hierarchies or a hierarchy list\r\n### We will filter hierarchies in this step from base set created previously\r\nIf ( TRIM( pHier ) @= cAll );\r\n sMDX = sMDX1;\r\nElse;\r\n sHierTokenizer = TRIM( pHier );\r\n If( sHierTokenizer @= '' );\r\n # if pHier blank then we need only same named hierarchies - that means to exclude elements that have : in their names\r\n sMDX = Expand( '{FILTER( %sMDX1%, INSTR([%cDimDimensions%].CurrentMember.Name, '':'' ) = 0 )}' );\r\n Else;\r\n sMDX = '';\r\n ### Loop and tokenize hierarchy list\r\n While ( sHierTokenizer @<> '' );\r\n nPos = SCAN( pDelim, sHierTokenizer );\r\n If ( nPos = 0 );\r\n nPos = LONG( sHierTokenizer ) + 1;\r\n EndIf;\r\n sSearchHier = TRIM( SUBST( sHierTokenizer, 1, nPos - 1 ) );\r\n If( sMDX @= '' );\r\n sMDX = Expand( '{TM1FILTERBYPATTERN( %sMDX1%, \"*:%sSearchHier%\" )}' );\r\n Else;\r\n sMDX = Expand( '%sMDX% + {TM1FILTERBYPATTERN( %sMDX1%, \"*:%sSearchHier%\" )}' );\r\n EndIf;\r\n ### Consume hierarchy and delimiter\r\n sHierTokenizer = TRIM( DELET( sHierTokenizer, 1, nPos + LONG( pDelim ) - 1 ) );\r\n End;\r\n sMDX = Expand( '{%sMDX%}' );\r\n EndIf;\r\nEndIf;\r\n\r\nsMDX = Expand(' {EXCEPT( %sMDX%, {TM1FILTERBYPATTERN( {TM1SUBSETALL([%cDimDimensions%])}, \"*:Leaves\" )} )}');\r\nsMDXF = Expand( '{ORDER( %sMDX%, [%cDimDimensions%].CurrentMember.Name, ASC )}' );\r\n\r\n### Create dimension:hierarchy subset\r\nIf ( SubsetExists( cDimDimensions, cTempSub ) = 0 );\r\n SubsetCreatebyMDX( cTempSub, sMDXF, cDimDimensions, 1 );\r\nElse;\r\n SubsetMDXSet( cDimDimensions, cTempSub, sMDXF );\r\nEndIf;\r\n\r\nDatasourceNameForServer = cDimDimensions;\r\nDatasourceNameForClient = cDimDimensions;\r\nDataSourceType = 'SUBSET';\r\nDatasourceDimensionSubset = cTempSub;\r\n\r\n### END PROLOG\r\n", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n# Get dimension & hierarchy from vDimHier\r\nnDelimHier = SCAN( ':', vDimHier );\r\nIf ( nDelimHier <> 0 );\r\n sDim = SUBST( vDimHier, 1, nDelimHier - 1);\r\n sHier = SUBST( vDimHier, nDelimHier + 1, LONG( vDimHier ) - nDelimHier );\r\nElse;\r\n sDim = vDimHier;\r\n sHier = vDimHier;\r\nEndIf;\r\n\r\nIf ( sHier @= cHierLeaves );\r\n ItemSkip;\r\nEndIf;\r\n\r\n# Set check counters\r\nIf( sDim @<> sDimPrev );\r\n nDims = nDims + 1;\r\nEndIf;\r\nnElems = 0;\r\nnLeaves = 0;\r\n\r\n# Add leaves which exist in hierarchy but (somehow) don't exist in Leaves hierarchy to Leaves\r\nnElem = 1;\r\nnMaxElem = ElementCount( sDim, sHier );\r\nWhile ( nElem <= nMaxElem );\r\n sElem = ElementName( sDim, sHier, nElem );\r\n sType = ElementType( sDim, sHier, sElem );\r\n If ( ElementLevel( sDim, sHier, sElem ) = 0 & HierarchyExists( sDim, cHierLeaves ) = 1 );\r\n If ( ElementIndex( sDim, cHierLeaves, sElem ) = 0 & ( sType @= 'N' % sType @= 'S' ) );\r\n HierarchyElementInsert( sDim, cHierLeaves, '', sElem, sType );\r\n nElems = nElems + 1;\r\n If ( pLogOutput <> 0 );\r\n LogOutput( cMsgInfoLevel, Expand( 'Adding element [%sElem%] of [%sType%] type into [%cHierLeaves%], element was found in hierarchy [%sHier%].' ) );\r\n EndIf;\r\n EndIf;\r\n EndIf;\r\n nElem = nElem + 1;\r\nEnd;\r\n\r\n# Add leaves not existing in hierarchy to the 'ORPHAN LEAVES' consolidation\r\nIf( pReverse = 1 & HierarchyExists( sDim, cHierLeaves ) = 1 );\r\n nLeaf = 1;\r\n nMaxLeaves = ElementCount( sDim, cHierLeaves );\r\n While ( nLeaf <= nMaxLeaves );\r\n sLeaf = ElementName( sDim, cHierLeaves, nLeaf );\r\n sType = ElementType( sDim, cHierLeaves, sLeaf );\r\n If ( ElementIndex( sDim, sHier, sLeaf ) = 0 );\r\n HierarchyElementInsert( sDim, sHier, '', cRollupOrphan, 'C' );\r\n HierarchyElementInsert( sDim, sHier, '', sLeaf, sType );\r\n If( sType @= 'N' );\r\n HierarchyElementComponentAdd( sDim, sHier, cRollupOrphan, sLeaf, 1 );\r\n EndIf;\r\n nLeaves = nLeaves + 1;\r\n If ( pLogOutput <> 0 );\r\n LogOutput( cMsgInfoLevel, Expand( 'Adding leaf [%sLeaf%] into hierarchy [%sHier%].' ) );\r\n EndIf;\r\n EndIf;\r\n nLeaf = nLeaf + 1;\r\n End;\r\nEndIf;\r\n\r\n# Summary information printout\r\nIf( nElems > 0 );\r\n sElems = NumberToString( nElems );\r\n If ( pLogOutput <> 0 );\r\n LogOutput( cMsgInfoLevel, Expand( 'Added [%sElems%] elements from hierarchy [%sHier%] into [%cHierLeaves%] hierarchy of [%sDim%] dimension.' ) );\r\n EndIf;\r\nEndIf;\r\nIf( nLeaves > 0 );\r\n sLeaves = NumberToString( nLeaves );\r\n If ( pLogOutput <> 0 );\r\n LogOutput( cMsgInfoLevel, Expand( 'Added [%sLeaves%] leaves into hierarchy [%sHier%] of [%sDim%] dimension.' ) );\r\n EndIf;\r\nEndIf;\r\nIf( sDim @<> sDimPrev & (nElems + nLeaves) > 0 );\r\n nDimsChanged = nDimsChanged + 1;\r\nEndIf;\r\nsDimPrev = sDim;\r\n\r\n### END METADATA", "DataProcedure": "#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "EpilogProcedure": "#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n### If errors occurred terminate process with a major error status ###\r\nIf( nErrors <> 0 );\r\n sMessage = 'the process incurred at least 1 major error and consequently aborted. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% aborted. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nEndIf;\r\n\r\n### Return Code\r\nIf ( nDims <> 0 );\r\n sDims = NumberToString( nDims );\r\n sDimsChanged = NumberToString( nDimsChanged );\r\n If ( nDimsChanged > 0 );\r\n sProcessAction = Expand( 'Modified [%sDimsChanged%] dimensions out of [%sDims%] matching the filter.' );\r\n Else;\r\n sProcessAction = Expand( 'Scanned [%sDims%] dimensions, all are ok.' );\r\n EndIf;\r\nElse;\r\n sProcessAction = 'No dimensions/hierarchies are matching supplied parameters. Nothing modified.';\r\nEndIf;\r\nsProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\nnProcessReturnCode = 1;\r\nIf( pLogoutput <> 0 );\r\n LogOutput( cMsgInfoLevel, Expand( sProcessAction ) ); \r\nEndIf;\r\n\r\n### END EPILOG", @@ -13,41 +13,47 @@ "subset": "All" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pDim", - "Prompt": "REQUIRED: Dimension, accepts wildcards (all dimensions = *)", + "Prompt": "REQUIRED: Delimited list of dimensions", "Value": "", "Type": "String" }, { "Name": "pHier", - "Prompt": "OPTIONAL: Hierarchy, accepts wildcards (all hierarchies = *)", + "Prompt": "OPTIONAL: Hierarchy name (Default = pDim)", "Value": "", "Type": "String" }, { "Name": "pDelim", - "Prompt": "OPTIONAL: Delimiter character (default value if blank = '&')", + "Prompt": "OPTIONAL: Delimiter for list parameters (Default = '&')", "Value": "&", "Type": "String" }, { "Name": "pReverse", - "Prompt": "OPTIONAL: If true then also add any elements from the Leaves hierarchy not existing in the specified hierarchies to those hierarchies (under a consolidation bucket 'ORPHAN LEAVES')", + "Prompt": "OPTIONAL: Add any elements from the Leaves hierarchy not existing in the specified hierarchies to those hierarchies (under a consolidation bucket 'ORPHAN LEAVES'. Boolean. Default = 0)", "Value": 0, "Type": "Numeric" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [ @@ -59,7 +65,5 @@ "EndByte": 0 } ], - "VariablesUIData": [ - "VarType=32\fColType=827\f" - ] + "VariablesUIData": [] } \ No newline at end of file diff --git a/bedrock_processes_json/}bedrock.hier.sub.clone.json b/bedrock_processes_json/}bedrock.hier.sub.clone.json index ce8177d..abfe350 100644 --- a/bedrock_processes_json/}bedrock.hier.sub.clone.json +++ b/bedrock_processes_json/}bedrock.hier.sub.clone.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.hier.sub.clone", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.sub.clone', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pSrcDim', '', 'pSrcHier', '', 'pSrcSub', '',\r\n \t'pTgtDim', '', 'pTgtHier', '', 'pTgtSub', '',\r\n \t'pTemp', 1\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will copy a subset from a Hierarchy in source Dimension to a Hierarchy in target\r\n# Dimension.\r\n\r\n# Note:\r\n# Valid source dimension name (pSrcDim), source (pSrcSub) and target subset (pTgtSub) are \r\n# mandatory otherwise the process will abort.\r\n\r\n# Caution:\r\n# - Target hierarchy cannot be `Leaves`.\r\n# - If the target dimension Hierarchy exists then it will be overwritten.\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent= 'Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pSrcDim:%pSrcDim%, pSrcHier:%pSrcHier%, pSrcSub:%pSrcSub%, pTgtDim:%pTgtDim%, pTgtHier:%pTgtHier%, pTgtSub:%pTgtSub%, pTemp:%pTemp%, pAlias:%pAlias%.' ; \r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\nIf( Scan( ':', pSrcDim ) > 0 & pSrcHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pSrcHier = SubSt( pSrcDim, Scan( ':', pSrcDim ) + 1, Long( pSrcDim ) );\r\n pSrcDim = SubSt( pSrcDim, 1, Scan( ':', pSrcDim ) - 1 );\r\nEndIf;\r\n\r\n# Validate Source dimension\r\nIf( Trim( pSrcDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No source dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( DimensionExists( pSrcDim ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Dimension ' | pSrcDim | ' does not exist.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate Source Hierarchy\r\nIf( Trim( pSrcHier ) @= '' );\r\n pSrcHier = Trim( pSrcDim );\r\nEndIf;\r\n\r\nIf( HierarchyExists( pSrcDim , pSrcHier ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'The Hierachy ' | pSrcHier | ' does not exist.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate Source subset\r\nIf( Trim( pSrcsub ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No source subset specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( HierarchySubsetExists( pSrcDim , pSrcHier, pSrcsub ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid source subset : ' | pSrcDim |':'| pSrcHier |':'| pSrcSub;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nIf( Scan( ':', pTgtDim ) > 0 & pTgtHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pTgtHier = SubSt( pTgtDim, Scan( ':', pTgtDim ) + 1, Long( pTgtDim ) );\r\n pTgtDim = SubSt( pTgtDim, 1, Scan( ':', pTgtDim ) - 1 );\r\nEndIf;\r\n\r\n# Validate target dimension\r\nIf( Trim( pTgtDim ) @= '' );\r\n pTgtDim = Trim( pSrcDim );\r\nElseIf( DimensionExists( pTgtDim ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid target dimension: ' | pTgtDim;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n\r\n# Validate Target Hierarchy\r\nIf( Trim( pTgtHier ) @= '' );\r\n pTgtHier = pTgtDim;\r\nElseIf( HierarchyExists( pTgtDim, pTgtHier ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'The target Hierachy ' | pTgtHier | ' does not exist.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate subset\r\nIf( Trim( pTgtSub ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No target subset specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n## Validate pTemp\r\nIF( pTemp <> 0 & pTemp <> 1 );\r\n nErrors = 1;\r\n sMessage = 'Wrong parameter pTemp value (only 0 or 1 accepted).';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate Alias exists\r\nIf ( pAlias @<> '' & \r\n DimIx ( Expand ( '}ElementAttributes_%pTgtDim%' ), pAlias ) = 0\r\n);\r\n nErrors = 1;\r\n sMessage = 'Alias does not exist in dimension %pTgtDim%.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf; \r\n\r\n# Validate alias attribute name is actually an alias\r\nIf ( pAlias @<> '' & \r\n Dtype ( Expand ( '}ElementAttributes_%pTgtDim%' ), pAlias ) @<> 'AA'\r\n);\r\n nErrors = 1;\r\n sMessage = 'Attribute %pAlias% is not an alias in dimension %pTgtDim%.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf; \r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### Create Target Subset ###\r\nIf( HierarchySubsetExists( pTgtDim, pTgtHier, pTgtsub ) = 1 );\r\n HierarchySubsetDeleteAllElements( pTgtDim, pTgtHier, pTgtsub );\r\nElse;\r\n HierarchySubsetCreate( pTgtDim, pTgtHier, pTgtsub, pTemp );\r\nEndIf;\r\n\r\n### Set Alias ###\r\nIf ( pAlias @<> '' );\r\n If ( pTgtDim @= pTgtHier );\r\n SubsetAliasSet( pTgtDim, pTgtsub, pAlias);\r\n Else;\r\n SubsetAliasSet( pTgtDim | ':' | pTgtHier, pTgtsub, pAlias);\r\n EndIf;\r\nEndIf;\r\n\r\n# HierarchySubsetMDXGet not returning anything. Thought it might also return alias used in source subset\r\nsMDX = HierarchySubsetMDXGet(pSrcDim, pSrcHier, pSrcSub);\r\n\r\nnElementPosition = 0;\r\n\r\n### Set data source for process ###\r\nDatasourceType = 'SUBSET';\r\nDatasourceNameForServer = pSrcDim | ':' | pSrcHier;\r\nDatasourceDimensionSubset = pSrcsub;", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.sub.clone', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pSrcDim', '', 'pSrcHier', '', 'pSrcSub', '',\r\n \t'pTgtDim', '', 'pTgtHier', '', 'pTgtSub', '',\r\n \t'pTemp', 1\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will copy a subset from a Hierarchy in source Dimension to a Hierarchy in target\r\n# Dimension.\r\n\r\n# Note:\r\n# Valid source dimension name (pSrcDim), source (pSrcSub) and target subset (pTgtSub) are \r\n# mandatory otherwise the process will abort.\r\n\r\n# Caution:\r\n# - Target hierarchy cannot be `Leaves`.\r\n# - If the target dimension Hierarchy exists then it will be overwritten.\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent= 'Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pSrcDim:%pSrcDim%, pSrcHier:%pSrcHier%, pSrcSub:%pSrcSub%, pTgtDim:%pTgtDim%, pTgtHier:%pTgtHier%, pTgtSub:%pTgtSub%, pTemp:%pTemp%, pAlias:%pAlias%.' ;\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pAlias\": \"\",\r\n \"pSrcDim\": null,\r\n \"pSrcHier\": \"\",\r\n \"pSrcSub\": null,\r\n \"pTgtDim\": \"\",\r\n \"pTgtHier\": \"\",\r\n \"pTgtSub\": null,\r\n \"pLogOutput\": 0,\r\n \"pStrictErrorHandling\": 0,\r\n \"pTemp\": 1\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pAlias\": '|StringToJson ( pAlias )|',\r\n \"pSrcDim\": '|StringToJson ( pSrcDim )|',\r\n \"pSrcHier\": '|StringToJson ( pSrcHier )|',\r\n \"pSrcSub\": '|StringToJson ( pSrcSub )|',\r\n \"pTgtDim\": '|StringToJson ( pTgtDim )|',\r\n \"pTgtHier\": '|StringToJson ( pTgtHier )|',\r\n \"pTgtSub\": '|StringToJson ( pTgtSub )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|',\r\n \"pTemp\": '|NumberToString( pTemp )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npAlias = JsonToString( JsonGet( pJson, 'pAlias' ) );\r\npSrcDim = JsonToString( JsonGet( pJson, 'pSrcDim' ) );\r\npSrcHier = JsonToString( JsonGet( pJson, 'pSrcHier' ) );\r\npSrcSub = JsonToString( JsonGet( pJson, 'pSrcSub' ) );\r\npTgtDim = JsonToString( JsonGet( pJson, 'pTgtDim' ) );\r\npTgtHier = JsonToString( JsonGet( pJson, 'pTgtHier' ) );\r\npTgtSub = JsonToString( JsonGet( pJson, 'pTgtSub' ) );\r\n# Numeric Parameters\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\npTemp = StringToNumber( JsonToString( JsonGet( pJson, 'pTemp' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\nIf( Scan( ':', pSrcDim ) > 0 & pSrcHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pSrcHier = SubSt( pSrcDim, Scan( ':', pSrcDim ) + 1, Long( pSrcDim ) );\r\n pSrcDim = SubSt( pSrcDim, 1, Scan( ':', pSrcDim ) - 1 );\r\nEndIf;\r\n\r\n# Validate Source dimension\r\nIf( Trim( pSrcDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No source dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( DimensionExists( pSrcDim ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Dimension ' | pSrcDim | ' does not exist.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate Source Hierarchy\r\nIf( Trim( pSrcHier ) @= '' );\r\n pSrcHier = Trim( pSrcDim );\r\nEndIf;\r\n\r\nIf( HierarchyExists( pSrcDim , pSrcHier ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'The Hierachy ' | pSrcHier | ' does not exist.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate Source subset\r\nIf( Trim( pSrcsub ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No source subset specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( HierarchySubsetExists( pSrcDim , pSrcHier, pSrcsub ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid source subset : ' | pSrcDim |':'| pSrcHier |':'| pSrcSub;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nIf( Scan( ':', pTgtDim ) > 0 & pTgtHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pTgtHier = SubSt( pTgtDim, Scan( ':', pTgtDim ) + 1, Long( pTgtDim ) );\r\n pTgtDim = SubSt( pTgtDim, 1, Scan( ':', pTgtDim ) - 1 );\r\nEndIf;\r\n\r\n# Validate target dimension\r\nIf( Trim( pTgtDim ) @= '' );\r\n pTgtDim = Trim( pSrcDim );\r\nElseIf( DimensionExists( pTgtDim ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid target dimension: ' | pTgtDim;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n\r\n# Validate Target Hierarchy\r\nIf( Trim( pTgtHier ) @= '' );\r\n pTgtHier = pTgtDim;\r\nElseIf( HierarchyExists( pTgtDim, pTgtHier ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'The target Hierachy ' | pTgtHier | ' does not exist.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate subset\r\nIf( Trim( pTgtSub ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No target subset specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n## Validate pTemp\r\nIF( pTemp <> 0 & pTemp <> 1 );\r\n nErrors = 1;\r\n sMessage = 'Wrong parameter pTemp value (only 0 or 1 accepted).';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate Alias exists\r\nIf ( pAlias @<> '' & \r\n DimIx ( Expand ( '}ElementAttributes_%pTgtDim%' ), pAlias ) = 0\r\n);\r\n nErrors = 1;\r\n sMessage = 'Alias does not exist in dimension %pTgtDim%.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf; \r\n\r\n# Validate alias attribute name is actually an alias\r\nIf ( pAlias @<> '' & \r\n Dtype ( Expand ( '}ElementAttributes_%pTgtDim%' ), pAlias ) @<> 'AA'\r\n);\r\n nErrors = 1;\r\n sMessage = 'Attribute %pAlias% is not an alias in dimension %pTgtDim%.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf; \r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### Create Target Subset ###\r\nIf( HierarchySubsetExists( pTgtDim, pTgtHier, pTgtsub ) = 1 );\r\n HierarchySubsetDeleteAllElements( pTgtDim, pTgtHier, pTgtsub );\r\nElse;\r\n HierarchySubsetCreate( pTgtDim, pTgtHier, pTgtsub, pTemp );\r\nEndIf;\r\n\r\n### Set Alias ###\r\nIf ( pAlias @<> '' );\r\n If ( pTgtDim @= pTgtHier );\r\n SubsetAliasSet( pTgtDim, pTgtsub, pAlias);\r\n Else;\r\n SubsetAliasSet( pTgtDim | ':' | pTgtHier, pTgtsub, pAlias);\r\n EndIf;\r\nEndIf;\r\n\r\n# HierarchySubsetMDXGet not returning anything. Thought it might also return alias used in source subset\r\nsMDX = HierarchySubsetMDXGet(pSrcDim, pSrcHier, pSrcSub);\r\n\r\nnElementPosition = 0;\r\n\r\n### Set data source for process ###\r\nDatasourceType = 'SUBSET';\r\nDatasourceNameForServer = pSrcDim | ':' | pSrcHier;\r\nDatasourceDimensionSubset = pSrcsub;", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n\r\nIF( pTgtDim @= pSrcDim & pTgtHier @= pSrcHier);\r\n nElementPosition = nElementPosition + 1;\r\nElseIF( ElementIndex( pTgtDim, pTgtHier,vEle ) > 0 );\r\n nElementPosition = nElementPosition + 1;\r\nElse;\r\n ItemReject( Expand( 'Cannot insert into subset. Element %vEle% does not exist in target dimension:Hierarchy %pTgtDim%:%pTgtHier%.' ) );\r\nEndIF;\r\n\r\nHierarchySubsetElementInsert( pTgtDim , pTgtHier, pTgtSub , vEle , nElementPosition );", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully cloned the %pTgtDim%:%pTgtHier%:%pTgtSub% subset from %pSrcDim%:%pSrcHier%:%pSrcSub%.' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n### End Epilog ###", @@ -13,65 +13,71 @@ "subset": "All" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pSrcDim", - "Prompt": "REQUIRED: Dimension where the subset exists", + "Prompt": "REQUIRED: Source dimension name", "Value": "", "Type": "String" }, { "Name": "pSrcHier", - "Prompt": "OPTIONAL: Source Hierarchy (blank = same as source)", + "Prompt": "OPTIONAL: Source hierarchy name (Default = pSrcDim)", "Value": "", "Type": "String" }, { "Name": "pSrcSub", - "Prompt": "REQUIRED: Source Subset", + "Prompt": "REQUIRED: Source subset name", "Value": "", "Type": "String" }, { "Name": "pTgtDim", - "Prompt": "OPTIONAL: Target dimension (blank = same as source)", + "Prompt": "OPTIONAL: Target dimension name (Default = pSrcDim)", "Value": "", "Type": "String" }, { "Name": "pTgtHier", - "Prompt": "OPTIONAL: Target Hierarchy (blank = same as Target Dimension)", + "Prompt": "OPTIONAL: Target hierarchy name (Default = pTgtDim)", "Value": "", "Type": "String" }, { "Name": "pTgtSub", - "Prompt": "REQUIRED: Target Subset", + "Prompt": "REQUIRED: Target subset name", "Value": "", "Type": "String" }, { "Name": "pTemp", - "Prompt": "OPTIONAL: Use temporary objects? (Boolean 1=True)", + "Prompt": "OPTIONAL: Delete/create temporary objects (0 = Do not delete, 1 = Delete, 2 = if view and subsets are created, keep only subsets)", "Value": 1, "Type": "Numeric" }, { "Name": "pAlias", - "Prompt": "Optional: Set Alias for Subset", + "Prompt": "OPTIONAL: Set alias for subset", "Value": "", "Type": "String" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [ diff --git a/bedrock_processes_json/}bedrock.hier.sub.create.all.json b/bedrock_processes_json/}bedrock.hier.sub.create.all.json index 86d101c..1ff861a 100644 --- a/bedrock_processes_json/}bedrock.hier.sub.create.all.json +++ b/bedrock_processes_json/}bedrock.hier.sub.create.all.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.hier.sub.create.all", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.sub.create.all', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pDim', '', 'pHier', '', 'pSub', '',\r\n \t'pAddToSubset', 0, 'pExclusions', '',\r\n \t'pDelim', '&', 'pAlias', '',\r\n \t'pTemp', 1\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will create a static subset in Hierarchy of a Dimension that consists of all elements.\r\n\r\n# Note:\r\n# This process uses modification parameters to determine what to include in the subset:\r\n# - pExclusions: If pExclusions is specified then the elements (separated by a delimiter) will be\r\n# excluded from the subset. Wildcards characters `*` and `?` are accepted.\r\n# - pAddToSubset: If the specified subset already exists then this parameter will control whether elements will\r\n# be added to the existing subset (value 1) or a new subset will be created (value 0).\r\n#EndRegion @DOC\r\n\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pHier:%pHier%, pSub:%pSub%, pAddToSubset:%pAddToSubset%, pExclusions:%pExclusions%, pDelim:%pDelim%, pAlias:%pAlias%, pTemp:%pTemp%.'; \r\ncAttributeDim = '}ElementAttributes_' | pDim;\r\nnErrors = 0;\r\n\r\n## LogOutput parameters\r\nIF ( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n## Validate pTemp\r\nIF( pTemp <> 0 & pTemp <> 1 );\r\n nErrors = 1;\r\n sMessage = 'Wrong parameter pTemp value (only 0 or 1 accepted).';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nnRet = ExecuteProcess('}bedrock.hier.sub.create',\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pDim', pDim,\r\n 'pHier',pHier,\r\n 'pSub', pSub,\r\n 'pExclusions', pExclusions,\r\n 'pDelim', pDelim,\r\n 'pAddToSubset', pAddToSubset,\r\n 'pAlias', pAlias,\r\n 'pTemp', pTemp\r\n );\r\n\r\nIf(nRet <> 0);\r\n nErrors = 1;\r\n sMessage = 'Subset create process has errors';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndif;\r\n \r\n### End Prolog ###", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.sub.create.all', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pDim', '', 'pHier', '', 'pSub', '',\r\n \t'pAddToSubset', 0, 'pExclusions', '',\r\n \t'pDelim', '&', 'pAlias', '',\r\n \t'pTemp', 1\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will create a static subset in Hierarchy of a Dimension that consists of all elements.\r\n\r\n# Note:\r\n# This process uses modification parameters to determine what to include in the subset:\r\n# - pExclusions: If pExclusions is specified then the elements (separated by a delimiter) will be\r\n# excluded from the subset. Wildcards characters `*` and `?` are accepted.\r\n# - pAddToSubset: If the specified subset already exists then this parameter will control whether elements will\r\n# be added to the existing subset (value 1) or a new subset will be created (value 0).\r\n#EndRegion @DOC\r\n\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pHier:%pHier%, pSub:%pSub%, pAddToSubset:%pAddToSubset%, pExclusions:%pExclusions%, pDelim:%pDelim%, pAlias:%pAlias%, pTemp:%pTemp%.'; \r\ncAttributeDim = '}ElementAttributes_' | pDim;\r\nnErrors = 0;\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pAlias\": \"\",\r\n \"pDelim\": \"&\",\r\n \"pDim\": null,\r\n \"pExclusions\": \"\",\r\n \"pHier\": \"\",\r\n \"pSub\": null,\r\n \"pAddToSubset\": 0,\r\n \"pLogOutput\": 0,\r\n \"pStrictErrorHandling\": 0,\r\n \"pTemp\": 1\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pAlias\": '|StringToJson ( pAlias )|',\r\n \"pDelim\": '|StringToJson ( pDelim )|',\r\n \"pDim\": '|StringToJson ( pDim )|',\r\n \"pExclusions\": '|StringToJson ( pExclusions )|',\r\n \"pHier\": '|StringToJson ( pHier )|',\r\n \"pSub\": '|StringToJson ( pSub )|',\r\n \"pAddToSubset\": '|NumberToString( pAddToSubset )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|',\r\n \"pTemp\": '|NumberToString( pTemp )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npAlias = JsonToString( JsonGet( pJson, 'pAlias' ) );\r\npDelim = JsonToString( JsonGet( pJson, 'pDelim' ) );\r\npDim = JsonToString( JsonGet( pJson, 'pDim' ) );\r\npExclusions = JsonToString( JsonGet( pJson, 'pExclusions' ) );\r\npHier = JsonToString( JsonGet( pJson, 'pHier' ) );\r\npSub = JsonToString( JsonGet( pJson, 'pSub' ) );\r\n# Numeric Parameters\r\npAddToSubset = StringToNumber( JsonToString( JsonGet( pJson, 'pAddToSubset' ) ) );\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\npTemp = StringToNumber( JsonToString( JsonGet( pJson, 'pTemp' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n## LogOutput parameters\r\nIF ( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n## Validate pTemp\r\nIF( pTemp <> 0 & pTemp <> 1 );\r\n nErrors = 1;\r\n sMessage = 'Wrong parameter pTemp value (only 0 or 1 accepted).';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nnRet = ExecuteProcess('}bedrock.hier.sub.create',\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pDim', pDim,\r\n 'pHier',pHier,\r\n 'pSub', pSub,\r\n 'pExclusions', pExclusions,\r\n 'pDelim', pDelim,\r\n 'pAddToSubset', pAddToSubset,\r\n 'pAlias', pAlias,\r\n 'pTemp', pTemp\r\n );\r\n\r\nIf(nRet <> 0);\r\n nErrors = 1;\r\n sMessage = 'Subset create process has errors';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndif;\r\n \r\n### End Prolog ###", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n### If errors occurred terminate process with a major error status ###\r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully created subset %pSub% from dimension %pDim%.' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n### End Epilog ###\r\n", @@ -10,27 +10,15 @@ "Type": "None" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pDim", - "Prompt": "REQUIRED: Dimension name", + "Prompt": "REQUIRED: Delimited list of dimensions", "Value": "", "Type": "String" }, { "Name": "pHier", - "Prompt": "OPTIONAL: Hierarchy name (default if blank = same named hierarchy)", + "Prompt": "OPTIONAL: Hierarchy name (Default = pDim)", "Value": "", "Type": "String" }, @@ -42,33 +30,51 @@ }, { "Name": "pAddToSubset", - "Prompt": "OPTIONAL: Add to Subset if it Already Exists (0=No 1=Yes)", + "Prompt": "OPTIONAL: Add to subset if it already exists (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { "Name": "pExclusions", - "Prompt": "OPTIONAL: Elements to Exclude From Subset (Separated by Delimiter, Accepts Wild card)", + "Prompt": "OPTIONAL: Delimited list of elements to exclude", "Value": "", "Type": "String" }, { "Name": "pDelim", - "Prompt": "OPTIONAL: Delimiter character", + "Prompt": "OPTIONAL: Delimiter for list parameters (Default = '&')", "Value": "&", "Type": "String" }, { "Name": "pAlias", - "Prompt": "OPTIONAL: Set Alias for Subset", + "Prompt": "OPTIONAL: Set alias for subset", "Value": "", "Type": "String" }, { "Name": "pTemp", - "Prompt": "OPTIONAL: Use temporary objects? (Boolean 1=True)", + "Prompt": "OPTIONAL: Delete/create temporary objects (0 = Do not delete, 1 = Delete, 2 = if view and subsets are created, keep only subsets)", "Value": 1, "Type": "Numeric" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [], diff --git a/bedrock_processes_json/}bedrock.hier.sub.create.attribute.all.json b/bedrock_processes_json/}bedrock.hier.sub.create.attribute.all.json index b197113..c0da427 100644 --- a/bedrock_processes_json/}bedrock.hier.sub.create.attribute.all.json +++ b/bedrock_processes_json/}bedrock.hier.sub.create.attribute.all.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.hier.sub.create.attribute.all", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.sub.create.attribute.all', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pDim', '', 'pHier', '', 'pSub', '',\r\n \t'pAttr', '', 'pAttrValue', '',\r\n \t'pAddToSubset', 0, 'pExclusions', '',\r\n \t'pDelim', '&', 'pAlias', '', 'pTemp', 1\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will create a static subset in Hierarchy of a Dimension that consists of all\r\n# elements with pAttr attribute value equivalent to pAttrValue.\r\n\r\n# Note:\r\n# This process uses a modification parameters to determine what to include in the subset:\r\n# - pAttr: If specified, only elements that have a value equivalent to pAttrValue will be included\r\n# in the subset. If blank, this filter will be ignored.\r\n# - pExclusions: If pExclusions is specified then the elements (separated by a delimiter) will be\r\n# excluded from the subset. Wildcards characters `*` and `?` are accepted.\r\n# - pAddToSubset: If the specified subset already exists then this parameter will control whether elements will\r\n# be added to the existing subset (value 1) or a new subset will be created (value 0).\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pHier:%pHier%, pSub:%pSub%, pAttr:%pAttr%, pAttrValue:%pAttrValue%, pExclusions:%pExclusions%, pDelim:%pDelim%, pAddToSubset:%pAddToSubset%, pAlias:%pAlias%, pTemp:%pTemp%.'; \r\ncAttributeDim = '}ElementAttributes_' | pDim;\r\nnErrors = 0;\r\n\r\n## LogOutput parameters\r\nIF ( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n## Validate pTemp\r\nIF( pTemp <> 0 & pTemp <> 1 );\r\n nErrors = 1;\r\n sMessage = 'Wrong parameter pTemp value (only 0 or 1 accepted).';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nnRet = ExecuteProcess('}bedrock.hier.sub.create',\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pDim', pDim,\r\n 'pHier', pHier,\r\n 'pSub', pSub,\r\n 'pAttr', pAttr,\r\n 'pAttrValue', pAttrValue,\r\n 'pExclusions', pExclusions,\r\n 'pDelim', pDelim,\r\n 'pAddToSubset', pAddToSubset,\r\n 'pAlias', pAlias,\r\n 'pTemp', pTemp\r\n );\r\n\r\n### End Prolog ###", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.sub.create.attribute.all', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pDim', '', 'pHier', '', 'pSub', '',\r\n \t'pAttr', '', 'pAttrValue', '',\r\n \t'pAddToSubset', 0, 'pExclusions', '',\r\n \t'pDelim', '&', 'pAlias', '', 'pTemp', 1\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will create a static subset in Hierarchy of a Dimension that consists of all\r\n# elements with pAttr attribute value equivalent to pAttrValue.\r\n\r\n# Note:\r\n# This process uses a modification parameters to determine what to include in the subset:\r\n# - pAttr: If specified, only elements that have a value equivalent to pAttrValue will be included\r\n# in the subset. If blank, this filter will be ignored.\r\n# - pExclusions: If pExclusions is specified then the elements (separated by a delimiter) will be\r\n# excluded from the subset. Wildcards characters `*` and `?` are accepted.\r\n# - pAddToSubset: If the specified subset already exists then this parameter will control whether elements will\r\n# be added to the existing subset (value 1) or a new subset will be created (value 0).\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pHier:%pHier%, pSub:%pSub%, pAttr:%pAttr%, pAttrValue:%pAttrValue%, pExclusions:%pExclusions%, pDelim:%pDelim%, pAddToSubset:%pAddToSubset%, pAlias:%pAlias%, pTemp:%pTemp%.'; \r\ncAttributeDim = '}ElementAttributes_' | pDim;\r\nnErrors = 0;\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pAlias\": \"\",\r\n \"pAttr\": \"\",\r\n \"pAttrValue\": \"\",\r\n \"pDelim\": \"&\",\r\n \"pDim\": null,\r\n \"pExclusions\": \"\",\r\n \"pHier\": \"\",\r\n \"pSub\": null,\r\n \"pAddToSubset\": 0,\r\n \"pLogOutput\": 0,\r\n \"pStrictErrorHandling\": 0,\r\n \"pTemp\": 1\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pAlias\": '|StringToJson ( pAlias )|',\r\n \"pAttr\": '|StringToJson ( pAttr )|',\r\n \"pAttrValue\": '|StringToJson ( pAttrValue )|',\r\n \"pDelim\": '|StringToJson ( pDelim )|',\r\n \"pDim\": '|StringToJson ( pDim )|',\r\n \"pExclusions\": '|StringToJson ( pExclusions )|',\r\n \"pHier\": '|StringToJson ( pHier )|',\r\n \"pSub\": '|StringToJson ( pSub )|',\r\n \"pAddToSubset\": '|NumberToString( pAddToSubset )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|',\r\n \"pTemp\": '|NumberToString( pTemp )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npAlias = JsonToString( JsonGet( pJson, 'pAlias' ) );\r\npAttr = JsonToString( JsonGet( pJson, 'pAttr' ) );\r\npAttrValue = JsonToString( JsonGet( pJson, 'pAttrValue' ) );\r\npDelim = JsonToString( JsonGet( pJson, 'pDelim' ) );\r\npDim = JsonToString( JsonGet( pJson, 'pDim' ) );\r\npExclusions = JsonToString( JsonGet( pJson, 'pExclusions' ) );\r\npHier = JsonToString( JsonGet( pJson, 'pHier' ) );\r\npSub = JsonToString( JsonGet( pJson, 'pSub' ) );\r\n# Numeric Parameters\r\npAddToSubset = StringToNumber( JsonToString( JsonGet( pJson, 'pAddToSubset' ) ) );\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\npTemp = StringToNumber( JsonToString( JsonGet( pJson, 'pTemp' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n## LogOutput parameters\r\nIF ( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n## Validate pTemp\r\nIF( pTemp <> 0 & pTemp <> 1 );\r\n nErrors = 1;\r\n sMessage = 'Wrong parameter pTemp value (only 0 or 1 accepted).';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nnRet = ExecuteProcess('}bedrock.hier.sub.create',\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pDim', pDim,\r\n 'pHier', pHier,\r\n 'pSub', pSub,\r\n 'pAttr', pAttr,\r\n 'pAttrValue', pAttrValue,\r\n 'pExclusions', pExclusions,\r\n 'pDelim', pDelim,\r\n 'pAddToSubset', pAddToSubset,\r\n 'pAlias', pAlias,\r\n 'pTemp', pTemp\r\n );\r\n\r\n### End Prolog ###", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully created subset %pSub% from dimension %pDim%.' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n### End Epilog ###\r\n", @@ -10,27 +10,15 @@ "Type": "None" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pDim", - "Prompt": "REQUIRED: Dimension name", + "Prompt": "REQUIRED: Delimited list of dimensions", "Value": "", "Type": "String" }, { "Name": "pHier", - "Prompt": "OPTIONAL: Hierarchy name (default if blank = same named hierarchy)", + "Prompt": "OPTIONAL: Hierarchy name (Default = pDim)", "Value": "", "Type": "String" }, @@ -48,39 +36,57 @@ }, { "Name": "pAttrValue", - "Prompt": "OPTIONAL: Attribute Value", + "Prompt": "OPTIONAL: Attribute value", "Value": "", "Type": "String" }, { "Name": "pAddToSubset", - "Prompt": "OPTIONAL: Add to Subset if it Already Exists (0=No 1=Yes)", + "Prompt": "OPTIONAL: Add to subset if it already exists (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { "Name": "pExclusions", - "Prompt": "OPTIONAL: Elements to Exclude From Subset (Separated by Delimiter, Accepts Wild card)", + "Prompt": "OPTIONAL: Delimited list of elements to exclude", "Value": "", "Type": "String" }, { "Name": "pDelim", - "Prompt": "OPTIONAL: Delimiter character", + "Prompt": "OPTIONAL: Delimiter for list parameters (Default = '&')", "Value": "&", "Type": "String" }, { "Name": "pAlias", - "Prompt": "OPTIONAL: Set Alias for Subset", + "Prompt": "OPTIONAL: Set alias for subset", "Value": "", "Type": "String" }, { "Name": "pTemp", - "Prompt": "OPTIONAL: Use temporary objects? (Boolean 1=True)", + "Prompt": "OPTIONAL: Delete/create temporary objects (0 = Do not delete, 1 = Delete, 2 = if view and subsets are created, keep only subsets)", "Value": 1, "Type": "Numeric" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [], diff --git a/bedrock_processes_json/}bedrock.hier.sub.create.attribute.leaf.json b/bedrock_processes_json/}bedrock.hier.sub.create.attribute.leaf.json index 322df48..15b06a1 100644 --- a/bedrock_processes_json/}bedrock.hier.sub.create.attribute.leaf.json +++ b/bedrock_processes_json/}bedrock.hier.sub.create.attribute.leaf.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.hier.sub.create.attribute.leaf", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.sub.create.attribute.leaf', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pDim', '', 'pHier', '', 'pSub', '',\r\n \t'pAttr', '', 'pAttrValue', '',\r\n \t'pAddToSubset', 0, 'pExclusions', '',\r\n \t'pDelim', '&', 'pAlias', '', 'pTemp', 1\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will create a static subset in Hierarchy of a Dimension that consists of all\r\n# leaf elements with pAttr attribute value equivalent to pAttrValue.\r\n\r\n# Note:\r\n# This process uses a modification parameters to determine what to include in the subset:\r\n# - pAttr: If specified, only elements that have a value equivalent to pAttrValue will be included\r\n# in the subset. If blank, this filter will be ignored.\r\n# - pExclusions: If pExclusions is specified then the elements (separated by a delimiter) will be\r\n# excluded from the subset. Wildcards characters `*` and `?` are accepted.\r\n# - pAddToSubset: If the specified subset already exists then this parameter will control whether elements will\r\n# be added to the existing subset (value 1) or a new subset will be created (value 0).\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\nnErrors = 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pHier:%pHier%, pSub:%pSub%, pAttr:%pAttr%, pAttrValue:%pAttrValue%, pExclusions:%pExclusions%, pDelim:%pDelim%, pAddToSubset:%pAddToSubset%, pAlias:%pAlias%, pTemp:%pTemp%.'; \r\ncAttributeDim = '}ElementAttributes_' | pDim;\r\n\r\n## LogOutput parameters\r\nIF ( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\nnRet = ExecuteProcess('}bedrock.hier.sub.create',\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pDim', pDim,\r\n 'pHier', pHier,\r\n 'pSub', pSub,\r\n 'pAttr', pAttr,\r\n 'pAttrValue', pAttrValue,\r\n 'pLevelFrom', 0,\r\n 'pLevelTo', 0,\r\n 'pExclusions', pExclusions,\r\n 'pDelim', pDelim,\r\n 'pAddToSubset', pAddToSubset,\r\n 'pAlias', pAlias,\r\n 'pTemp', pTemp\r\n );\r\n\r\n\r\n### End Prolog ###", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.sub.create.attribute.leaf', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pDim', '', 'pHier', '', 'pSub', '',\r\n \t'pAttr', '', 'pAttrValue', '',\r\n \t'pAddToSubset', 0, 'pExclusions', '',\r\n \t'pDelim', '&', 'pAlias', '', 'pTemp', 1\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will create a static subset in Hierarchy of a Dimension that consists of all\r\n# leaf elements with pAttr attribute value equivalent to pAttrValue.\r\n\r\n# Note:\r\n# This process uses a modification parameters to determine what to include in the subset:\r\n# - pAttr: If specified, only elements that have a value equivalent to pAttrValue will be included\r\n# in the subset. If blank, this filter will be ignored.\r\n# - pExclusions: If pExclusions is specified then the elements (separated by a delimiter) will be\r\n# excluded from the subset. Wildcards characters `*` and `?` are accepted.\r\n# - pAddToSubset: If the specified subset already exists then this parameter will control whether elements will\r\n# be added to the existing subset (value 1) or a new subset will be created (value 0).\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\nnErrors = 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pHier:%pHier%, pSub:%pSub%, pAttr:%pAttr%, pAttrValue:%pAttrValue%, pExclusions:%pExclusions%, pDelim:%pDelim%, pAddToSubset:%pAddToSubset%, pAlias:%pAlias%, pTemp:%pTemp%.'; \r\ncAttributeDim = '}ElementAttributes_' | pDim;\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pAlias\": \"\",\r\n \"pAttr\": \"\",\r\n \"pAttrValue\": \"\",\r\n \"pDelim\": \"&\",\r\n \"pDim\": null,\r\n \"pExclusions\": \"\",\r\n \"pHier\": \"\",\r\n \"pSub\": null,\r\n \"pAddToSubset\": 0,\r\n \"pLogOutput\": 0,\r\n \"pStrictErrorHandling\": 0,\r\n \"pTemp\": 1\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pAlias\": '|StringToJson ( pAlias )|',\r\n \"pAttr\": '|StringToJson ( pAttr )|',\r\n \"pAttrValue\": '|StringToJson ( pAttrValue )|',\r\n \"pDelim\": '|StringToJson ( pDelim )|',\r\n \"pDim\": '|StringToJson ( pDim )|',\r\n \"pExclusions\": '|StringToJson ( pExclusions )|',\r\n \"pHier\": '|StringToJson ( pHier )|',\r\n \"pSub\": '|StringToJson ( pSub )|',\r\n \"pAddToSubset\": '|NumberToString( pAddToSubset )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|',\r\n \"pTemp\": '|NumberToString( pTemp )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npAlias = JsonToString( JsonGet( pJson, 'pAlias' ) );\r\npAttr = JsonToString( JsonGet( pJson, 'pAttr' ) );\r\npAttrValue = JsonToString( JsonGet( pJson, 'pAttrValue' ) );\r\npDelim = JsonToString( JsonGet( pJson, 'pDelim' ) );\r\npDim = JsonToString( JsonGet( pJson, 'pDim' ) );\r\npExclusions = JsonToString( JsonGet( pJson, 'pExclusions' ) );\r\npHier = JsonToString( JsonGet( pJson, 'pHier' ) );\r\npSub = JsonToString( JsonGet( pJson, 'pSub' ) );\r\n# Numeric Parameters\r\npAddToSubset = StringToNumber( JsonToString( JsonGet( pJson, 'pAddToSubset' ) ) );\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\npTemp = StringToNumber( JsonToString( JsonGet( pJson, 'pTemp' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n## LogOutput parameters\r\nIF ( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\nnRet = ExecuteProcess('}bedrock.hier.sub.create',\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pDim', pDim,\r\n 'pHier', pHier,\r\n 'pSub', pSub,\r\n 'pAttr', pAttr,\r\n 'pAttrValue', pAttrValue,\r\n 'pLevelFrom', 0,\r\n 'pLevelTo', 0,\r\n 'pExclusions', pExclusions,\r\n 'pDelim', pDelim,\r\n 'pAddToSubset', pAddToSubset,\r\n 'pAlias', pAlias,\r\n 'pTemp', pTemp\r\n );\r\n\r\n\r\n### End Prolog ###", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully created subset %pSub% from dimension %pDim%.' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n### End Epilog ###\r\n", @@ -10,27 +10,15 @@ "Type": "None" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pDim", - "Prompt": "REQUIRED: Dimension name", + "Prompt": "REQUIRED: Delimited list of dimensions", "Value": "", "Type": "String" }, { "Name": "pHier", - "Prompt": "OPTIONAL: Hierarchy name (default if blank = same named hierarchy)", + "Prompt": "OPTIONAL: Hierarchy name (Default = pDim)", "Value": "", "Type": "String" }, @@ -48,39 +36,57 @@ }, { "Name": "pAttrValue", - "Prompt": "OPTIONAL: Attribute Value", + "Prompt": "OPTIONAL: Attribute value", "Value": "", "Type": "String" }, { "Name": "pAddToSubset", - "Prompt": "OPTIONAL: Add to Subset if it Already Exists (0=No 1=Yes)", + "Prompt": "OPTIONAL: Add to subset if it already exists (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { "Name": "pExclusions", - "Prompt": "OPTIONAL: Elements to Exclude From Subset (Separated by Delimiter, Accepts Wild card)", + "Prompt": "OPTIONAL: Delimited list of elements to exclude", "Value": "", "Type": "String" }, { "Name": "pDelim", - "Prompt": "OPTIONAL: Delimiter character", + "Prompt": "OPTIONAL: Delimiter for list parameters (Default = '&')", "Value": "&", "Type": "String" }, { "Name": "pAlias", - "Prompt": "OPTIONAL: Set Alias for Subset", + "Prompt": "OPTIONAL: Set alias for subset", "Value": "", "Type": "String" }, { "Name": "pTemp", - "Prompt": "OPTIONAL: Use temporary objects? (Boolean 1=True)", + "Prompt": "OPTIONAL: Delete/create temporary objects (0 = Do not delete, 1 = Delete, 2 = if view and subsets are created, keep only subsets)", "Value": 1, "Type": "Numeric" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [], diff --git a/bedrock_processes_json/}bedrock.hier.sub.create.byelement.json b/bedrock_processes_json/}bedrock.hier.sub.create.byelement.json index 5e11761..b759b8f 100644 --- a/bedrock_processes_json/}bedrock.hier.sub.create.byelement.json +++ b/bedrock_processes_json/}bedrock.hier.sub.create.byelement.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.hier.sub.create.byelement", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.sub.create.byelement', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pDim', '', 'pHier', '', 'pSub', '',\r\n \t'pEle', '', 'pDelim', '&',\r\n \t'pAddToSubset', 0, 'pExpandConsol', 1,\r\n \t'pAlias', '', 'pTemp', 1\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will create a static subset in a Hierarchy of target Dimension based on a list of\r\n# supplied elements.\r\n\r\n# Note:\r\n# - pAddToSubset: If the specified subset already exists then this parameter will control whether elements will\r\n# be added to the existing subset (value 1) or a new subset will be created (value 0).\r\n# - pExpandConsol: If the specified list of elements contains consolidated elements they will be replaced with \r\n# their leaf level descendants\r\n# Caution: Process doesn't accept wildcards in element names.\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pHier:%pHier%, pSub:%pSub%, pEle:%pEle%, pDelim:%pDelim%, pAddToSubset:%pAddToSubset%, pExpandConsol:%pExpandConsol%, pAlias:%pAlias%, pTemp:%pTemp%.'; \r\ncAttributeDim = '}ElementAttributes_' | pDim;\r\n\r\n## LogOutput parameters\r\nIF ( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n\r\n### Validate Parameters ###\r\n\r\nnErrors = 0;\r\n\r\nIf( Scan( ':', pDim ) > 0 & pHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pHier = SubSt( pDim, Scan( ':', pDim ) + 1, Long( pDim ) );\r\n pDim = SubSt( pDim, 1, Scan( ':', pDim ) - 1 );\r\nEndIf;\r\n\r\n# Validate dimension\r\n\r\nIf( Trim( pDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No dimension specified';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\nIf( DimensionExists( pDim ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid dimension: ' | pDim;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n## Validate Hierarchy\r\n\r\nIF(pHier @= 'Leaves' );\r\n nErrors = 1;\r\n sMessage = 'Invalid Hierarchy: ' | pDim |':'|pHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nIf( Trim( pHier ) @= '' );\r\n sHier = pDim;\r\nElse;\r\n sHier = pHier;\r\nEndIf;\r\n\r\nIF(HierarchyExists(pDim, pHier ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid dimension Hierarchy: ' | pDim |':'|pHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate subset\r\nIf( Trim( pSub ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No subset specified';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate elements\r\nIf( Trim( pEle ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No elements specified';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate delimiter\r\nIf( pDelim @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\n# Validate add to subset\r\nIf( pAddToSubset <> 0 & pAddToSubset <> 1 );\r\n nErrors = 1;\r\n sMessage = 'Invalid value for pAddToSubset: ' | NumberToString( pAddToSubset ) | '. Valid values are 0 and 1';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate expand consolidations\r\nIf( pExpandConsol <> 0 & pExpandConsol <> 1 & pExpandConsol <> 2 );\r\n nErrors = 1;\r\n sMessage = 'Invalid value for pExpandConsol: ' | NumberToString( pExpandConsol ) | '. Valid values are 0, 1 and 2';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n## Validate Alias\r\nsDimAttr = '}ElementAttributes_' | pDim;\r\nIF(pAlias @<> '' );\r\n IF(DimensionExists( sDimAttr ) = 0 );\r\n sMessage = 'No attributes exist for the dimension: ' | pDim;\r\n pAlias = '';\r\n EndIf;\r\n\r\n IF(DIMIX( sDimAttr, pAlias ) = 0 );\r\n sMessage = 'The Alias: ' | pAlias | ' does not exist in the dimension: ' | pDim;\r\n pAlias = '';\r\n EndIf;\r\n\r\n IF(\r\n DTYPE( sDimAttr, pAlias ) @<> 'AA' );\r\n sMessage = 'The Alias: ' | pAlias | ' is not an Alias in the dimension: ' | sDimAttr;\r\n pAlias = '';\r\n EndIf;\r\nENDIF;\r\n\r\n## Validate pTemp\r\nIF( pTemp <> 0 & pTemp <> 1 );\r\n nErrors = 1;\r\n sMessage = 'Wrong parameter pTemp value (only 0 or 1 accepted).';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### Prepare subset ###\r\nIf( HierarchySubsetExists( pDim, pHier, pSub ) = 1 );\r\n If( pAddtoSubset <> 1 );\r\n HierarchySubsetDeleteAllElements( pDim, pHier, pSub );\r\n EndIf;\r\nElse;\r\n If( nErrors = 0 );\r\n HierarchySubsetCreate( pDim, pHier, pSub, pTemp );\r\n EndIf;\r\nEndIf;\r\n\r\n### Assign Alias to subset\r\nIF(pAlias @<> '' );\r\n HierarchySubsetAliasSet( pDim, pHier, pSub, pAlias );\r\nENDIF;\r\n\r\n### Insert elements ###\r\n\r\nsElements = pEle;\r\nnDelimIndex = 1;\r\n\r\n# Split filter into separate dimensions\r\nWhile( nDelimIndex <> 0 & Long( sElements ) > 0 );\r\n\r\n nDelimIndex = Scan( pDelim, sElements );\r\n If( nDelimIndex <> 0 );\r\n sElement = Trim( SubSt( sElements, 1, nDelimIndex - 1 ) );\r\n sElements = Trim( SubSt( sElements, nDelimIndex + Long( pDelim ), Long( sElements ) ) );\r\n Else;\r\n sElement = Trim( sElements );\r\n EndIf;\r\n\r\n If( ElementIndex( pDim, pHier, sElement ) <> 0 );\r\n If( nErrors = 0 );\r\n IF( ElementLevel( pDim, pHier, sElement) > 0 );\r\n If( pExpandConsol = 1 );\r\n ExecuteProcess('}bedrock.hier.sub.create',\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pDim', pDim,\r\n 'pHier',pHier,\r\n 'pSub', pSub,\r\n 'pConsol', sElement,\r\n 'pExclusions', '',\r\n 'pDelim', pDelim,\r\n 'pAddToSubset', 1,\r\n 'pAlias', '',\r\n 'pTemp', pTemp\r\n );\r\n ElseIf( pExpandConsol = 2 );\r\n ExecuteProcess('}bedrock.hier.sub.create',\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pDim', pDim,\r\n 'pHier',pHier,\r\n 'pSub', pSub,\r\n 'pConsol', sElement,\r\n 'pLevelFrom', 0,\r\n 'pLevelTo', 0,\r\n 'pExclusions', '',\r\n 'pDelim', pDelim,\r\n 'pAddToSubset', 1,\r\n 'pAlias', '',\r\n 'pTemp', pTemp\r\n );\r\n Else;\r\n HierarchySubsetElementInsert( pDim, pHier, pSub, sElement, 0 );\r\n EndIf;\r\n ELSE;\r\n HierarchySubsetElementInsert( pDim, pHier, pSub, sElement, 0 );\r\n ENDIF;\r\n EndIf;\r\n EndIf;\r\nEnd;\r\n\r\n\r\n### End Prolog ###", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.sub.create.byelement', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pDim', '', 'pHier', '', 'pSub', '',\r\n \t'pEle', '', 'pDelim', '&',\r\n \t'pAddToSubset', 0, 'pExpandConsol', 1,\r\n \t'pAlias', '', 'pTemp', 1\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will create a static subset in a Hierarchy of target Dimension based on a list of\r\n# supplied elements.\r\n\r\n# Note:\r\n# - pAddToSubset: If the specified subset already exists then this parameter will control whether elements will\r\n# be added to the existing subset (value 1) or a new subset will be created (value 0).\r\n# - pExpandConsol: If the specified list of elements contains consolidated elements they will be replaced with \r\n# their leaf level descendants\r\n# Caution: Process doesn't accept wildcards in element names.\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pHier:%pHier%, pSub:%pSub%, pEle:%pEle%, pDelim:%pDelim%, pAddToSubset:%pAddToSubset%, pExpandConsol:%pExpandConsol%, pAlias:%pAlias%, pTemp:%pTemp%.'; \r\ncAttributeDim = '}ElementAttributes_' | pDim;\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pAlias\": \"\",\r\n \"pDelim\": \"&\",\r\n \"pDim\": null,\r\n \"pEle\": null,\r\n \"pHier\": \"\",\r\n \"pSub\": null,\r\n \"pAddToSubset\": 0,\r\n \"pExpandConsol\": 1,\r\n \"pLogOutput\": 0,\r\n \"pStrictErrorHandling\": 0,\r\n \"pTemp\": 1\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pAlias\": '|StringToJson ( pAlias )|',\r\n \"pDelim\": '|StringToJson ( pDelim )|',\r\n \"pDim\": '|StringToJson ( pDim )|',\r\n \"pEle\": '|StringToJson ( pEle )|',\r\n \"pHier\": '|StringToJson ( pHier )|',\r\n \"pSub\": '|StringToJson ( pSub )|',\r\n \"pAddToSubset\": '|NumberToString( pAddToSubset )|',\r\n \"pExpandConsol\": '|NumberToString( pExpandConsol )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|',\r\n \"pTemp\": '|NumberToString( pTemp )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npAlias = JsonToString( JsonGet( pJson, 'pAlias' ) );\r\npDelim = JsonToString( JsonGet( pJson, 'pDelim' ) );\r\npDim = JsonToString( JsonGet( pJson, 'pDim' ) );\r\npEle = JsonToString( JsonGet( pJson, 'pEle' ) );\r\npHier = JsonToString( JsonGet( pJson, 'pHier' ) );\r\npSub = JsonToString( JsonGet( pJson, 'pSub' ) );\r\n# Numeric Parameters\r\npAddToSubset = StringToNumber( JsonToString( JsonGet( pJson, 'pAddToSubset' ) ) );\r\npExpandConsol = StringToNumber( JsonToString( JsonGet( pJson, 'pExpandConsol' ) ) );\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\npTemp = StringToNumber( JsonToString( JsonGet( pJson, 'pTemp' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n## LogOutput parameters\r\nIF ( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n\r\n### Validate Parameters ###\r\n\r\nnErrors = 0;\r\n\r\nIf( Scan( ':', pDim ) > 0 & pHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pHier = SubSt( pDim, Scan( ':', pDim ) + 1, Long( pDim ) );\r\n pDim = SubSt( pDim, 1, Scan( ':', pDim ) - 1 );\r\nEndIf;\r\n\r\n# Validate dimension\r\n\r\nIf( Trim( pDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No dimension specified';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\nIf( DimensionExists( pDim ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid dimension: ' | pDim;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n## Validate Hierarchy\r\n\r\nIF(pHier @= 'Leaves' );\r\n nErrors = 1;\r\n sMessage = 'Invalid Hierarchy: ' | pDim |':'|pHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nIf( Trim( pHier ) @= '' );\r\n sHier = pDim;\r\nElse;\r\n sHier = pHier;\r\nEndIf;\r\n\r\nIF(HierarchyExists(pDim, pHier ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid dimension Hierarchy: ' | pDim |':'|pHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate subset\r\nIf( Trim( pSub ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No subset specified';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate elements\r\nIf( Trim( pEle ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No elements specified';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate delimiter\r\nIf( pDelim @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\n# Validate add to subset\r\nIf( pAddToSubset <> 0 & pAddToSubset <> 1 );\r\n nErrors = 1;\r\n sMessage = 'Invalid value for pAddToSubset: ' | NumberToString( pAddToSubset ) | '. Valid values are 0 and 1';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate expand consolidations\r\nIf( pExpandConsol <> 0 & pExpandConsol <> 1 & pExpandConsol <> 2 );\r\n nErrors = 1;\r\n sMessage = 'Invalid value for pExpandConsol: ' | NumberToString( pExpandConsol ) | '. Valid values are 0, 1 and 2';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n## Validate Alias\r\nsDimAttr = '}ElementAttributes_' | pDim;\r\nIF(pAlias @<> '' );\r\n IF(DimensionExists( sDimAttr ) = 0 );\r\n sMessage = 'No attributes exist for the dimension: ' | pDim;\r\n pAlias = '';\r\n EndIf;\r\n\r\n IF(DIMIX( sDimAttr, pAlias ) = 0 );\r\n sMessage = 'The Alias: ' | pAlias | ' does not exist in the dimension: ' | pDim;\r\n pAlias = '';\r\n EndIf;\r\n\r\n IF(\r\n DTYPE( sDimAttr, pAlias ) @<> 'AA' );\r\n sMessage = 'The Alias: ' | pAlias | ' is not an Alias in the dimension: ' | sDimAttr;\r\n pAlias = '';\r\n EndIf;\r\nENDIF;\r\n\r\n## Validate pTemp\r\nIF( pTemp <> 0 & pTemp <> 1 );\r\n nErrors = 1;\r\n sMessage = 'Wrong parameter pTemp value (only 0 or 1 accepted).';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### Prepare subset ###\r\nIf( HierarchySubsetExists( pDim, pHier, pSub ) = 1 );\r\n If( pAddtoSubset <> 1 );\r\n HierarchySubsetDeleteAllElements( pDim, pHier, pSub );\r\n EndIf;\r\nElse;\r\n If( nErrors = 0 );\r\n HierarchySubsetCreate( pDim, pHier, pSub, pTemp );\r\n EndIf;\r\nEndIf;\r\n\r\n### Assign Alias to subset\r\nIF(pAlias @<> '' );\r\n HierarchySubsetAliasSet( pDim, pHier, pSub, pAlias );\r\nENDIF;\r\n\r\n### Insert elements ###\r\n\r\nsElements = pEle;\r\nnDelimIndex = 1;\r\n\r\n# Split filter into separate dimensions\r\nWhile( nDelimIndex <> 0 & Long( sElements ) > 0 );\r\n\r\n nDelimIndex = Scan( pDelim, sElements );\r\n If( nDelimIndex <> 0 );\r\n sElement = Trim( SubSt( sElements, 1, nDelimIndex - 1 ) );\r\n sElements = Trim( SubSt( sElements, nDelimIndex + Long( pDelim ), Long( sElements ) ) );\r\n Else;\r\n sElement = Trim( sElements );\r\n EndIf;\r\n\r\n If( ElementIndex( pDim, pHier, sElement ) <> 0 );\r\n If( nErrors = 0 );\r\n IF( ElementLevel( pDim, pHier, sElement) > 0 );\r\n If( pExpandConsol = 1 );\r\n ExecuteProcess('}bedrock.hier.sub.create',\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pDim', pDim,\r\n 'pHier',pHier,\r\n 'pSub', pSub,\r\n 'pConsol', sElement,\r\n 'pExclusions', '',\r\n 'pDelim', pDelim,\r\n 'pAddToSubset', 1,\r\n 'pAlias', '',\r\n 'pTemp', pTemp\r\n );\r\n ElseIf( pExpandConsol = 2 );\r\n ExecuteProcess('}bedrock.hier.sub.create',\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pDim', pDim,\r\n 'pHier',pHier,\r\n 'pSub', pSub,\r\n 'pConsol', sElement,\r\n 'pLevelFrom', 0,\r\n 'pLevelTo', 0,\r\n 'pExclusions', '',\r\n 'pDelim', pDelim,\r\n 'pAddToSubset', 1,\r\n 'pAlias', '',\r\n 'pTemp', pTemp\r\n );\r\n Else;\r\n HierarchySubsetElementInsert( pDim, pHier, pSub, sElement, 0 );\r\n EndIf;\r\n ELSE;\r\n HierarchySubsetElementInsert( pDim, pHier, pSub, sElement, 0 );\r\n ENDIF;\r\n EndIf;\r\n EndIf;\r\nEnd;\r\n\r\n\r\n### End Prolog ###", "MetadataProcedure": "#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "DataProcedure": "#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully created subset %pSub% from dimension %pDim%.' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n### End Epilog ###", @@ -10,27 +10,15 @@ "Type": "None" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pDim", - "Prompt": "REQUIRED: Dimension name", + "Prompt": "REQUIRED: Delimited list of dimensions", "Value": "", "Type": "String" }, { "Name": "pHier", - "Prompt": "OPTIONAL: Hierarchy name (default if blank = same named hierarchy)", + "Prompt": "OPTIONAL: Hierarchy name (Default = pDim)", "Value": "", "Type": "String" }, @@ -42,39 +30,57 @@ }, { "Name": "pEle", - "Prompt": "REQUIRED: Elements Separated by Delimiter", + "Prompt": "REQUIRED: Delimited list of elements", "Value": "", "Type": "String" }, { "Name": "pDelim", - "Prompt": "OPTIONAL: Delimiter character", + "Prompt": "OPTIONAL: Delimiter for list parameters (Default = '&')", "Value": "&", "Type": "String" }, { "Name": "pAddToSubset", - "Prompt": "OPTIONAL: Add to Subset if it Already Exists (0=No 1=Yes)", + "Prompt": "OPTIONAL: Add to subset if it already exists (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { "Name": "pExpandConsol", - "Prompt": "OPTIONAL: Replace consolidations with their descendants or their leaf level descendants (0=No 1=Descendants 2=Leaf Level Descendants)", + "Prompt": "OPTIONAL: Replace consolidations with their descendants or their leaf level descendants (0 = No, 1 = Descendants, 2 = N Level Descendants. Default = 1)", "Value": 1, "Type": "Numeric" }, { "Name": "pAlias", - "Prompt": "OPTIONAL: Set Alias for Subset", + "Prompt": "OPTIONAL: Set alias for subset", "Value": "", "Type": "String" }, { "Name": "pTemp", - "Prompt": "OPTIONAL: Use temporary objects? (Boolean 1=True)", + "Prompt": "OPTIONAL: Delete/create temporary objects (0 = Do not delete, 1 = Delete, 2 = if view and subsets are created, keep only subsets)", "Value": 1, "Type": "Numeric" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [], diff --git a/bedrock_processes_json/}bedrock.hier.sub.create.bylevel.json b/bedrock_processes_json/}bedrock.hier.sub.create.bylevel.json index 31dcef7..c11b000 100644 --- a/bedrock_processes_json/}bedrock.hier.sub.create.bylevel.json +++ b/bedrock_processes_json/}bedrock.hier.sub.create.bylevel.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.hier.sub.create.bylevel", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.sub.create.bylevel', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pDim', '', 'pHier', '',\r\n \t'pSort', 0, 'pConvertStatic', 1,\r\n \t'pAlias', '', 'pTemp', 1\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process creates static subsets named \"All level \" for the specified consolidation\r\n# levels in a Hierarchy of a Dimension.\r\n\r\n# Note:\r\n# Option to sort subset is available only for sorting per element principal names.\r\n\r\n# Caution: Target hierarchy cannot be `Leaves`.\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pHier:%pHier%, pSort:%pSort%, pConvertStatic:%pConvertStatic%, pAlias:%pAlias%, pTemp:%pTemp%.'; \r\ncAttributeDim = '}ElementAttributes_' | pDim;\r\ncSubs = '' ;\r\n\r\n## LogOutput parameters\r\nIF ( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n\r\n### Validate Parameters ###\r\n\r\nnErrors = 0;\r\n\r\nIf( Scan( ':', pDim ) > 0 & pHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pHier = SubSt( pDim, Scan( ':', pDim ) + 1, Long( pDim ) );\r\n pDim = SubSt( pDim, 1, Scan( ':', pDim ) - 1 );\r\nEndIf;\r\n\r\n# Validate dimension\r\nIf( Trim( pDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No dimension specified';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\nIf( DimensionExists( pDim ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid dimension: ' | pDim;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n## Validate Hierarchy\r\nIF(pHier @= 'Leaves' );\r\n nErrors = 1;\r\n sMessage = 'Invalid Hierarchy: ' | pDim |':'|pHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nIf( Trim( pHier ) @= '' );\r\n sHier = pDim;\r\nElse;\r\n sHier = pHier;\r\nEndIf;\r\n\r\nIF(HierarchyExists(pDim, sHier ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid dimension Hierarchy: ' | pDim |':'|sHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n## Validate Alias\r\nIF(pAlias @<> '' );\r\n\r\n sDimAttr = '}ElementAttributes_' | pDim;\r\n IF(\r\n DimensionExists( sDimAttr ) = 0 );\r\n sMessage = 'No attributes exist for the dimension: ' | pDim;\r\n pAlias = '';\r\n EndIf;\r\n\r\n IF(DIMIX( sDimAttr, pAlias ) = 0 );\r\n sMessage = 'The Alias: ' | pAlias | ' does not exist in the dimension: ' | pDim;\r\n pAlias = '';\r\n EndIf;\r\n\r\n IF(DTYPE( sDimAttr, pAlias ) @<> 'AA' );\r\n sMessage = 'The Alias: ' | pAlias | ' is not an Alias in the dimension: ' | sDimAttr;\r\n pAlias = '';\r\n EndIf;\r\nENDIF;\r\n\r\n## Validate pTemp\r\nIF( pTemp <> 0 & pTemp <> 1 );\r\n nErrors = 1;\r\n sMessage = 'Wrong parameter pTemp value (only 0 or 1 accepted).';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### Build Subset ###\r\n\r\nIf( nErrors = 0 );\r\n nLevel = 0;\r\n nLevelMax = DnLev( pDim|':'|sHier ) - 1;\r\n While( nLevel <= nLevelMax );\r\n # Loop through the levels of the dimension.\r\n sLevel = NumberToString( nLevel );\r\n sSubset = 'All Level ' | Fill( '0', 2 - Long( sLevel ) ) | sLevel;\r\n cSubs = cSubs | ' ' | sSubset | ',' ;\r\n If( HierarchySubsetExists( pDim, sHier, sSubset ) = 1 );\r\n # Need to destroy the subset because the subset may change from an MDX subset to a Static Subset.\r\n HierarchySubsetDestroy( pDim, sHier, sSubset );\r\n EndIf;\r\n\r\n # Generate MDX\r\n sMDX = '{ TM1FILTERBYLEVEL( { TM1SUBSETALL( [' | pDim|'].['|sHier | '] ) }, ' | sLevel | ' ) }';\r\n If( pSort = 1 );\r\n sMDX = '{ TM1SORT( ' | sMDX | ', ASC ) }';\r\n EndIf;\r\n\r\n ## Build Subset for the level.\r\n If( pConvertStatic = 1 );\r\n # Convert the subset to a static subset\r\n sSubsetMDX = '}' | cThisProcName | '.' | NumberToString( Int( Rand() * 100000 ) );\r\n If( HierarchySubsetExists( pDim, pHier, sSubsetMDX ) = 1 );\r\n HierarchySubsetDestroy( pDim, sHier, sSubsetMDX );\r\n EndIF;\r\n SubsetCreatebyMDX( sSubsetMDX, sMDX, pDim, pTemp );\r\n nSubsetSize = HierarchySubsetGetSize( pDim, sHier, sSubsetMDX );\r\n nSubsetIndex = 0;\r\n HierarchySubsetCreate( pDim, sHier, sSubset, pTemp );\r\n While( nSubsetIndex < nSubsetSize );\r\n nSubsetIndex = nSubsetIndex + 1;\r\n sTemp = HierarchySubsetElementGetIndex (pDim, sHier, sSubsetMDX, '', nSubsetIndex);\r\n sElement = HierarchySubsetGetElementName( pDim, sHier, sSubsetMDX, nSubsetIndex );\r\n HierarchySubsetElementInsert( pDim, sHier, sSubset, sElement, nSubsetIndex );\r\n End;\r\n Else;\r\n SubsetCreatebyMDX( sSubset, sMDX, pDim, pTemp );\r\n EndIf;\r\n\r\n ### Assign Alias to subset\r\n IF(pAlias @<> '' );\r\n If( nErrors = 0 );\r\n HierarchySubsetAliasSet( pDim, pHier, sSubset, pAlias );\r\n EndIf;\r\n ENDIF;\r\n nLevel = nLevel + 1;\r\n End;\r\nEndIf;\r\n\r\n\r\n\r\n\r\n### End Prolog ###", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.sub.create.bylevel', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pDim', '', 'pHier', '',\r\n \t'pSort', 0, 'pConvertStatic', 1,\r\n \t'pAlias', '', 'pTemp', 1\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process creates static subsets named \"All level \" for the specified consolidation\r\n# levels in a Hierarchy of a Dimension.\r\n\r\n# Note:\r\n# Option to sort subset is available only for sorting per element principal names.\r\n\r\n# Caution: Target hierarchy cannot be `Leaves`.\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pHier:%pHier%, pSort:%pSort%, pConvertStatic:%pConvertStatic%, pAlias:%pAlias%, pTemp:%pTemp%.'; \r\ncAttributeDim = '}ElementAttributes_' | pDim;\r\ncSubs = '' ;\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pAlias\": \"\",\r\n \"pDim\": null,\r\n \"pHier\": \"\",\r\n \"pConvertStatic\": 1,\r\n \"pLogOutput\": 0,\r\n \"pSort\": 0,\r\n \"pStrictErrorHandling\": 0,\r\n \"pTemp\": 1\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pAlias\": '|StringToJson ( pAlias )|',\r\n \"pDim\": '|StringToJson ( pDim )|',\r\n \"pHier\": '|StringToJson ( pHier )|',\r\n \"pConvertStatic\": '|NumberToString( pConvertStatic )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pSort\": '|NumberToString( pSort )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|',\r\n \"pTemp\": '|NumberToString( pTemp )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npAlias = JsonToString( JsonGet( pJson, 'pAlias' ) );\r\npDim = JsonToString( JsonGet( pJson, 'pDim' ) );\r\npHier = JsonToString( JsonGet( pJson, 'pHier' ) );\r\n# Numeric Parameters\r\npConvertStatic = StringToNumber( JsonToString( JsonGet( pJson, 'pConvertStatic' ) ) );\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npSort = StringToNumber( JsonToString( JsonGet( pJson, 'pSort' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\npTemp = StringToNumber( JsonToString( JsonGet( pJson, 'pTemp' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n## LogOutput parameters\r\nIF ( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n\r\n### Validate Parameters ###\r\n\r\nnErrors = 0;\r\n\r\nIf( Scan( ':', pDim ) > 0 & pHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pHier = SubSt( pDim, Scan( ':', pDim ) + 1, Long( pDim ) );\r\n pDim = SubSt( pDim, 1, Scan( ':', pDim ) - 1 );\r\nEndIf;\r\n\r\n# Validate dimension\r\nIf( Trim( pDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No dimension specified';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\nIf( DimensionExists( pDim ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid dimension: ' | pDim;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n## Validate Hierarchy\r\nIF(pHier @= 'Leaves' );\r\n nErrors = 1;\r\n sMessage = 'Invalid Hierarchy: ' | pDim |':'|pHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nIf( Trim( pHier ) @= '' );\r\n sHier = pDim;\r\nElse;\r\n sHier = pHier;\r\nEndIf;\r\n\r\nIF(HierarchyExists(pDim, sHier ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid dimension Hierarchy: ' | pDim |':'|sHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n## Validate Alias\r\nIF(pAlias @<> '' );\r\n\r\n sDimAttr = '}ElementAttributes_' | pDim;\r\n IF(\r\n DimensionExists( sDimAttr ) = 0 );\r\n sMessage = 'No attributes exist for the dimension: ' | pDim;\r\n pAlias = '';\r\n EndIf;\r\n\r\n IF(DIMIX( sDimAttr, pAlias ) = 0 );\r\n sMessage = 'The Alias: ' | pAlias | ' does not exist in the dimension: ' | pDim;\r\n pAlias = '';\r\n EndIf;\r\n\r\n IF(DTYPE( sDimAttr, pAlias ) @<> 'AA' );\r\n sMessage = 'The Alias: ' | pAlias | ' is not an Alias in the dimension: ' | sDimAttr;\r\n pAlias = '';\r\n EndIf;\r\nENDIF;\r\n\r\n## Validate pTemp\r\nIF( pTemp <> 0 & pTemp <> 1 );\r\n nErrors = 1;\r\n sMessage = 'Wrong parameter pTemp value (only 0 or 1 accepted).';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### Build Subset ###\r\n\r\nIf( nErrors = 0 );\r\n nLevel = 0;\r\n nLevelMax = DnLev( pDim|':'|sHier ) - 1;\r\n While( nLevel <= nLevelMax );\r\n # Loop through the levels of the dimension.\r\n sLevel = NumberToString( nLevel );\r\n sSubset = 'All Level ' | Fill( '0', 2 - Long( sLevel ) ) | sLevel;\r\n cSubs = cSubs | ' ' | sSubset | ',' ;\r\n If( HierarchySubsetExists( pDim, sHier, sSubset ) = 1 );\r\n # Need to destroy the subset because the subset may change from an MDX subset to a Static Subset.\r\n HierarchySubsetDestroy( pDim, sHier, sSubset );\r\n EndIf;\r\n\r\n # Generate MDX\r\n sMDX = '{ TM1FILTERBYLEVEL( { TM1SUBSETALL( [' | pDim|'].['|sHier | '] ) }, ' | sLevel | ' ) }';\r\n If( pSort = 1 );\r\n sMDX = '{ TM1SORT( ' | sMDX | ', ASC ) }';\r\n EndIf;\r\n\r\n ## Build Subset for the level.\r\n If( pConvertStatic = 1 );\r\n # Convert the subset to a static subset\r\n sSubsetMDX = '}' | cThisProcName | '.' | NumberToString( Int( Rand() * 100000 ) );\r\n If( HierarchySubsetExists( pDim, pHier, sSubsetMDX ) = 1 );\r\n HierarchySubsetDestroy( pDim, sHier, sSubsetMDX );\r\n EndIF;\r\n SubsetCreatebyMDX( sSubsetMDX, sMDX, pDim, pTemp );\r\n nSubsetSize = HierarchySubsetGetSize( pDim, sHier, sSubsetMDX );\r\n nSubsetIndex = 0;\r\n HierarchySubsetCreate( pDim, sHier, sSubset, pTemp );\r\n While( nSubsetIndex < nSubsetSize );\r\n nSubsetIndex = nSubsetIndex + 1;\r\n sTemp = HierarchySubsetElementGetIndex (pDim, sHier, sSubsetMDX, '', nSubsetIndex);\r\n sElement = HierarchySubsetGetElementName( pDim, sHier, sSubsetMDX, nSubsetIndex );\r\n HierarchySubsetElementInsert( pDim, sHier, sSubset, sElement, nSubsetIndex );\r\n End;\r\n Else;\r\n SubsetCreatebyMDX( sSubset, sMDX, pDim, pTemp );\r\n EndIf;\r\n\r\n ### Assign Alias to subset\r\n IF(pAlias @<> '' );\r\n If( nErrors = 0 );\r\n HierarchySubsetAliasSet( pDim, pHier, sSubset, pAlias );\r\n EndIf;\r\n ENDIF;\r\n nLevel = nLevel + 1;\r\n End;\r\nEndIf;\r\n\r\n\r\n\r\n\r\n### End Prolog ###", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully created subset(s) %cSubs% from dimension %pDim%.' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n### End Epilog ###", @@ -10,53 +10,59 @@ "Type": "None" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pDim", - "Prompt": "REQUIRED: Dimension name", + "Prompt": "REQUIRED: Delimited list of dimensions", "Value": "", "Type": "String" }, { "Name": "pHier", - "Prompt": "OPTIONAL: Hierarchy name (default if blank = same named hierarchy)", + "Prompt": "OPTIONAL: Hierarchy name (Default = pDim)", "Value": "", "Type": "String" }, { "Name": "pSort", - "Prompt": "OPTIONAL: Sort the Subset", + "Prompt": "OPTIONAL: Sort the subset (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { "Name": "pConvertStatic", - "Prompt": "OPTIONAL: Convert the Subset to Static", + "Prompt": "OPTIONAL: Convert the subset to static (Boolean. Default = 1)", "Value": 1, "Type": "Numeric" }, { "Name": "pAlias", - "Prompt": "OPTIONAL: Set Alias for Subset", + "Prompt": "OPTIONAL: Set alias for subset", "Value": "", "Type": "String" }, { "Name": "pTemp", - "Prompt": "OPTIONAL: Use temporary objects? (Boolean 1=True)", + "Prompt": "OPTIONAL: Delete/create temporary objects (0 = Do not delete, 1 = Delete, 2 = if view and subsets are created, keep only subsets)", "Value": 1, "Type": "Numeric" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [], diff --git a/bedrock_processes_json/}bedrock.hier.sub.create.bymdx.json b/bedrock_processes_json/}bedrock.hier.sub.create.bymdx.json index cc29718..838503b 100644 --- a/bedrock_processes_json/}bedrock.hier.sub.create.bymdx.json +++ b/bedrock_processes_json/}bedrock.hier.sub.create.bymdx.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.hier.sub.create.bymdx", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.sub.create.bymdx', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pDim', '', 'pHier', '', 'pSub', '',\r\n \t'pMDXExpr', '',\r\n \t'pConvertToStatic', 1, 'pTemp', 1\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will Create a dynamic subset from an MDX expression that evaluates to a non-empty set in the specified dimension.\r\n\r\n# Use case: Intended for Production & Development\r\n#1/ Create a dynamic subset for use in a view\r\n\r\n# Note:\r\n# Naturally, valid dimension name (pDim) are mandatory otherwise the process will abort.\r\n# If the MDX does not compile or produces an empty set, the process will error.\r\n# If convert to static (pConvertToStatic) is set to 1 then the MDX subset will be replaced by a static subset.\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName | '_' | cTimeStamp | '_' | cRandomInt;\r\ncTempFile = GetProcessErrorFileDirectory | cTempSub | '.csv';\r\ncUserName = TM1User();\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent= 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pHier:%pHier%, pSub:%pSub%, pMDXExpr:%pMDXExpr%, pConvertToStatic:%pConvertToStatic%, pTemp:%pTemp%, pAlias:%pAlias%.' ;\r\nsMDXExpr = pMDXExpr;\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\n\r\nnErrors = 0;\r\n\r\nIf( Scan( ':', pDim ) > 0 & pHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pHier = SubSt( pDim, Scan( ':', pDim ) + 1, Long( pDim ) );\r\n pDim = SubSt( pDim, 1, Scan( ':', pDim ) - 1 );\r\nEndIf;\r\n\r\n# Validate dimension\r\nIf( Trim( pDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No dimension specified';\r\n DataSourceType= 'NULL';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( Scan( ':', pDim ) > 0 & pHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pHier = SubSt( pDim, Scan( ':', pDim ) + 1, Long( pDim ) );\r\n pDim = SubSt( pDim, 1, Scan( ':', pDim ) - 1 );\r\nEndIf;\r\n\r\nIf( DimensionExists( pDim ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid dimension: ' | pDim;\r\n DataSourceType = 'NULL';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n## Validate hierarchy\r\nIf( Trim( pHier ) @= '' );\r\n sHier = pDim;\r\nElse;\r\n sHier = pHier;\r\nEndIf;\r\n\r\nIF(HierarchyExists(pDim, pHier ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid dimension Hierarchy: ' | pDim |':'|pHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate subset\r\nIf( Trim( pSub ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No subset specified';\r\n DataSourceType = 'NULL';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate MDX\r\nIf( Trim( sMDXExpr ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No MDX expression specified.';\r\n DataSourceType = 'NULL';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n## Validate pTemp\r\nIF( pTemp <> 0 & pTemp <> 1 );\r\n nErrors = 1;\r\n sMessage = 'Wrong parameter pTemp value (only 0 or 1 accepted).';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate Alias exists\r\nIf ( pAlias @<> '' & \r\n DimIx ( Expand ( '}ElementAttributes_%pDim%' ), pAlias ) = 0\r\n);\r\n nErrors = 1;\r\n sMessage = 'Alias does not exist in dimension %pDim%.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf; \r\n\r\n# Validate alias attribute name is actually an alias\r\nIf ( pAlias @<> '' & \r\n Dtype ( Expand ( '}ElementAttributes_%pDim%' ), pAlias ) @<> 'AA' \r\n);\r\n nErrors = 1;\r\n sMessage = 'Attribute %pAlias% is not an alias in dimension %pDim%.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n\r\n### Create Subset ###\r\nIf( nErrors = 0 );\r\n If( ElementCount( pDim, sHier ) = 0 & pConvertToStatic <> 0);\r\n HierarchySubsetCreate( pDim, sHier, pSub );\r\n Else;\r\n If( HierarchySubsetExists( pDim,sHier, pSub ) = 1 );\r\n HierarchySubsetMDXSet( pDim, sHier, pSub, sMDXExpr );\r\n Else;\r\n SubsetCreateByMDX( pSub, sMDXExpr, pDim|':'|sHier, pTemp );\r\n EndIf;\r\n If( pConvertToStatic = 1 );\r\n HierarchySubsetElementInsert( pDim, sHier, pSub, ElementName( pDim, sHier, 1 ), 1 );\r\n HierarchySubsetElementDelete( pDim, sHier, pSub, 1 );\r\n EndIf;\r\n EndIf;\r\n \r\n # Set Alias\r\n If ( pAlias @<> '' );\r\n If ( pDim @= sHier );\r\n SubsetAliasSet( pDim, pSub, pAlias);\r\n Else;\r\n SubsetAliasSet( pDim | ':' | sHier, pSub, pAlias);\r\n EndIf;\r\n EndIf;\r\nEndIf;\r\n\r\n\r\n### End Prolog ###", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.sub.create.bymdx', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pDim', '', 'pHier', '', 'pSub', '',\r\n \t'pMDXExpr', '',\r\n \t'pConvertToStatic', 1, 'pTemp', 1\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will Create a dynamic subset from an MDX expression that evaluates to a non-empty set in the specified dimension.\r\n\r\n# Use case: Intended for Production & Development\r\n#1/ Create a dynamic subset for use in a view\r\n\r\n# Note:\r\n# Naturally, valid dimension name (pDim) are mandatory otherwise the process will abort.\r\n# If the MDX does not compile or produces an empty set, the process will error.\r\n# If convert to static (pConvertToStatic) is set to 1 then the MDX subset will be replaced by a static subset.\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName | '_' | cTimeStamp | '_' | cRandomInt;\r\ncTempFile = GetProcessErrorFileDirectory | cTempSub | '.csv';\r\ncUserName = TM1User();\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent= 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pHier:%pHier%, pSub:%pSub%, pMDXExpr:%pMDXExpr%, pConvertToStatic:%pConvertToStatic%, pTemp:%pTemp%, pAlias:%pAlias%.' ;\r\nsMDXExpr = pMDXExpr;\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pAlias\": \"\",\r\n \"pDim\": null,\r\n \"pHier\": \"\",\r\n \"pMDXExpr\": null,\r\n \"pSub\": null,\r\n \"pConvertToStatic\": 1,\r\n \"pLogOutput\": 0,\r\n \"pStrictErrorHandling\": 0,\r\n \"pTemp\": 1\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pAlias\": '|StringToJson ( pAlias )|',\r\n \"pDim\": '|StringToJson ( pDim )|',\r\n \"pHier\": '|StringToJson ( pHier )|',\r\n \"pMDXExpr\": '|StringToJson ( pMDXExpr )|',\r\n \"pSub\": '|StringToJson ( pSub )|',\r\n \"pConvertToStatic\": '|NumberToString( pConvertToStatic )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|',\r\n \"pTemp\": '|NumberToString( pTemp )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npAlias = JsonToString( JsonGet( pJson, 'pAlias' ) );\r\npDim = JsonToString( JsonGet( pJson, 'pDim' ) );\r\npHier = JsonToString( JsonGet( pJson, 'pHier' ) );\r\npMDXExpr = JsonToString( JsonGet( pJson, 'pMDXExpr' ) );\r\npSub = JsonToString( JsonGet( pJson, 'pSub' ) );\r\n# Numeric Parameters\r\npConvertToStatic = StringToNumber( JsonToString( JsonGet( pJson, 'pConvertToStatic' ) ) );\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\npTemp = StringToNumber( JsonToString( JsonGet( pJson, 'pTemp' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\n\r\nnErrors = 0;\r\n\r\nIf( Scan( ':', pDim ) > 0 & pHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pHier = SubSt( pDim, Scan( ':', pDim ) + 1, Long( pDim ) );\r\n pDim = SubSt( pDim, 1, Scan( ':', pDim ) - 1 );\r\nEndIf;\r\n\r\n# Validate dimension\r\nIf( Trim( pDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No dimension specified';\r\n DataSourceType= 'NULL';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( Scan( ':', pDim ) > 0 & pHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pHier = SubSt( pDim, Scan( ':', pDim ) + 1, Long( pDim ) );\r\n pDim = SubSt( pDim, 1, Scan( ':', pDim ) - 1 );\r\nEndIf;\r\n\r\nIf( DimensionExists( pDim ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid dimension: ' | pDim;\r\n DataSourceType = 'NULL';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n## Validate hierarchy\r\nIf( Trim( pHier ) @= '' );\r\n sHier = pDim;\r\nElse;\r\n sHier = pHier;\r\nEndIf;\r\n\r\nIF(HierarchyExists(pDim, pHier ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid dimension Hierarchy: ' | pDim |':'|pHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate subset\r\nIf( Trim( pSub ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No subset specified';\r\n DataSourceType = 'NULL';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate MDX\r\nIf( Trim( sMDXExpr ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No MDX expression specified.';\r\n DataSourceType = 'NULL';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n## Validate pTemp\r\nIF( pTemp <> 0 & pTemp <> 1 );\r\n nErrors = 1;\r\n sMessage = 'Wrong parameter pTemp value (only 0 or 1 accepted).';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate Alias exists\r\nIf ( pAlias @<> '' & \r\n DimIx ( Expand ( '}ElementAttributes_%pDim%' ), pAlias ) = 0\r\n);\r\n nErrors = 1;\r\n sMessage = 'Alias does not exist in dimension %pDim%.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf; \r\n\r\n# Validate alias attribute name is actually an alias\r\nIf ( pAlias @<> '' & \r\n Dtype ( Expand ( '}ElementAttributes_%pDim%' ), pAlias ) @<> 'AA' \r\n);\r\n nErrors = 1;\r\n sMessage = 'Attribute %pAlias% is not an alias in dimension %pDim%.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n\r\n### Create Subset ###\r\nIf( nErrors = 0 );\r\n If( ElementCount( pDim, sHier ) = 0 & pConvertToStatic <> 0);\r\n HierarchySubsetCreate( pDim, sHier, pSub );\r\n Else;\r\n If( HierarchySubsetExists( pDim,sHier, pSub ) = 1 );\r\n HierarchySubsetMDXSet( pDim, sHier, pSub, sMDXExpr );\r\n Else;\r\n SubsetCreateByMDX( pSub, sMDXExpr, pDim|':'|sHier, pTemp );\r\n EndIf;\r\n If( pConvertToStatic = 1 );\r\n HierarchySubsetElementInsert( pDim, sHier, pSub, ElementName( pDim, sHier, 1 ), 1 );\r\n HierarchySubsetElementDelete( pDim, sHier, pSub, 1 );\r\n EndIf;\r\n EndIf;\r\n \r\n # Set Alias\r\n If ( pAlias @<> '' );\r\n If ( pDim @= sHier );\r\n SubsetAliasSet( pDim, pSub, pAlias);\r\n Else;\r\n SubsetAliasSet( pDim | ':' | sHier, pSub, pAlias);\r\n EndIf;\r\n EndIf;\r\nEndIf;\r\n\r\n\r\n### End Prolog ###", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n### Destroy Temporary Subset ###\r\n\r\nIf( pConvertToStatic = 1 & pTemp = 0 );\r\n\r\n If( HierarchySubsetExists( pDim , pHier, cTempSub) = 1 );\r\n HierarchySubsetDestroy( pDim, pHier, cTempSub );\r\n EndIf;\r\n\r\nEndIf;\r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully created subset %pSub% from dimension %pDim%.' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n### End Epilog ###", @@ -10,59 +10,65 @@ "Type": "None" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "Optional: write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pDim", - "Prompt": "Required: Dimension name", + "Prompt": "REQUIRED: Delimited list of dimensions", "Value": "", "Type": "String" }, { "Name": "pHier", - "Prompt": "Optional: Hierarchy name (default if blank = same named hierarchy)", + "Prompt": "OPTIONAL: Hierarchy name (Default = pDim)", "Value": "", "Type": "String" }, { "Name": "pSub", - "Prompt": "Required: Subset name", + "Prompt": "REQUIRED: Subset name", "Value": "", "Type": "String" }, { "Name": "pMDXExpr", - "Prompt": "Required: Valid MDX Expression for Specified Dimension", + "Prompt": "REQUIRED: Valid MDX Expression", "Value": "", "Type": "String" }, { "Name": "pConvertToStatic", - "Prompt": "Optional: Bolean: 1 = True (convert to static subset)", + "Prompt": "OPTIONAL: Convert the subset to static (Boolean. Default = 1)", "Value": 1, "Type": "Numeric" }, { "Name": "pTemp", - "Prompt": "Optional: Use temporary objects? (Boolean 1=True)", + "Prompt": "OPTIONAL: Delete/create temporary objects (0 = Do not delete, 1 = Delete, 2 = if view and subsets are created, keep only subsets)", "Value": 1, "Type": "Numeric" }, { "Name": "pAlias", - "Prompt": "Optional: Set Alias for Subset", + "Prompt": "OPTIONAL: Set alias for subset", "Value": "", "Type": "String" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [], diff --git a/bedrock_processes_json/}bedrock.hier.sub.create.consolidation.all.json b/bedrock_processes_json/}bedrock.hier.sub.create.consolidation.all.json index 8dfcd76..d57374c 100644 --- a/bedrock_processes_json/}bedrock.hier.sub.create.consolidation.all.json +++ b/bedrock_processes_json/}bedrock.hier.sub.create.consolidation.all.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.hier.sub.create.consolidation.all", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.sub.create.consolidation.all', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pDim', '', 'pHier', '', 'pSub', '', 'pConsol', '',\r\n \t'pAddToSubset', 0, 'pExclusions', '',\r\n \t'pDelim', '&', 'pAlias', '', 'pTemp', 1\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will create a static subset in a Hierarchy of target Dimension that consists of\r\n# all descendants of a specified consolidated element, including consolidated elements.\r\n\r\n# Note:\r\n# - pExclusions: If pExclusions is specified then the elements (separated by a delimiter) will be\r\n# excluded from the subset. Wildcards characters `*` and `?` are accepted.\r\n# - pAddToSubset : If the specified subset already exists then this parameter will control whether\r\n# elements will be added to the existing subset (value 1) or a new subset will be created\r\n# (value 0).\r\n\r\n# Caution: Number of consolidated levels that are processed is limited to maximum of 99.\r\n#EndRegion @DOC\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\n\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorShell = Expand('Executing process %cThisProcName% has failed.');\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pHier:%pHier%, pSub:%pSub%, pConsol:%pConsol%, pAddToSubset:%pAddToSubset%, pExclusions:%pExclusions%, pDelim:%pDelim%, pAlias:%pAlias%, pTemp:%pTemp%.' ;\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\nnErrors = 0;\r\n\r\n## Validate pTemp\r\nIF( pTemp <> 0 & pTemp <> 1 );\r\n nErrors = 1;\r\n sMessage = 'Wrong parameter pTemp value (only 0 or 1 accepted).';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nnRet = \r\nExecuteProcess( '}bedrock.hier.sub.create', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pDim', pDim, 'pHier', pHier, 'pSub', pSub, 'pConsol', pConsol,\r\n 'pAttr', '', 'pAttrValue', '',\r\n 'pLevelFrom', 0, 'pLevelTo', 999,\r\n 'pExclusions', pExclusions, 'pDelim', pDelim,\r\n 'pAddToSubset', pAddToSubset,\r\n 'pAlias', pAlias, 'pTemp', pTemp\r\n);\r\n \r\nIF ( nRet <> ProcessExitNormal() );\r\n sMessage = cMsgErrorShell;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n ProcessError();\r\nENDIF;\r\n\r\n", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.sub.create.consolidation.all', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pDim', '', 'pHier', '', 'pSub', '', 'pConsol', '',\r\n \t'pAddToSubset', 0, 'pExclusions', '',\r\n \t'pDelim', '&', 'pAlias', '', 'pTemp', 1\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will create a static subset in a Hierarchy of target Dimension that consists of\r\n# all descendants of a specified consolidated element, including consolidated elements.\r\n\r\n# Note:\r\n# - pExclusions: If pExclusions is specified then the elements (separated by a delimiter) will be\r\n# excluded from the subset. Wildcards characters `*` and `?` are accepted.\r\n# - pAddToSubset : If the specified subset already exists then this parameter will control whether\r\n# elements will be added to the existing subset (value 1) or a new subset will be created\r\n# (value 0).\r\n\r\n# Caution: Number of consolidated levels that are processed is limited to maximum of 99.\r\n#EndRegion @DOC\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\n\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorShell = Expand('Executing process %cThisProcName% has failed.');\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pHier:%pHier%, pSub:%pSub%, pConsol:%pConsol%, pAddToSubset:%pAddToSubset%, pExclusions:%pExclusions%, pDelim:%pDelim%, pAlias:%pAlias%, pTemp:%pTemp%.' ;\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pAlias\": \"\",\r\n \"pConsol\": \"*\",\r\n \"pDelim\": \"&\",\r\n \"pDim\": null,\r\n \"pExclusions\": \"\",\r\n \"pHier\": \"\",\r\n \"pSub\": null,\r\n \"pAddToSubset\": 0,\r\n \"pLogOutput\": 0,\r\n \"pStrictErrorHandling\": 0,\r\n \"pTemp\": 1\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pAlias\": '|StringToJson ( pAlias )|',\r\n \"pConsol\": '|StringToJson ( pConsol )|',\r\n \"pDelim\": '|StringToJson ( pDelim )|',\r\n \"pDim\": '|StringToJson ( pDim )|',\r\n \"pExclusions\": '|StringToJson ( pExclusions )|',\r\n \"pHier\": '|StringToJson ( pHier )|',\r\n \"pSub\": '|StringToJson ( pSub )|',\r\n \"pAddToSubset\": '|NumberToString( pAddToSubset )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|',\r\n \"pTemp\": '|NumberToString( pTemp )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npAlias = JsonToString( JsonGet( pJson, 'pAlias' ) );\r\npConsol = JsonToString( JsonGet( pJson, 'pConsol' ) );\r\npDelim = JsonToString( JsonGet( pJson, 'pDelim' ) );\r\npDim = JsonToString( JsonGet( pJson, 'pDim' ) );\r\npExclusions = JsonToString( JsonGet( pJson, 'pExclusions' ) );\r\npHier = JsonToString( JsonGet( pJson, 'pHier' ) );\r\npSub = JsonToString( JsonGet( pJson, 'pSub' ) );\r\n# Numeric Parameters\r\npAddToSubset = StringToNumber( JsonToString( JsonGet( pJson, 'pAddToSubset' ) ) );\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\npTemp = StringToNumber( JsonToString( JsonGet( pJson, 'pTemp' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\nnErrors = 0;\r\n\r\n## Validate pTemp\r\nIF( pTemp <> 0 & pTemp <> 1 );\r\n nErrors = 1;\r\n sMessage = 'Wrong parameter pTemp value (only 0 or 1 accepted).';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nnRet = \r\nExecuteProcess( '}bedrock.hier.sub.create', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pDim', pDim, 'pHier', pHier, 'pSub', pSub, 'pConsol', pConsol,\r\n 'pAttr', '', 'pAttrValue', '',\r\n 'pLevelFrom', 0, 'pLevelTo', 999,\r\n 'pExclusions', pExclusions, 'pDelim', pDelim,\r\n 'pAddToSubset', pAddToSubset,\r\n 'pAlias', pAlias, 'pTemp', pTemp\r\n);\r\n \r\nIF ( nRet <> ProcessExitNormal() );\r\n sMessage = cMsgErrorShell;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n ProcessError();\r\nENDIF;\r\n\r\n", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully created subset %pSub% from dimension %pDim%.' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n### End Epilog ###", @@ -10,27 +10,15 @@ "Type": "None" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pDim", - "Prompt": "REQUIRED: Dimension name", + "Prompt": "REQUIRED: Delimited list of dimensions", "Value": "", "Type": "String" }, { "Name": "pHier", - "Prompt": "OPTIONAL: Hierarchy name (default if blank = same named hierarchy)", + "Prompt": "OPTIONAL: Hierarchy name (Default = pDim)", "Value": "", "Type": "String" }, @@ -42,39 +30,57 @@ }, { "Name": "pConsol", - "Prompt": "OPTIONAL: Consolidated Element (Blank Equals All)", - "Value": "", + "Prompt": "OPTIONAL: Consolidated element name used as source (Default = '*')", + "Value": "*", "Type": "String" }, { "Name": "pAddToSubset", - "Prompt": "OPTIONAL: Add to Subset if it Already Exists (0=No 1=Yes)", + "Prompt": "OPTIONAL: Add to subset if it already exists (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { "Name": "pExclusions", - "Prompt": "OPTIONAL: Elements to Exclude From Subset (Separated by Delimiter, Accepts Wild card)", + "Prompt": "OPTIONAL: Delimited list of elements to exclude", "Value": "", "Type": "String" }, { "Name": "pDelim", - "Prompt": "OPTIONAL: Delimiter character", + "Prompt": "OPTIONAL: Delimiter for list parameters (Default = '&')", "Value": "&", "Type": "String" }, { "Name": "pAlias", - "Prompt": "OPTIONAL: Set Alias for Subset", + "Prompt": "OPTIONAL: Set alias for subset", "Value": "", "Type": "String" }, { "Name": "pTemp", - "Prompt": "OPTIONAL: Use temporary objects? (Boolean 1=True)", + "Prompt": "OPTIONAL: Delete/create temporary objects (0 = Do not delete, 1 = Delete, 2 = if view and subsets are created, keep only subsets)", "Value": 1, "Type": "Numeric" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [], diff --git a/bedrock_processes_json/}bedrock.hier.sub.create.consolidation.leaf.json b/bedrock_processes_json/}bedrock.hier.sub.create.consolidation.leaf.json index 5e00d2f..dc6cde5 100644 --- a/bedrock_processes_json/}bedrock.hier.sub.create.consolidation.leaf.json +++ b/bedrock_processes_json/}bedrock.hier.sub.create.consolidation.leaf.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.hier.sub.create.consolidation.leaf", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.sub.create.consolidation.leaf', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pDim', '', 'pHier', '', 'pSub', '', 'pConsol', '',\r\n \t'pAddToSubset', 0, 'pExclusions', '',\r\n \t'pDelim', '&', 'pAlias', '', 'pTemp', 1\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will create a static subset in a Hierarchy of target Dimension that consists of\r\n# all leaf descendants of a specified consolidated element.\r\n\r\n# Note:\r\n# - pExclusions: If pExclusions is specified then the elements (separated by a delimiter) will be\r\n# excluded from the subset. Wildcards characters `*` and `?` are accepted.\r\n# - pAddToSubset : If the specified subset already exists then this parameter will control whether\r\n# elements will be added to the existing subset (value 1) or a new subset will be created\r\n# (value 0).\r\n\r\n#EndRegion @DOC\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\n\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorShell = Expand('Executing process %cThisProcName% has failed.');\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pHier:%pHier%, pSub:%pSub%, pConsol:%pConsol%, pAddToSubset:%pAddToSubset%, pExclusions:%pExclusions%, pDelim:%pDelim%, pAlias:%pAlias%, pTemp:%pTemp%.' ;\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\nnErrors = 0;\r\n\r\n## Validate pTemp\r\nIF( pTemp <> 0 & pTemp <> 1 );\r\n nErrors = 1;\r\n sMessage = 'Wrong parameter pTemp value (only 0 or 1 accepted).';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nnRet = \r\nExecuteProcess( '}bedrock.hier.sub.create', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pDim', pDim, 'pHier', pHier, 'pSub', pSub, 'pConsol', pConsol,\r\n 'pAttr', '', 'pAttrValue', '',\r\n 'pLevelFrom', 0, 'pLevelTo', 0,\r\n 'pExclusions', pExclusions,\r\n 'pDelim', pDelim, 'pAddToSubset', pAddToSubset,\r\n 'pAlias', pAlias, 'pTemp', pTemp\r\n);\r\n\r\n \r\nIF ( nRet <> ProcessExitNormal() );\r\n sMessage = cMsgErrorShell;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n ProcessError();\r\nENDIF;\r\n\r\n### End Prolog ###", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.sub.create.consolidation.leaf', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pDim', '', 'pHier', '', 'pSub', '', 'pConsol', '',\r\n \t'pAddToSubset', 0, 'pExclusions', '',\r\n \t'pDelim', '&', 'pAlias', '', 'pTemp', 1\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will create a static subset in a Hierarchy of target Dimension that consists of\r\n# all leaf descendants of a specified consolidated element.\r\n\r\n# Note:\r\n# - pExclusions: If pExclusions is specified then the elements (separated by a delimiter) will be\r\n# excluded from the subset. Wildcards characters `*` and `?` are accepted.\r\n# - pAddToSubset : If the specified subset already exists then this parameter will control whether\r\n# elements will be added to the existing subset (value 1) or a new subset will be created\r\n# (value 0).\r\n\r\n#EndRegion @DOC\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\n\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorShell = Expand('Executing process %cThisProcName% has failed.');\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pHier:%pHier%, pSub:%pSub%, pConsol:%pConsol%, pAddToSubset:%pAddToSubset%, pExclusions:%pExclusions%, pDelim:%pDelim%, pAlias:%pAlias%, pTemp:%pTemp%.' ;\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pAlias\": \"\",\r\n \"pConsol\": \"*\",\r\n \"pDelim\": \"&\",\r\n \"pDim\": null,\r\n \"pExclusions\": \"\",\r\n \"pHier\": \"\",\r\n \"pSub\": null,\r\n \"pAddToSubset\": 0,\r\n \"pLogOutput\": 0,\r\n \"pStrictErrorHandling\": 0,\r\n \"pTemp\": 1\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pAlias\": '|StringToJson ( pAlias )|',\r\n \"pConsol\": '|StringToJson ( pConsol )|',\r\n \"pDelim\": '|StringToJson ( pDelim )|',\r\n \"pDim\": '|StringToJson ( pDim )|',\r\n \"pExclusions\": '|StringToJson ( pExclusions )|',\r\n \"pHier\": '|StringToJson ( pHier )|',\r\n \"pSub\": '|StringToJson ( pSub )|',\r\n \"pAddToSubset\": '|NumberToString( pAddToSubset )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|',\r\n \"pTemp\": '|NumberToString( pTemp )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npAlias = JsonToString( JsonGet( pJson, 'pAlias' ) );\r\npConsol = JsonToString( JsonGet( pJson, 'pConsol' ) );\r\npDelim = JsonToString( JsonGet( pJson, 'pDelim' ) );\r\npDim = JsonToString( JsonGet( pJson, 'pDim' ) );\r\npExclusions = JsonToString( JsonGet( pJson, 'pExclusions' ) );\r\npHier = JsonToString( JsonGet( pJson, 'pHier' ) );\r\npSub = JsonToString( JsonGet( pJson, 'pSub' ) );\r\n# Numeric Parameters\r\npAddToSubset = StringToNumber( JsonToString( JsonGet( pJson, 'pAddToSubset' ) ) );\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\npTemp = StringToNumber( JsonToString( JsonGet( pJson, 'pTemp' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\nnErrors = 0;\r\n\r\n## Validate pTemp\r\nIF( pTemp <> 0 & pTemp <> 1 );\r\n nErrors = 1;\r\n sMessage = 'Wrong parameter pTemp value (only 0 or 1 accepted).';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nnRet = \r\nExecuteProcess( '}bedrock.hier.sub.create', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pDim', pDim, 'pHier', pHier, 'pSub', pSub, 'pConsol', pConsol,\r\n 'pAttr', '', 'pAttrValue', '',\r\n 'pLevelFrom', 0, 'pLevelTo', 0,\r\n 'pExclusions', pExclusions,\r\n 'pDelim', pDelim, 'pAddToSubset', pAddToSubset,\r\n 'pAlias', pAlias, 'pTemp', pTemp\r\n);\r\n\r\n \r\nIF ( nRet <> ProcessExitNormal() );\r\n sMessage = cMsgErrorShell;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n ProcessError();\r\nENDIF;\r\n\r\n### End Prolog ###", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully created subset %pSub% from dimension %pDim%.' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n### End Epilog ###", @@ -10,71 +10,77 @@ "Type": "None" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pDim", - "Prompt": "REQUIRED: Dimension name", + "Prompt": "REQUIRED: Delimited list of dimensions", "Value": "", "Type": "String" }, { "Name": "pHier", - "Prompt": "OPTIONAL: Hierarchy name (default if blank = same named hierarchy)", + "Prompt": "OPTIONAL: Hierarchy name (Default = pDim)", "Value": "", "Type": "String" }, { "Name": "pSub", - "Prompt": "REQUIRED: Subset Name", + "Prompt": "REQUIRED: Subset name", "Value": "", "Type": "String" }, { "Name": "pConsol", - "Prompt": "OPTIONAL: Consolidated Element (Blank Equals All)", - "Value": "", + "Prompt": "OPTIONAL: Consolidated element name used as source (Default = '*')", + "Value": "*", "Type": "String" }, { "Name": "pAddToSubset", - "Prompt": "OPTIONAL: Add to Subset if it Already Exists (0=No 1=Yes)", + "Prompt": "OPTIONAL: Add to subset if it already exists (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { "Name": "pExclusions", - "Prompt": "OPTIONAL: Elements to Exclude From Subset (Separated by Delimiter, Accepts Wild card)", + "Prompt": "OPTIONAL: Delimited list of elements to exclude", "Value": "", "Type": "String" }, { "Name": "pDelim", - "Prompt": "OPTIONAL: Delimiter character", + "Prompt": "OPTIONAL: Delimiter for list parameters (Default = '&')", "Value": "&", "Type": "String" }, { "Name": "pAlias", - "Prompt": "OPTIONAL: Set Alias for Subset", + "Prompt": "OPTIONAL: Set alias for subset", "Value": "", "Type": "String" }, { "Name": "pTemp", - "Prompt": "OPTIONAL: Use temporary objects? (Boolean 1=True)", + "Prompt": "OPTIONAL: Delete/create temporary objects (0 = Do not delete, 1 = Delete, 2 = if view and subsets are created, keep only subsets)", "Value": 1, "Type": "Numeric" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [], diff --git a/bedrock_processes_json/}bedrock.hier.sub.create.json b/bedrock_processes_json/}bedrock.hier.sub.create.json index d9772b8..f118440 100644 --- a/bedrock_processes_json/}bedrock.hier.sub.create.json +++ b/bedrock_processes_json/}bedrock.hier.sub.create.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.hier.sub.create", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.sub.create', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pDim', '', 'pHier', '', 'pSub', '',\r\n \t'pConsol', '*', 'pAttr', '', 'pAttrValue', '',\r\n \t'pLevelFrom', 0, 'pLevelTo', 999,\r\n \t'pExclusions', '', 'pDelim', '&',\r\n \t'pAddToSubset', 0, 'pAlias', '',\r\n \t'pTemp', 1\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n\r\n### Start Prolog ###\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will create a static subset in a Hierarchy of target Dimension.\r\n\r\n# Note:\r\n# This process uses a number of parameters to determine what to include in the subset:\r\n# - pConsol: If specified, only elements that are descendants of the consol will be included in\r\n# the subset. If blank, then this filter will be ignored.\r\n# - pAttr: If specified, only elements that have a value equivalent to pAttrValue will be included\r\n# in the subset. If blank, this filter will be ignored.\r\n# - pLevelFrom: Only elements with a level greater than or equal to pLevelFrom will be included in\r\n# the subset.\r\n# - pLevelTo: Only elements with a level less than or equal to pLevelFrom will be included in the\r\n# subset.\r\n# - pExclusions: If pExclusions is specified then the elements (separated by a delimiter) will be\r\n# excluded from the subset. Wildcards characters `*` and `?` are accepted.\r\n# - pAddToSubset : If the specified subset already exists then this parameter will control whether\r\n# elements will be added to the existing subset (value 1) or a new subset will be created\r\n# (value 0).\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pHier:%pHier%, pSub:%pSub%, pConsol:%pConsol%, pAttr:%pAttr%, pAttrValue:%pAttrValue%, pLevelFrom:%pLevelFrom%, pLevelTo:%pLevelTo%, pExclusions:%pExclusions%, pDelim:%pDelim%, pAddToSubset:%pAddToSubset%, pAlias:%pAlias%, pTemp:%pTemp%.'; \r\ncAttributeDim = '}ElementAttributes_' | pDim;\r\n\r\n## LogOutput parameters\r\nIF ( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\nIf( Scan( ':', pDim ) > 0 & pHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pHier = SubSt( pDim, Scan( ':', pDim ) + 1, Long( pDim ) );\r\n pDim = SubSt( pDim, 1, Scan( ':', pDim ) - 1 );\r\nEndIf;\r\n\r\n## Validate dimension\r\nIF( Trim( pDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIF( DimensionExists( pDim ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid dimension: ' | pDim;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n## Validate Hierarchy\r\nIf( Trim( pHier ) @= '' );\r\n sHier = pDim;\r\nElse;\r\n sHier = pHier;\r\nEndIf;\r\nIF( sHier @= 'Leaves' );\r\n nErrors = 1;\r\n sMessage = 'Invalid Hierarchy: ' | pDim |':'|pHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIF(HierarchyExists(pDim, sHier ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid dimension Hierarchy: ' | pDim |':'|sHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n## Validate subset\r\nIF(Trim( pSub ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No subset specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n## Validate consolidation\r\npConsol = Trim( pConsol );\r\nIf( pConsol @<> '' & pConsol @<> '*' );\r\n If( ElementIndex(pDim, sHier, pConsol) = 0 );\r\n nErrors = 1;\r\n sMessage = 'The ' | pConsol | ' consolidation does not exist in the '| pDim |' dimension:Hierarchy ' | pDim |':'| sHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n Else;\r\n pConsol = HierarchyElementPrincipalName(pDim, sHier, pConsol);\r\n EndIf;\r\nEndIf;\r\n\r\n## Validate attribute\r\npAttr = Trim( pAttr );\r\nIF(pAttr @<> '' );\r\n\r\n If( DimensionExists( cAttributeDim ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Dimension: ' | pDim | ' does not have any attributes.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n EndIf;\r\n \r\n IF(DIMIX( cAttributeDim, pAttr ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'The ' | pAttr |' attribute does not exist in the ' | pDim | ' dimension.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n EndIf;\r\n \r\n sAttributeType = DType( cAttributeDim, pAttr );\r\n If(sAttributeType @= 'AN' % sAttributeType @= 'N' );\r\n If(pAttrValue @= '' );\r\n nAttributeValue = 0;\r\n Else;\r\n nAttributeValue = StringToNumber( pAttrValue );\r\n EndIf;\r\n EndIf;\r\n \r\nEndIf;\r\n\r\n## Validate element level parameters\r\nIf(pLevelFrom < 0 % pLevelTo < 0 % pLevelTo < pLevelFrom );\r\n nErrors = 1;\r\n sMessage = 'Element levels must be greater than or equal to zero and level to must be greater than or equal to level from';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate delimiter\r\nIF( pExclusions @<> '' & pDelim @= '' );\r\n ## Set to default parameter.\r\n pDelimiter = '&';\r\nEndIf;\r\n\r\n## Validate add to subset\r\nIF( pAddToSubset <> 0 & pAddToSubset <> 1 );\r\n nErrors = 1;\r\n sMessage = 'Invalid value for pAddToSubset: ' | NumberToString( pAddToSubset ) | '. Valid values are 0 and 1';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n## Validate Alias\r\nsDimAttr = '}ElementAttributes_' | pDim;\r\nIF( pAlias @<> '' );\r\n \r\n IF(DimensionExists( sDimAttr ) = 0 );\r\n sMessage = 'No attributes exist for the dimension: ' | pDim;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n pAlias = '';\r\n ElseIf(DIMIX( sDimAttr, pAlias ) = 0 );\r\n sMessage = 'The alias: ' | pAlias | ' does not exist as an attribute in the dimension: ' | pDim;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n pAlias = '';\r\n ElseIf(DTYPE( sDimAttr, pAlias ) @<> 'AA' );\r\n sMessage = 'The alias: ' | pAlias | ' is not an Alias type of attribute in the dimension: ' | sDimAttr;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n pAlias = '';\r\n EndIf;\r\n\r\nENDIF;\r\n\r\n## Validate pTemp\r\nIF( pTemp <> 0 & pTemp <> 1 );\r\n nErrors = 1;\r\n sMessage = 'Wrong parameter pTemp value (only 0 or 1 accepted).';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### Check for errors before preparing subset\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### Prepare subset ###\r\nIF( HierarchySubsetExists( pDim,sHier, pSub ) = 1 );\r\n If( pAddtoSubset <> 1 );\r\n HierarchySubsetDeleteAllElements( pDim, sHier, pSub );\r\n nSubsetSize = 0;\r\n Else;\r\n nSubsetSize = HierarchySubsetGetSize(pDim, sHier, pSub );\r\n EndIf;\r\nElse;\r\n HierarchySubsetCreate( pDim, sHier, pSub, pTemp );\r\n nSubsetSize = 0;\r\nEndIf;\r\n\r\n### Set Alias ###\r\nIF(pAlias @<> '' );\r\n HierarchySubsetAliasSet( pDim, pHier, pSub, pAlias);\r\nENDIF;\r\n\r\n### Assign Datasource ###\r\n\r\nDatasourceNameForServer = pDim|':'|sHier;\r\nDataSourceDimensionSubset = 'All';\r\n\r\n\r\n### End Prolog ###", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.sub.create', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pDim', '', 'pHier', '', 'pSub', '',\r\n \t'pConsol', '*', 'pAttr', '', 'pAttrValue', '',\r\n \t'pLevelFrom', 0, 'pLevelTo', 999,\r\n \t'pExclusions', '', 'pDelim', '&',\r\n \t'pAddToSubset', 0, 'pAlias', '',\r\n \t'pTemp', 1\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n\r\n### Start Prolog ###\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will create a static subset in a Hierarchy of target Dimension.\r\n\r\n# Note:\r\n# This process uses a number of parameters to determine what to include in the subset:\r\n# - pConsol: If specified, only elements that are descendants of the consol will be included in\r\n# the subset. If blank, then this filter will be ignored.\r\n# - pAttr: If specified, only elements that have a value equivalent to pAttrValue will be included\r\n# in the subset. If blank, this filter will be ignored.\r\n# - pLevelFrom: Only elements with a level greater than or equal to pLevelFrom will be included in\r\n# the subset.\r\n# - pLevelTo: Only elements with a level less than or equal to pLevelFrom will be included in the\r\n# subset.\r\n# - pExclusions: If pExclusions is specified then the elements (separated by a delimiter) will be\r\n# excluded from the subset. Wildcards characters `*` and `?` are accepted.\r\n# - pAddToSubset : If the specified subset already exists then this parameter will control whether\r\n# elements will be added to the existing subset (value 1) or a new subset will be created\r\n# (value 0).\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pHier:%pHier%, pSub:%pSub%, pConsol:%pConsol%, pAttr:%pAttr%, pAttrValue:%pAttrValue%, pLevelFrom:%pLevelFrom%, pLevelTo:%pLevelTo%, pExclusions:%pExclusions%, pDelim:%pDelim%, pAddToSubset:%pAddToSubset%, pAlias:%pAlias%, pTemp:%pTemp%.'; \r\ncAttributeDim = '}ElementAttributes_' | pDim;\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pAlias\": \"\",\r\n \"pAttr\": \"\",\r\n \"pAttrValue\": \"\",\r\n \"pConsol\": \"*\",\r\n \"pDelim\": \"&\",\r\n \"pDim\": null,\r\n \"pExclusions\": \"\",\r\n \"pHier\": \"\",\r\n \"pSub\": null,\r\n \"pAddToSubset\": 0,\r\n \"pLevelFrom\": 0,\r\n \"pLevelTo\": 999,\r\n \"pLogOutput\": 0,\r\n \"pStrictErrorHandling\": 0,\r\n \"pTemp\": 1\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pAlias\": '|StringToJson ( pAlias )|',\r\n \"pAttr\": '|StringToJson ( pAttr )|',\r\n \"pAttrValue\": '|StringToJson ( pAttrValue )|',\r\n \"pConsol\": '|StringToJson ( pConsol )|',\r\n \"pDelim\": '|StringToJson ( pDelim )|',\r\n \"pDim\": '|StringToJson ( pDim )|',\r\n \"pExclusions\": '|StringToJson ( pExclusions )|',\r\n \"pHier\": '|StringToJson ( pHier )|',\r\n \"pSub\": '|StringToJson ( pSub )|',\r\n \"pAddToSubset\": '|NumberToString( pAddToSubset )|',\r\n \"pLevelFrom\": '|NumberToString( pLevelFrom )|',\r\n \"pLevelTo\": '|NumberToString( pLevelTo )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|',\r\n \"pTemp\": '|NumberToString( pTemp )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npAlias = JsonToString( JsonGet( pJson, 'pAlias' ) );\r\npAttr = JsonToString( JsonGet( pJson, 'pAttr' ) );\r\npAttrValue = JsonToString( JsonGet( pJson, 'pAttrValue' ) );\r\npConsol = JsonToString( JsonGet( pJson, 'pConsol' ) );\r\npDelim = JsonToString( JsonGet( pJson, 'pDelim' ) );\r\npDim = JsonToString( JsonGet( pJson, 'pDim' ) );\r\npExclusions = JsonToString( JsonGet( pJson, 'pExclusions' ) );\r\npHier = JsonToString( JsonGet( pJson, 'pHier' ) );\r\npSub = JsonToString( JsonGet( pJson, 'pSub' ) );\r\n# Numeric Parameters\r\npAddToSubset = StringToNumber( JsonToString( JsonGet( pJson, 'pAddToSubset' ) ) );\r\npLevelFrom = StringToNumber( JsonToString( JsonGet( pJson, 'pLevelFrom' ) ) );\r\npLevelTo = StringToNumber( JsonToString( JsonGet( pJson, 'pLevelTo' ) ) );\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\npTemp = StringToNumber( JsonToString( JsonGet( pJson, 'pTemp' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n## LogOutput parameters\r\nIF ( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\nIf( Scan( ':', pDim ) > 0 & pHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pHier = SubSt( pDim, Scan( ':', pDim ) + 1, Long( pDim ) );\r\n pDim = SubSt( pDim, 1, Scan( ':', pDim ) - 1 );\r\nEndIf;\r\n\r\n## Validate dimension\r\nIF( Trim( pDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIF( DimensionExists( pDim ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid dimension: ' | pDim;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n## Validate Hierarchy\r\nIf( Trim( pHier ) @= '' );\r\n sHier = pDim;\r\nElse;\r\n sHier = pHier;\r\nEndIf;\r\nIF( sHier @= 'Leaves' );\r\n nErrors = 1;\r\n sMessage = 'Invalid Hierarchy: ' | pDim |':'|pHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIF(HierarchyExists(pDim, sHier ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid dimension Hierarchy: ' | pDim |':'|sHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n## Validate subset\r\nIF(Trim( pSub ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No subset specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n## Validate consolidation\r\npConsol = Trim( pConsol );\r\nIf( pConsol @<> '' & pConsol @<> '*' );\r\n If( ElementIndex(pDim, sHier, pConsol) = 0 );\r\n nErrors = 1;\r\n sMessage = 'The ' | pConsol | ' consolidation does not exist in the '| pDim |' dimension:Hierarchy ' | pDim |':'| sHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n Else;\r\n pConsol = HierarchyElementPrincipalName(pDim, sHier, pConsol);\r\n EndIf;\r\nEndIf;\r\n\r\n## Validate attribute\r\npAttr = Trim( pAttr );\r\nIF(pAttr @<> '' );\r\n\r\n If( DimensionExists( cAttributeDim ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Dimension: ' | pDim | ' does not have any attributes.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n EndIf;\r\n \r\n IF(DIMIX( cAttributeDim, pAttr ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'The ' | pAttr |' attribute does not exist in the ' | pDim | ' dimension.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n EndIf;\r\n \r\n sAttributeType = DType( cAttributeDim, pAttr );\r\n If(sAttributeType @= 'AN' % sAttributeType @= 'N' );\r\n If(pAttrValue @= '' );\r\n nAttributeValue = 0;\r\n Else;\r\n nAttributeValue = StringToNumber( pAttrValue );\r\n EndIf;\r\n EndIf;\r\n \r\nEndIf;\r\n\r\n## Validate element level parameters\r\nIf(pLevelFrom < 0 % pLevelTo < 0 % pLevelTo < pLevelFrom );\r\n nErrors = 1;\r\n sMessage = 'Element levels must be greater than or equal to zero and level to must be greater than or equal to level from';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate delimiter\r\nIF( pExclusions @<> '' & pDelim @= '' );\r\n ## Set to default parameter.\r\n pDelimiter = '&';\r\nEndIf;\r\n\r\n## Validate add to subset\r\nIF( pAddToSubset <> 0 & pAddToSubset <> 1 );\r\n nErrors = 1;\r\n sMessage = 'Invalid value for pAddToSubset: ' | NumberToString( pAddToSubset ) | '. Valid values are 0 and 1';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n## Validate Alias\r\nsDimAttr = '}ElementAttributes_' | pDim;\r\nIF( pAlias @<> '' );\r\n \r\n IF(DimensionExists( sDimAttr ) = 0 );\r\n sMessage = 'No attributes exist for the dimension: ' | pDim;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n pAlias = '';\r\n ElseIf(DIMIX( sDimAttr, pAlias ) = 0 );\r\n sMessage = 'The alias: ' | pAlias | ' does not exist as an attribute in the dimension: ' | pDim;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n pAlias = '';\r\n ElseIf(DTYPE( sDimAttr, pAlias ) @<> 'AA' );\r\n sMessage = 'The alias: ' | pAlias | ' is not an Alias type of attribute in the dimension: ' | sDimAttr;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n pAlias = '';\r\n EndIf;\r\n\r\nENDIF;\r\n\r\n## Validate pTemp\r\nIF( pTemp <> 0 & pTemp <> 1 );\r\n nErrors = 1;\r\n sMessage = 'Wrong parameter pTemp value (only 0 or 1 accepted).';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### Check for errors before preparing subset\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### Prepare subset ###\r\nIF( HierarchySubsetExists( pDim,sHier, pSub ) = 1 );\r\n If( pAddtoSubset <> 1 );\r\n HierarchySubsetDeleteAllElements( pDim, sHier, pSub );\r\n nSubsetSize = 0;\r\n Else;\r\n nSubsetSize = HierarchySubsetGetSize(pDim, sHier, pSub );\r\n EndIf;\r\nElse;\r\n HierarchySubsetCreate( pDim, sHier, pSub, pTemp );\r\n nSubsetSize = 0;\r\nEndIf;\r\n\r\n### Set Alias ###\r\nIF(pAlias @<> '' );\r\n HierarchySubsetAliasSet( pDim, pHier, pSub, pAlias);\r\nENDIF;\r\n\r\n### Assign Datasource ###\r\n\r\nDatasourceNameForServer = pDim|':'|sHier;\r\nDataSourceDimensionSubset = 'All';\r\n\r\n\r\n### End Prolog ###", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n\r\n### Check for errors in prolog ###\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n\r\n### Add elements to subset ###\r\n\r\n## Check that element is a descendant of specified consolidation\r\nIf( pConsol @<> '' & pConsol @<> '*' );\r\n If(ElementIsAncestor(pDim, pHier, pConsol, vEle) = 0 & vEle @<> pConsol );\r\n ItemSkip;\r\n EndIf;\r\nEndIf;\r\n\r\n## Check that element has a matching attribute value\r\nIf( pAttr @<> '' );\r\n If( sAttributeType @= 'AN' % sAttributeType @= 'N' );\r\n If( ElementAttrN( pDim, pHier, vEle, pAttr ) <> nAttributeValue );\r\n ItemSkip;\r\n EndIf;\r\n Else;\r\n If( ElementAttrS( pDim, pHier, vEle, pAttr ) @<> pAttrValue );\r\n ItemSkip;\r\n EndIf;\r\n EndIf;\r\nEndIf;\r\n\r\n## Check that element has an appropriate element level\r\nnElementLevel = ElementLevel( pDim, pHier, vEle );\r\nIf( nElementLevel < pLevelFrom % nElementLevel > pLevelTo );\r\n ItemSkip;\r\nEndIf;\r\n\r\n## Add element to subset\r\nnSubsetSize = nSubsetSize + 1;\r\n\r\nHierarchySubsetElementInsert( pDim, pHier, pSub, vEle, nSubsetSize );\r\n\r\n### End Metadata ###", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n\r\n ### Process Exclusions ###\r\n IF( nErrors = 0 & Trim( pExclusions ) @<> '' );\r\n ExecuteProcess( '}bedrock.hier.sub.exclude',\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pDim', pDim,\r\n 'pHier', pHier,\r\n 'pSub', pSub,\r\n 'pExclusions', pExclusions,\r\n 'pDelim', pDelim\r\n );\r\n EndIf;\r\n \r\n ### Get subset size ###\r\n nSubSiz = SubsetGetSize( pDim|':'|sHier, pSub );\r\n sSubSiz = NumberToString( nSubSiz );\r\n If( nSubSiz = 0 );\r\n nErrors = 1;\r\n sMessage= 'Subset contains no elements.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n EndIf;\r\nEndIf;\r\n \r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% created subset %pDim%:%pHier%:%pSub% with %sSubSiz% elements. ' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n### End Epilog ###", @@ -13,27 +13,15 @@ "subset": "All" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pDim", - "Prompt": "REQUIRED: Dimension name", + "Prompt": "REQUIRED: Delimited list of dimensions", "Value": "", "Type": "String" }, { "Name": "pHier", - "Prompt": "OPTIONAL: Hierarchy name (default if blank = same named hierarchy)", + "Prompt": "OPTIONAL: Hierarchy name (Default = pDim)", "Value": "", "Type": "String" }, @@ -45,7 +33,7 @@ }, { "Name": "pConsol", - "Prompt": "OPTIONAL: Elements within Consolidated Element (Blank or * Equals All)", + "Prompt": "OPTIONAL: Consolidated element name used as source (Default = '*')", "Value": "*", "Type": "String" }, @@ -57,51 +45,69 @@ }, { "Name": "pAttrValue", - "Prompt": "OPTIONAL: Attribute Value", + "Prompt": "OPTIONAL: Attribute value", "Value": "", "Type": "String" }, { "Name": "pLevelFrom", - "Prompt": "OPTIONAL: From Element Level", + "Prompt": "OPTIONAL: From Element Level (Default = 0)", "Value": 0, "Type": "Numeric" }, { "Name": "pLevelTo", - "Prompt": "OPTIONAL: To Element Level", + "Prompt": "OPTIONAL: To Element Level (Default = 999)", "Value": 999, "Type": "Numeric" }, { "Name": "pExclusions", - "Prompt": "OPTIONAL: Elements to Exclude From Subset (Separated by Delimiter, Accepts Wild card)", + "Prompt": "OPTIONAL: Delimited list of elements to exclude", "Value": "", "Type": "String" }, { "Name": "pDelim", - "Prompt": "OPTIONAL: Delimiter character", + "Prompt": "OPTIONAL: Delimiter for list parameters (Default = '&')", "Value": "&", "Type": "String" }, { "Name": "pAddToSubset", - "Prompt": "OPTIONAL: Add to Subset if it Already Exists (0=No 1=Yes)", + "Prompt": "OPTIONAL: Add to subset if it already exists (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { "Name": "pAlias", - "Prompt": "OPTIONAL: Set Alias for Subset", + "Prompt": "OPTIONAL: Set alias for subset", "Value": "", "Type": "String" }, { "Name": "pTemp", - "Prompt": "OPTIONAL: Use temporary objects? (Boolean 1=True)", + "Prompt": "OPTIONAL: Delete/create temporary objects (0 = Do not delete, 1 = Delete, 2 = if view and subsets are created, keep only subsets)", "Value": 1, "Type": "Numeric" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [ diff --git a/bedrock_processes_json/}bedrock.hier.sub.create.leaf.json b/bedrock_processes_json/}bedrock.hier.sub.create.leaf.json index 8a7e98b..8e92c3e 100644 --- a/bedrock_processes_json/}bedrock.hier.sub.create.leaf.json +++ b/bedrock_processes_json/}bedrock.hier.sub.create.leaf.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.hier.sub.create.leaf", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.sub.create.leaf', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pDim', '', 'pHier', '', 'pSub', '',\r\n \t'pAddToSubset', 0, 'pExclusions', '',\r\n \t'pDelim', '&', 'pAlias', '', 'pTemp', 1\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will create a static subset in Hierarchy of a Dimension that consists of all leaf\r\n# elements.\r\n\r\n# Note:\r\n# This process uses modification parameters to determine what to include in the subset:\r\n# - pExclusions: If pExclusions is specified then the elements (separated by a delimiter) will be\r\n# excluded from the subset. Wildcards characters `*` and `?` are accepted.\r\n# - pAddToSubset: If the specified subset already exists then this parameter will control whether elements will\r\n# be added to the existing subset (value 1) or a new subset will be created (value 0).\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\nnErrors = 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pHier:%pHier%, pSub:%pSub%, pExclusions:%pExclusions%, pDelim:%pDelim%, pAddToSubset:%pAddToSubset%, pAlias:%pAlias%, pTemp:%pTemp%.';\r\ncAttributeDim = '}ElementAttributes_' | pDim;\r\n\r\n\r\n## LogOutput parameters\r\nIF ( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\nnErrors = 0;\r\n\r\n## Validate pTemp\r\nIF( pTemp <> 0 & pTemp <> 1 );\r\n nErrors = 1;\r\n sMessage = 'Wrong parameter pTemp value (only 0 or 1 accepted).';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nnRet = \r\nExecuteProcess( '}bedrock.hier.sub.create', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pDim', pDim, 'pHier',pHier, 'pSub', pSub,\r\n 'pLevelFrom', 0, 'pLevelTo', 0,\r\n 'pExclusions', pExclusions, 'pAddToSubset', pAddToSubset,\r\n 'pDelim', pDelim, 'pAlias', pAlias, 'pTemp', pTemp\r\n);\r\n\r\n### End Prolog ###", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.sub.create.leaf', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pDim', '', 'pHier', '', 'pSub', '',\r\n \t'pAddToSubset', 0, 'pExclusions', '',\r\n \t'pDelim', '&', 'pAlias', '', 'pTemp', 1\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will create a static subset in Hierarchy of a Dimension that consists of all leaf\r\n# elements.\r\n\r\n# Note:\r\n# This process uses modification parameters to determine what to include in the subset:\r\n# - pExclusions: If pExclusions is specified then the elements (separated by a delimiter) will be\r\n# excluded from the subset. Wildcards characters `*` and `?` are accepted.\r\n# - pAddToSubset: If the specified subset already exists then this parameter will control whether elements will\r\n# be added to the existing subset (value 1) or a new subset will be created (value 0).\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\nnErrors = 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pHier:%pHier%, pSub:%pSub%, pExclusions:%pExclusions%, pDelim:%pDelim%, pAddToSubset:%pAddToSubset%, pAlias:%pAlias%, pTemp:%pTemp%.';\r\ncAttributeDim = '}ElementAttributes_' | pDim;\r\n\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pAlias\": \"\",\r\n \"pDelim\": \"&\",\r\n \"pDim\": null,\r\n \"pExclusions\": \"\",\r\n \"pHier\": \"\",\r\n \"pSub\": null,\r\n \"pAddToSubset\": 0,\r\n \"pLogOutput\": 0,\r\n \"pStrictErrorHandling\": 0,\r\n \"pTemp\": 1\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pAlias\": '|StringToJson ( pAlias )|',\r\n \"pDelim\": '|StringToJson ( pDelim )|',\r\n \"pDim\": '|StringToJson ( pDim )|',\r\n \"pExclusions\": '|StringToJson ( pExclusions )|',\r\n \"pHier\": '|StringToJson ( pHier )|',\r\n \"pSub\": '|StringToJson ( pSub )|',\r\n \"pAddToSubset\": '|NumberToString( pAddToSubset )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|',\r\n \"pTemp\": '|NumberToString( pTemp )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npAlias = JsonToString( JsonGet( pJson, 'pAlias' ) );\r\npDelim = JsonToString( JsonGet( pJson, 'pDelim' ) );\r\npDim = JsonToString( JsonGet( pJson, 'pDim' ) );\r\npExclusions = JsonToString( JsonGet( pJson, 'pExclusions' ) );\r\npHier = JsonToString( JsonGet( pJson, 'pHier' ) );\r\npSub = JsonToString( JsonGet( pJson, 'pSub' ) );\r\n# Numeric Parameters\r\npAddToSubset = StringToNumber( JsonToString( JsonGet( pJson, 'pAddToSubset' ) ) );\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\npTemp = StringToNumber( JsonToString( JsonGet( pJson, 'pTemp' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n## LogOutput parameters\r\nIF ( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\nnErrors = 0;\r\n\r\n## Validate pTemp\r\nIF( pTemp <> 0 & pTemp <> 1 );\r\n nErrors = 1;\r\n sMessage = 'Wrong parameter pTemp value (only 0 or 1 accepted).';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nnRet = \r\nExecuteProcess( '}bedrock.hier.sub.create', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pDim', pDim, 'pHier',pHier, 'pSub', pSub,\r\n 'pLevelFrom', 0, 'pLevelTo', 0,\r\n 'pExclusions', pExclusions, 'pAddToSubset', pAddToSubset,\r\n 'pDelim', pDelim, 'pAlias', pAlias, 'pTemp', pTemp\r\n);\r\n\r\n### End Prolog ###", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully created subset %pSub% from dimension %pDim%.' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n### End Epilog ###", @@ -10,27 +10,15 @@ "Type": "None" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pDim", - "Prompt": "REQUIRED: Dimension name", + "Prompt": "REQUIRED: Delimited list of dimensions", "Value": "", "Type": "String" }, { "Name": "pHier", - "Prompt": "OPTIONAL: Hierarchy name (default if blank = same named hierarchy)", + "Prompt": "OPTIONAL: Hierarchy name (Default = pDim)", "Value": "", "Type": "String" }, @@ -42,33 +30,51 @@ }, { "Name": "pAddToSubset", - "Prompt": "OPTIONAL: Add to Subset if it Already Exists (0=No 1=Yes)", + "Prompt": "OPTIONAL: Add to subset if it already exists (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { "Name": "pExclusions", - "Prompt": "OPTIONAL: Elements to Exclude From Subset (Separated by Delimiter, Accepts Wild card)", + "Prompt": "OPTIONAL: Delimited list of elements to exclude", "Value": "", "Type": "String" }, { "Name": "pDelim", - "Prompt": "OPTIONAL: Delimiter character", + "Prompt": "OPTIONAL: Delimiter for list parameters (Default = '&')", "Value": "&", "Type": "String" }, { "Name": "pAlias", - "Prompt": "OPTIONAL: Set Alias for Subset", + "Prompt": "OPTIONAL: Set alias for subset", "Value": "", "Type": "String" }, { "Name": "pTemp", - "Prompt": "OPTIONAL: Use temporary objects? (Boolean 1=True)", + "Prompt": "OPTIONAL: Delete/create temporary objects (0 = Do not delete, 1 = Delete, 2 = if view and subsets are created, keep only subsets)", "Value": 1, "Type": "Numeric" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [], diff --git a/bedrock_processes_json/}bedrock.hier.sub.create.orphans.json b/bedrock_processes_json/}bedrock.hier.sub.create.orphans.json index 795eeec..47e5696 100644 --- a/bedrock_processes_json/}bedrock.hier.sub.create.orphans.json +++ b/bedrock_processes_json/}bedrock.hier.sub.create.orphans.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.hier.sub.create.orphans", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.sub.create.orphans', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n\t 'pDim', '', 'pHier', '', 'pTemp', 1\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will create a static subset in a Hierarchy of target Dimension that consists of\r\n# all orphan elements.\r\n\r\n# Note:\r\n# Orphan element is defined as:\r\n# - Consolidated element without children.\r\n# - Leaf element without parent.\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pHier:%pHier%, pTemp:%pTemp%.'; \r\ncAttributeDim = '}ElementAttributes_' | pDim;\r\ncSubsetOrphanC = 'Orphan C Elements (no children)';\r\ncSubsetOrphanN = 'Orphan N Elements (no parents)';\r\n\r\n## LogOutput parameters\r\nIF ( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\nIf( Scan( ':', pDim ) > 0 & pHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pHier = SubSt( pDim, Scan( ':', pDim ) + 1, Long( pDim ) );\r\n pDim = SubSt( pDim, 1, Scan( ':', pDim ) - 1 );\r\nEndIf;\r\n\r\n# Validate dimension\r\nIf( Trim( pDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No dimension specified';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\nIf( DimensionExists( pDim ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid dimension: ' | pDim;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n## Validate Hierarchy\r\nIF(pHier @= 'Leaves' );\r\n nErrors = 1;\r\n sMessage = 'Invalid Hierarchy: ' | pDim |':'|pHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nIf( Trim( pHier ) @= '' );\r\n sHier = pDim;\r\nElse;\r\n sHier = pHier;\r\nEndIf;\r\n\r\nIF(HierarchyExists(pDim, sHier ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid dimension Hierarchy: ' | pDim |':'|sHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n## Validate pTemp\r\nIF( pTemp <> 0 & pTemp <> 1 );\r\n nErrors = 1;\r\n sMessage = 'Wrong parameter pTemp value (only 0 or 1 accepted).';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### Create Subsets ###\r\nIf( nErrors = 0 );\r\n If( HierarchySubsetExists( pDim, sHier, cSubsetOrphanC ) = 1 );\r\n HierarchySubsetDeleteAllElements( pDim, sHier, cSubsetOrphanC );\r\n Else;\r\n HierarchySubsetCreate( pDim, sHier, cSubsetOrphanC, pTemp );\r\n EndIf;\r\n If( HierarchySubsetExists( pDim, sHier, cSubsetOrphanN ) = 1 );\r\n HierarchySubsetDeleteAllElements( pDim, sHier, cSubsetOrphanN );\r\n Else;\r\n HierarchySubsetCreate( pDim, sHier, cSubsetOrphanN, pTemp );\r\n EndIf;\r\nEndIf;\r\n\r\n\r\n### Populate subsets ###\r\nnElementCount = DimSiz( pDim|':'|sHier);\r\nnElementIndex = 1;\r\nnLeafCount = 0;\r\nnConsolCount = 0;\r\nWhile( nElementIndex <= nElementCount );\r\n sElement = ElementName( pDim, sHier, nElementIndex );\r\n If( ElementType( pDim, sHier, sElement ) @= 'N' & ElementParent( pDim, sHier, sElement, 1 ) @= '' );\r\n # N element with no parents\r\n nLeafCount = nLeafCount + 1;\r\n HierarchySubsetElementInsert( pDim, sHier, cSubsetOrphanN, sElement, nLeafCount );\r\n EndIf;\r\n If(ElementType(pDim,sHier, sElement) @= 'C' & ElementComponentCount(pDim, sHier, sElement) = 0);\r\n # C element with no children\r\n nConsolCount = nConsolCount + 1;\r\n HierarchySubsetElementInsert( pDim, sHier, cSubsetOrphanC, sElement, nConsolCount );\r\n EndIf;\r\n nElementIndex = nElementIndex + 1;\r\nEnd;\r\n\r\n\r\n### Tidy up ###\r\n\r\n# If no orphans then destroy empty subsets\r\nIf( nErrors = 0 );\r\n If( HierarchySubsetGetSize( pDim, sHier, cSubsetOrphanN ) = 0 );\r\n HierarchySubsetDestroy( pDim, sHier, cSubsetOrphanN );\r\n EndIf;\r\n If( HierarchySubsetGetSize( pDim, sHier, cSubsetOrphanC ) = 0 );\r\n HierarchySubsetDestroy( pDim, sHier, cSubsetOrphanC );\r\n EndIf;\r\nEndIf;\r\n\r\n\r\n### End Prolog ###", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.sub.create.orphans', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n\t 'pDim', '', 'pHier', '', 'pTemp', 1\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will create a static subset in a Hierarchy of target Dimension that consists of\r\n# all orphan elements.\r\n\r\n# Note:\r\n# Orphan element is defined as:\r\n# - Consolidated element without children.\r\n# - Leaf element without parent.\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pHier:%pHier%, pTemp:%pTemp%.'; \r\ncAttributeDim = '}ElementAttributes_' | pDim;\r\ncSubsetOrphanC = 'Orphan C Elements (no children)';\r\ncSubsetOrphanN = 'Orphan N Elements (no parents)';\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pDim\": null,\r\n \"pHier\": \"\",\r\n \"pLogOutput\": 0,\r\n \"pStrictErrorHandling\": 0,\r\n \"pTemp\": 1\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pDim\": '|StringToJson ( pDim )|',\r\n \"pHier\": '|StringToJson ( pHier )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|',\r\n \"pTemp\": '|NumberToString( pTemp )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npDim = JsonToString( JsonGet( pJson, 'pDim' ) );\r\npHier = JsonToString( JsonGet( pJson, 'pHier' ) );\r\n# Numeric Parameters\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\npTemp = StringToNumber( JsonToString( JsonGet( pJson, 'pTemp' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n## LogOutput parameters\r\nIF ( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\nIf( Scan( ':', pDim ) > 0 & pHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pHier = SubSt( pDim, Scan( ':', pDim ) + 1, Long( pDim ) );\r\n pDim = SubSt( pDim, 1, Scan( ':', pDim ) - 1 );\r\nEndIf;\r\n\r\n# Validate dimension\r\nIf( Trim( pDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No dimension specified';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\nIf( DimensionExists( pDim ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid dimension: ' | pDim;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n## Validate Hierarchy\r\nIF(pHier @= 'Leaves' );\r\n nErrors = 1;\r\n sMessage = 'Invalid Hierarchy: ' | pDim |':'|pHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nIf( Trim( pHier ) @= '' );\r\n sHier = pDim;\r\nElse;\r\n sHier = pHier;\r\nEndIf;\r\n\r\nIF(HierarchyExists(pDim, sHier ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid dimension Hierarchy: ' | pDim |':'|sHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n## Validate pTemp\r\nIF( pTemp <> 0 & pTemp <> 1 );\r\n nErrors = 1;\r\n sMessage = 'Wrong parameter pTemp value (only 0 or 1 accepted).';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### Create Subsets ###\r\nIf( nErrors = 0 );\r\n If( HierarchySubsetExists( pDim, sHier, cSubsetOrphanC ) = 1 );\r\n HierarchySubsetDeleteAllElements( pDim, sHier, cSubsetOrphanC );\r\n Else;\r\n HierarchySubsetCreate( pDim, sHier, cSubsetOrphanC, pTemp );\r\n EndIf;\r\n If( HierarchySubsetExists( pDim, sHier, cSubsetOrphanN ) = 1 );\r\n HierarchySubsetDeleteAllElements( pDim, sHier, cSubsetOrphanN );\r\n Else;\r\n HierarchySubsetCreate( pDim, sHier, cSubsetOrphanN, pTemp );\r\n EndIf;\r\nEndIf;\r\n\r\n\r\n### Populate subsets ###\r\nnElementCount = DimSiz( pDim|':'|sHier);\r\nnElementIndex = 1;\r\nnLeafCount = 0;\r\nnConsolCount = 0;\r\nWhile( nElementIndex <= nElementCount );\r\n sElement = ElementName( pDim, sHier, nElementIndex );\r\n If( ElementType( pDim, sHier, sElement ) @= 'N' & ElementParent( pDim, sHier, sElement, 1 ) @= '' );\r\n # N element with no parents\r\n nLeafCount = nLeafCount + 1;\r\n HierarchySubsetElementInsert( pDim, sHier, cSubsetOrphanN, sElement, nLeafCount );\r\n EndIf;\r\n If(ElementType(pDim,sHier, sElement) @= 'C' & ElementComponentCount(pDim, sHier, sElement) = 0);\r\n # C element with no children\r\n nConsolCount = nConsolCount + 1;\r\n HierarchySubsetElementInsert( pDim, sHier, cSubsetOrphanC, sElement, nConsolCount );\r\n EndIf;\r\n nElementIndex = nElementIndex + 1;\r\nEnd;\r\n\r\n\r\n### Tidy up ###\r\n\r\n# If no orphans then destroy empty subsets\r\nIf( nErrors = 0 );\r\n If( HierarchySubsetGetSize( pDim, sHier, cSubsetOrphanN ) = 0 );\r\n HierarchySubsetDestroy( pDim, sHier, cSubsetOrphanN );\r\n EndIf;\r\n If( HierarchySubsetGetSize( pDim, sHier, cSubsetOrphanC ) = 0 );\r\n HierarchySubsetDestroy( pDim, sHier, cSubsetOrphanC );\r\n EndIf;\r\nEndIf;\r\n\r\n\r\n### End Prolog ###", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n If( nLeafCount > 0 );\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully created subset %cSubsetOrphanN% from dimension %pDim%:%pHier%.' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) );\r\n nProcessReturnCode = 0; \r\n EndIf;\r\n EndIf ;\r\n \r\n If( nConsolCount > 0 );\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully created subset %cSubsetOrphanC% from dimension %pDim%:%pHier%.' );\r\n \r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\n Endif ;\r\nEndIf;\r\n\r\n### End Epilog ###", @@ -10,35 +10,41 @@ "Type": "None" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pDim", - "Prompt": "REQUIRED: Dimension name", + "Prompt": "REQUIRED: Delimited list of dimensions", "Value": "", "Type": "String" }, { "Name": "pHier", - "Prompt": "OPTIONAL: Hierarchy name (default if blank = same named hierarchy)", + "Prompt": "OPTIONAL: Hierarchy name (Default = pDim)", "Value": "", "Type": "String" }, { "Name": "pTemp", - "Prompt": "OPTIONAL: Use temporary objects? (Boolean 1=True)", + "Prompt": "OPTIONAL: Delete/create temporary objects (0 = Do not delete, 1 = Delete, 2 = if view and subsets are created, keep only subsets)", "Value": 1, "Type": "Numeric" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [], diff --git a/bedrock_processes_json/}bedrock.hier.sub.create.toplevelhierarchy.json b/bedrock_processes_json/}bedrock.hier.sub.create.toplevelhierarchy.json index 4e7a0f4..43eb347 100644 --- a/bedrock_processes_json/}bedrock.hier.sub.create.toplevelhierarchy.json +++ b/bedrock_processes_json/}bedrock.hier.sub.create.toplevelhierarchy.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.hier.sub.create.toplevelhierarchy", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.sub.create.toplevelhierarchy', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pDim', '', 'pHier', '', 'pSub', '',\r\n \t'pConvertToStatic', 1, 'pAlias', '', 'pTemp', 1\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n\r\n# This process will Create a Top Level Hierarchy by N-Level Elements\r\n# that is a subset of all \"top node\" elements ( Consolidated elements that have no parents )\r\n\r\n#EndRegion @DOC\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pHier:%pHier%, pSub:%pSub%, pConvertToStatic:%pConvertToStatic%, pAlias:%pAlias%, pTemp:%pTemp%.'; \r\ncAttributeDim = '}ElementAttributes_' | pDim;\r\n\r\n\r\n### Validate Parameters ###\r\n\r\nnErrors = 0;\r\n\r\nIf( Scan( ':', pDim ) > 0 & pHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pHier = SubSt( pDim, Scan( ':', pDim ) + 1, Long( pDim ) );\r\n pDim = SubSt( pDim, 1, Scan( ':', pDim ) - 1 );\r\nEndIf;\r\n\r\n# Validate dimension\r\nIf( Trim( pDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No dimension specified';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\nIf( DimensionExists( pDim ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid dimension: ' | pDim;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n\r\n## Validate Hierarchy\r\nIF(pHier @= 'Leaves' );\r\n nErrors = 1;\r\n sMessage = 'Invalid Hierarchy: ' | pDim |':'|pHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nIf( Trim( pHier ) @= '' );\r\n sHier = pDim;\r\nElse;\r\n sHier = pHier;\r\nEndIf;\r\n\r\nIF(HierarchyExists(pDim, sHier ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid dimension Hierarchy: ' | pDim |':'|sHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nIf( DnLev( pDim|':'|sHier ) <= 1 );\r\n # Create by MDX would return empty set and fail so need to abort here\r\n nErrors = 1;\r\n sMessage = 'Cannot continue, dimension hierarchy is flat: ' | pDim|':'|sHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIF;\r\n\r\n\r\n# Validate subset\r\nIf( Trim( pSub ) @= '' );\r\n pSub = 'Top Level Hierarchies';\r\nEndIf;\r\n\r\n## Validate Alias\r\nsDimAttr = '}ElementAttributes_' | pDim;\r\nIF(pAlias @<> '' );\r\n IF(DimensionExists( sDimAttr ) = 0 );\r\n sMessage = 'No attributes exist for the dimension: ' | pDim;\r\n pAlias = '';\r\n EndIf;\r\n\r\n IF(DIMIX( sDimAttr, pAlias ) = 0 );\r\n sMessage = 'The Alias: ' | pAlias | ' does not exist in the dimension: ' | pDim;\r\n pAlias = '';\r\n EndIf;\r\n\r\n IF(DTYPE( sDimAttr, pAlias ) @<> 'AA' );\r\n sMessage = 'The Alias: ' | pAlias | ' is not an Alias in the dimension: ' | sDimAttr;\r\n pAlias = '';\r\n EndIf;\r\nENDIF;\r\n\r\n## Validate pTemp\r\nIF( pTemp <> 0 & pTemp <> 1 );\r\n nErrors = 1;\r\n sMessage = 'Wrong parameter pTemp value (only 0 or 1 accepted).';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### MDX for creating subset ###\r\nsMDX = '{EXCEPT( {FILTER( {TM1SUBSETALL( [' | pDim|'].['|sHier | '] )}, MemberToStr( [' |\r\n pDim|':'|sHier | '].CurrentMember.Parent ) = \"\" )},' |\r\n '{TM1FILTERBYLEVEL( {TM1SUBSETALL( [' | pDim|'].['|sHier | '] )},0 )} )}';\r\n\r\n\r\n### Create Subset ###\r\n\r\nIf( nErrors = 0 );\r\n\r\n # For a dynamic subset, the original subset MUST be destroyed first or the MDX will fail\r\n If( pConvertToStatic = 0 );\r\n If( HierarchySubsetExists( pDim, sHier, pSub ) = 1 );\r\n HierarchySubsetDestroy( pDim, sHier, pSub );\r\n EndIf;\r\n SubsetCreateByMDX( pSub, sMDX, pDim, pTemp );\r\n\r\n # For a static subset the subset does not need to be destroyed but its elements need to be deleted first\r\n Else;\r\n If( HierarchySubsetExists( pDim, sHier, pSub ) = 1 );\r\n HierarchySubsetDeleteAllElements( pDim, sHier, pSub );\r\n Else;\r\n HierarchySubsetCreate( pDim, sHier, pSub, pTemp );\r\n EndIf;\r\n\r\n # Create a temporary MDX subset for processing\r\n sSubsetMDX = cThisProcName |'.' | NumberToString( Int( Rand() * 100000 ) );\r\n # It is unlikely that the subset already exists due to the random number in the subset name\r\n # However, it the SubsetDestroy is included in case the same random number is generated\r\n If( HierarchySubsetExists( pDim, sHier, sSubsetMDX ) = 1 );\r\n HierarchySubsetDestroy( pDim, sHier, sSubsetMDX );\r\n EndIf;\r\n SubsetCreateByMDX( sSubsetMDX, sMDX, pDim, pTemp );\r\n\r\n # Transfer the elements from the MDX subset to the static subset\r\n nSubsetSize = HierarchySubsetGetSize( pDim, sHier,sSubsetMDX );\r\n nSubsetIndex = 0;\r\n While( nSubsetIndex < nSubsetSize );\r\n nSubsetIndex = nSubsetIndex + 1;\r\n sTemp = HierarchySubsetElementGetIndex (pDim, sHier, sSubsetMDX, '', nSubsetIndex);\r\n sElement = HierarchySubsetGetElementName( pDim, sHier, sSubsetMDX, nSubsetIndex );\r\n HierarchySubsetElementInsert( pDim, sHier, pSub, sElement, nSubsetIndex );\r\n End;\r\n EndIf;\r\n\r\nEndIf;\r\n\r\n### Set Alias ##\r\nIF(pAlias @<> '' );\r\n If( nErrors = 0 );\r\n HierarchySubsetAliasSet( pDim, pHier, pSub, pAlias );\r\n EndIf;\r\nENDIF;\r\n\r\n### End Prolog ###", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.sub.create.toplevelhierarchy', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pDim', '', 'pHier', '', 'pSub', '',\r\n \t'pConvertToStatic', 1, 'pAlias', '', 'pTemp', 1\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n\r\n# This process will Create a Top Level Hierarchy by N-Level Elements\r\n# that is a subset of all \"top node\" elements ( Consolidated elements that have no parents )\r\n\r\n#EndRegion @DOC\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pHier:%pHier%, pSub:%pSub%, pConvertToStatic:%pConvertToStatic%, pAlias:%pAlias%, pTemp:%pTemp%.'; \r\ncAttributeDim = '}ElementAttributes_' | pDim;\r\n\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pAlias\": \"\",\r\n \"pDim\": null,\r\n \"pHier\": \"\",\r\n \"pSub\": null,\r\n \"pConvertToStatic\": 1,\r\n \"pLogOutput\": 0,\r\n \"pStrictErrorHandling\": 0,\r\n \"pTemp\": 1\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pAlias\": '|StringToJson ( pAlias )|',\r\n \"pDim\": '|StringToJson ( pDim )|',\r\n \"pHier\": '|StringToJson ( pHier )|',\r\n \"pSub\": '|StringToJson ( pSub )|',\r\n \"pConvertToStatic\": '|NumberToString( pConvertToStatic )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|',\r\n \"pTemp\": '|NumberToString( pTemp )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npAlias = JsonToString( JsonGet( pJson, 'pAlias' ) );\r\npDim = JsonToString( JsonGet( pJson, 'pDim' ) );\r\npHier = JsonToString( JsonGet( pJson, 'pHier' ) );\r\npSub = JsonToString( JsonGet( pJson, 'pSub' ) );\r\n# Numeric Parameters\r\npConvertToStatic = StringToNumber( JsonToString( JsonGet( pJson, 'pConvertToStatic' ) ) );\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\npTemp = StringToNumber( JsonToString( JsonGet( pJson, 'pTemp' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n### Validate Parameters ###\r\n\r\nnErrors = 0;\r\n\r\nIf( Scan( ':', pDim ) > 0 & pHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pHier = SubSt( pDim, Scan( ':', pDim ) + 1, Long( pDim ) );\r\n pDim = SubSt( pDim, 1, Scan( ':', pDim ) - 1 );\r\nEndIf;\r\n\r\n# Validate dimension\r\nIf( Trim( pDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No dimension specified';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\nIf( DimensionExists( pDim ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid dimension: ' | pDim;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n\r\n## Validate Hierarchy\r\nIF(pHier @= 'Leaves' );\r\n nErrors = 1;\r\n sMessage = 'Invalid Hierarchy: ' | pDim |':'|pHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nIf( Trim( pHier ) @= '' );\r\n sHier = pDim;\r\nElse;\r\n sHier = pHier;\r\nEndIf;\r\n\r\nIF(HierarchyExists(pDim, sHier ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid dimension Hierarchy: ' | pDim |':'|sHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nIf( DnLev( pDim|':'|sHier ) <= 1 );\r\n # Create by MDX would return empty set and fail so need to abort here\r\n nErrors = 1;\r\n sMessage = 'Cannot continue, dimension hierarchy is flat: ' | pDim|':'|sHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIF;\r\n\r\n\r\n# Validate subset\r\nIf( Trim( pSub ) @= '' );\r\n pSub = 'Top Level Hierarchies';\r\nEndIf;\r\n\r\n## Validate Alias\r\nsDimAttr = '}ElementAttributes_' | pDim;\r\nIF(pAlias @<> '' );\r\n IF(DimensionExists( sDimAttr ) = 0 );\r\n sMessage = 'No attributes exist for the dimension: ' | pDim;\r\n pAlias = '';\r\n EndIf;\r\n\r\n IF(DIMIX( sDimAttr, pAlias ) = 0 );\r\n sMessage = 'The Alias: ' | pAlias | ' does not exist in the dimension: ' | pDim;\r\n pAlias = '';\r\n EndIf;\r\n\r\n IF(DTYPE( sDimAttr, pAlias ) @<> 'AA' );\r\n sMessage = 'The Alias: ' | pAlias | ' is not an Alias in the dimension: ' | sDimAttr;\r\n pAlias = '';\r\n EndIf;\r\nENDIF;\r\n\r\n## Validate pTemp\r\nIF( pTemp <> 0 & pTemp <> 1 );\r\n nErrors = 1;\r\n sMessage = 'Wrong parameter pTemp value (only 0 or 1 accepted).';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### MDX for creating subset ###\r\nsMDX = '{EXCEPT( {FILTER( {TM1SUBSETALL( [' | pDim|'].['|sHier | '] )}, MemberToStr( [' |\r\n pDim|'].['|sHier | '].CurrentMember.Parent ) = \"\" )},' |\r\n '{TM1FILTERBYLEVEL( {TM1SUBSETALL( [' | pDim|'].['|sHier | '] )},0 )} )}';\r\n\r\n\r\n### Create Subset ###\r\n\r\nIf( nErrors = 0 );\r\n\r\n # For a dynamic subset, the original subset MUST be destroyed first or the MDX will fail\r\n If( pConvertToStatic = 0 );\r\n If( HierarchySubsetExists( pDim, sHier, pSub ) = 1 );\r\n HierarchySubsetDestroy( pDim, sHier, pSub );\r\n EndIf;\r\n SubsetCreateByMDX( pSub, sMDX, pDim, pTemp );\r\n\r\n # For a static subset the subset does not need to be destroyed but its elements need to be deleted first\r\n Else;\r\n If( HierarchySubsetExists( pDim, sHier, pSub ) = 1 );\r\n HierarchySubsetDeleteAllElements( pDim, sHier, pSub );\r\n Else;\r\n HierarchySubsetCreate( pDim, sHier, pSub, pTemp );\r\n EndIf;\r\n\r\n # Create a temporary MDX subset for processing\r\n sSubsetMDX = cThisProcName |'.' | NumberToString( Int( Rand() * 100000 ) );\r\n # It is unlikely that the subset already exists due to the random number in the subset name\r\n # However, it the SubsetDestroy is included in case the same random number is generated\r\n If( HierarchySubsetExists( pDim, sHier, sSubsetMDX ) = 1 );\r\n HierarchySubsetDestroy( pDim, sHier, sSubsetMDX );\r\n EndIf;\r\n SubsetCreateByMDX( sSubsetMDX, sMDX, pDim, pTemp );\r\n\r\n # Transfer the elements from the MDX subset to the static subset\r\n nSubsetSize = HierarchySubsetGetSize( pDim, sHier,sSubsetMDX );\r\n nSubsetIndex = 0;\r\n While( nSubsetIndex < nSubsetSize );\r\n nSubsetIndex = nSubsetIndex + 1;\r\n sTemp = HierarchySubsetElementGetIndex (pDim, sHier, sSubsetMDX, '', nSubsetIndex);\r\n sElement = HierarchySubsetGetElementName( pDim, sHier, sSubsetMDX, nSubsetIndex );\r\n HierarchySubsetElementInsert( pDim, sHier, pSub, sElement, nSubsetIndex );\r\n End;\r\n EndIf;\r\n\r\nEndIf;\r\n\r\n### Set Alias ##\r\nIF(pAlias @<> '' );\r\n If( nErrors = 0 );\r\n HierarchySubsetAliasSet( pDim, pHier, pSub, pAlias );\r\n EndIf;\r\nENDIF;\r\n\r\n### End Prolog ###", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully created subset %pSub% from dimension %pDim%.' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n### End Epilog ###", @@ -10,27 +10,15 @@ "Type": "None" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pDim", - "Prompt": "REQUIRED: Dimension name", + "Prompt": "REQUIRED: Delimited list of dimensions", "Value": "", "Type": "String" }, { "Name": "pHier", - "Prompt": "OPTIONAL: Hierarchy name (default if blank = same named hierarchy)", + "Prompt": "OPTIONAL: Hierarchy name (Default = pDim)", "Value": "", "Type": "String" }, @@ -42,21 +30,39 @@ }, { "Name": "pConvertToStatic", - "Prompt": "OPTIONAL: Boolean: 1 = Convert to Static Subset", + "Prompt": "OPTIONAL: Convert the subset to static (Boolean. Default = 1)", "Value": 1, "Type": "Numeric" }, { "Name": "pAlias", - "Prompt": "OPTIONAL: Set Alias for Subset", + "Prompt": "OPTIONAL: Set alias for subset", "Value": "", "Type": "String" }, { "Name": "pTemp", - "Prompt": "OPTIONAL: Use temporary objects? (Boolean 1=True)", + "Prompt": "OPTIONAL: Delete/create temporary objects (0 = Do not delete, 1 = Delete, 2 = if view and subsets are created, keep only subsets)", "Value": 1, "Type": "Numeric" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [], diff --git a/bedrock_processes_json/}bedrock.hier.sub.delete.json b/bedrock_processes_json/}bedrock.hier.sub.delete.json index 7291a4a..309974b 100644 --- a/bedrock_processes_json/}bedrock.hier.sub.delete.json +++ b/bedrock_processes_json/}bedrock.hier.sub.delete.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.hier.sub.delete", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.sub.delete', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pDim', '', 'pHier', '', 'pSub', '',\r\n \t'pDelim', '&', 'pMode', 0\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process deletes public subsets from selected dimension and hierarchies. Dimensions, hierarchies\r\n# and subsets can be specified as a delimited list. Wildcards are accepted as `*` and `?` characters.\r\n\r\n# Note:\r\n# - pDim: To specify which dimensions to delete subsets from use the pDim parameter.\r\n# - To delete subsets from a single dimension only just specify that dimension name e.g. `Product`.\r\n# - To delete subsets from multiple dimensions specify each dimension name separated by a delimiter\r\n# e.g. `Product & Customer & Account`.\r\n# - To delete subsets from all dimensions then leave pDim parameter blank or supply `ALL`.\r\n# - If any invalid dimensions are specified they will be skipped but the process will continue to \r\n# process the other dimensions.\r\n# - When specifying dimension names wildcards are permitted and all dimensions that match the \r\n# wildcard search string will be searched - for syntax see below pSub parameter.\r\n# - pHier: To specify which hierarchies to delete subsets from use the pHier parameter.\r\n# - To specify default hierachy, leave parameter value empty.\r\n# - To specify all available hierarchies, set parameter value to `*`.\r\n# - When specifying hierarchy names wildcards are permitted and all hierachies that match the wildcard \r\n# search string will be searched - for syntax see below pSub parameter.\r\n# - pSub: To specify which subsets to delete use the pSub parameter.\r\n# - This parameter must be specified, a blank value will cause the process to terminate.\r\n# - To delete a single subset only just specify that subset name e.g. `SmallProducts`.\r\n# - To delete multiple subsets specify each subset name separated by a delimiter\r\n# e.g. `SmallProducts & LargeProducts`.\r\n# - pDelim: The delimiter is used when specifying multiple dimensions and/or multiple subsets.\r\n# - The default delimiter is `&`.\r\n# - Any delimiter can be used by specifying a value for pDelim.\r\n# - Choose a delimiter that won't be used in either the wildcard search strings or dimension names.\r\n# - pMode:\r\n# - When set to value less or equal to `1`: all found subsets will be destroyed.\r\n# - When set to value of `2`: all found subsets will be emptied. \r\n# __Example__:\r\n# - When specifying subset names wildcards are permitted and all subsets that match the wildcard \r\n# search string will be deleted:\r\n# - The wildcard search string follows the same format as wildcards used in Subset Editor.\r\n# - To delete all subsets that __start__ with a specific string use a trailing `*` e.g. `Bedrock*`.\r\n# - To delete all subsets that __end__ in a specific string use a leading `*` e.g. `*Bedrock`.\r\n# - To delete all subsets that __contain__ a specific string use leading and trailing `*`'s e.g. `*Bedrock*`.\r\n# - To delete a single specific subset only don't use `*`'s at all e.g. `Bedrock`.\r\n# - To specify multiple search stings list them all separated by a delimiter e.g. `Bedrock* & *Temp & *Test*`.\r\n# - Similarly you can use `?` as wildcard specifying one character - usage is similar as above specified examples for `*`.\r\n# - Specific subset names and wildcard based names can both be used together e.g. `SalesByProduct;Bedrock*`\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\n\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants\r\n\r\ncThisProcName = GetProcessName();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncTempSubDim = cThisProcName |'_Dim_'| cTimeStamp |'_'| cRandomInt;\r\ncUserName = TM1User();\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pHier:%pHier%, pSub:%pSub%, pMode:%pMode%.';\r\ncAll = 'ALL';\r\ncDimDimensions = '}Dimensions';\r\ncCharAny = '?';\r\ncStringAny = '*';\r\ncCharDimHier = ':';\r\n\r\n### Flag - quit before parsing of parameters\r\nnSkipParsing = 0;\r\nsProcessAction = '';\r\n\r\n### LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters\r\n\r\nnErrors = 0;\r\n\r\nIf( Scan( '*', pDim ) = 0 & Scan( '?', pDim ) = 0 & Scan( pDelim, pDim ) = 0 & Scan( ':', pDim ) > 0 & pHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pHier = SubSt( pDim, Scan( ':', pDim ) + 1, Long( pDim ) );\r\n pDim = SubSt( pDim, 1, Scan( ':', pDim ) - 1 );\r\nEndIf;\r\n\r\n### Validate delimiter\r\nIf( Trim( pDelim ) @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\n### Validate dimension\r\nIf( Trim( pDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No dimension specified';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\nIf( SCAN( cCharAny, pDim ) = 0 & SCAN( cStringAny, pDim ) = 0 & SCAN( pDelim, pDim ) = 0 & SCAN( cCharDimHier, pDim ) > 0 & pHier @= '' );\r\n pHier = SubSt( pDim, SCAN( cCharDimHier, pDim ) + 1, Long( pDim ) );\r\n pDim = SubSt( pDim, 1, SCAN( cCharDimHier, pDim ) - 1 );\r\nEndIf;\r\n\r\n## Validate Hierarchy\r\n\r\nIF(pHier @= 'Leaves' );\r\n nErrors = 1;\r\n sMessage = 'Invalid Hierarchy: ' | pDim |':'|pHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nIf( Trim( pHier ) @<> '' );\r\n sHier = pHier;\r\nEndIf;\r\n\r\n### Validate subset\r\nIf( Trim( pSub ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No subsets specified';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### Destroy subset if exactly specified in parameters - important for recursive calls\r\nIf ( SCAN( cCharAny, pDim ) = 0 & SCAN( cStringAny, pDim ) = 0 & SCAN( pDelim, pDim ) = 0 &\r\n SCAN( cCharAny, pHier ) = 0 & SCAN( cStringAny, pHier ) = 0 & SCAN( pDelim, pHier ) = 0 &\r\n SCAN( cCharAny, pSub ) = 0 & SCAN( cStringAny, pSub ) = 0 & SCAN( pDelim, pSub ) = 0 );\r\n If ( DimensionExists( pDim ) = 0 );\r\n nErrors = 1;\r\n sMessage = Expand( 'Dimension %pDim% doesn''t exist.' );\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n EndIf;\r\n If ( pHier @<> '' & HierarchyExists( pDim, pHier ) = 0 );\r\n nErrors = 1;\r\n sMessage = Expand( 'Hierarchy %pHier% doesn''t exist in dimension %pDim%.' );\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n EndIf;\r\n If ( HierarchySubsetExists( pDim, pHier, pSub ) = 0 );\r\n nErrors = 1;\r\n sMessage = Expand( 'Subset %pSub% doesn''t exist in hierarchy %pHier% of dimension %pDim%.' );\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n EndIf;\r\n If ( pHier @= '' );\r\n pHier = pDim;\r\n EndIf;\r\n If ( pMode <= 1 );\r\n HierarchySubsetDestroy( pDim, pHier, pSub );\r\n sProcessAction = Expand( 'Destroyed subset %pSub% on dimension %pDim% in hierarchy %pHier%.' );\r\n ElseIf ( pMode = 2 );\r\n HierarchySubsetDeleteAllElements( pDim, pHier, pSub );\r\n sProcessAction = Expand( 'Deleted all elements from subset %pSub% on dimension %pDim% in hierarchy %pHier%.' );\r\n EndIf;\r\n ### We don't need to parse any parameters as this was exact match, so we will finish processing\r\n nSkipParsing = 1;\r\nEndIf;\r\n\r\n### Need to process parameters before cleaning\r\nIf ( nSkipParsing = 0 );\r\n \r\n ### Validate all dimension case\r\n If( Trim( pDim ) @= '*' );\r\n pDim = cAll;\r\n EndIf;\r\n \r\n ### Handle All dimensions or a dimension list\r\n ### We will exclude hierarchies in this step and will filter them in connection with subsets in later steps\r\n If ( TRIM( pDim ) @= cAll );\r\n sMDX = Expand( '{FILTER(TM1SUBSETALL([%cDimDimensions%]), INSTR([%cDimDimensions%].CurrentMember.Name, '':'' ) = 0 )}' );\r\n Else;\r\n sDimTokenizer = TRIM( pDim );\r\n sMDX = '';\r\n ### Loop and tokenize dimension list\r\n While ( sDimTokenizer @<> '' );\r\n nPos = SCAN( pDelim, sDimTokenizer );\r\n If ( nPos = 0 );\r\n nPos = LONG( sDimTokenizer ) + 1;\r\n EndIf;\r\n sSearchDim = TRIM( SUBST( sDimTokenizer, 1, nPos - 1 ) );\r\n If( sMDX @= '' );\r\n sMDX = Expand( '{TM1FILTERBYPATTERN({FILTER(TM1SUBSETALL([%cDimDimensions%]), INSTR([%cDimDimensions%].CurrentMember.Name, '':'' ) = 0 )}, \"%sSearchDim%\")}' );\r\n Else;\r\n sMDX = Expand( '%sMDX% + {TM1FILTERBYPATTERN({FILTER(TM1SUBSETALL([%cDimDimensions%]), INSTR([%cDimDimensions%].CurrentMember.Name, '':'' ) = 0 )}, \"%sSearchDim%\")}' );\r\n EndIf;\r\n ### Consume dimension and delimiter\r\n sDimTokenizer = TRIM( DELET( sDimTokenizer, 1, nPos + LONG( pDelim ) - 1 ) );\r\n End;\r\n sMDX = Expand( '{%sMDX%}' );\r\n EndIf;\r\n \r\n ### Create dimensions subset\r\n If ( SubsetExists( cDimDimensions, cTempSub ) = 1 );\r\n SubsetMDXSet( cDimDimensions, cTempSub, sMDX );\r\n Else;\r\n SubsetCreatebyMDX( cTempSub, sMDX, cDimDimensions, 1 );\r\n EndIf;\r\n nMaxDim = SubsetGetSize( cDimDimensions, cTempSub );\r\n \r\n ### Loop through dimensions\r\n nCurDim = 1;\r\n While ( nCurDim <= nMaxDim );\r\n sCurDim = SubsetGetElementName( cDimDimensions, cTempSub, nCurDim );\r\n sCurSubDim = Expand( '}Subsets_%sCurDim%' );\r\n ### We will lookup subsets in }Subsets_ dimension of current dim\r\n If ( DimensionExists( sCurSubDim ) <> 0 );\r\n If ( pHier @= '' );\r\n sHier = sCurDim;\r\n Else;\r\n sHier = pHier;\r\n EndIf;\r\n sHierTokenizer = TRIM( sHier );\r\n sMDX = '';\r\n ### Loop and tokenize hierarchies list\r\n While ( sHierTokenizer @<> '' );\r\n nPos = SCAN( pDelim, sHierTokenizer );\r\n If ( nPos = 0 );\r\n nPos = LONG( sHierTokenizer ) + 1;\r\n EndIf;\r\n sSearchHier = TRIM( SUBST( sHierTokenizer, 1, nPos - 1 ) );\r\n sSubTokenizer = TRIM( pSub );\r\n ### Loop and tokenize subset list\r\n While ( sSubTokenizer @<> '' );\r\n nPos1 = SCAN( pDelim, sSubTokenizer );\r\n If ( nPos1 = 0 );\r\n nPos1 = LONG( sSubTokenizer ) + 1;\r\n EndIf;\r\n sSearchSubset = TRIM( SUBST( sSubTokenizer, 1, nPos1 - 1 ) );\r\n If ( sSearchHier @<> '*' );\r\n If ( sSearchHier @= sCurDim );\r\n sSearchMDX = sSearchSubset;\r\n Else;\r\n sSearchMDX = Expand( '%sSearchHier%:%sSearchSubset%' );\r\n EndIf;\r\n If( sMDX @= '' );\r\n sMDX = Expand( '{TM1FILTERBYPATTERN(TM1SUBSETALL( [%sCurSubDim%] ), \"%sSearchMDX%\")}' );\r\n Else;\r\n sMDX = Expand( '%sMDX% + {TM1FILTERBYPATTERN(TM1SUBSETALL( [%sCurSubDim%] ), \"%sSearchMDX%\")}' );\r\n EndIf;\r\n Else;\r\n # We need to handle special case of * specified as hierarchy filter - this is interpreted as ALL hierarchies - otherwise we would be skipping default hierarchy\r\n sSearchMDX1 = Expand( '%sSearchHier%:%sSearchSubset%' );\r\n sSearchMDX2 = Expand( '%sSearchSubset%' );\r\n If( sMDX @= '' );\r\n sMDX = Expand( '{TM1FILTERBYPATTERN(TM1SUBSETALL( [%sCurSubDim%] ), \"%sSearchMDX1%\")} + {TM1FILTERBYPATTERN(TM1SUBSETALL( [%sCurSubDim%] ), \"%sSearchMDX2%\")}' );\r\n Else;\r\n sMDX = Expand( '%sMDX% + {TM1FILTERBYPATTERN(TM1SUBSETALL( [%sCurSubDim%] ), \"%sSearchMDX1%\")} + {TM1FILTERBYPATTERN(TM1SUBSETALL( [%sCurSubDim%] ), \"%sSearchMDX2%\")}' );\r\n EndIf;\r\n EndIf;\r\n ### Consume subset and delimiter\r\n sSubTokenizer = TRIM( DELET( sSubTokenizer, 1, nPos1 + LONG( pDelim ) - 1 ) );\r\n End;\r\n ### Consume hierarchy and delimiter\r\n sHierTokenizer = TRIM( DELET( sHierTokenizer, 1, nPos + LONG( pDelim )- 1 ) );\r\n End;\r\n ### Query the hierarchies/subsets\r\n If ( SubsetExists( sCurSubDim, cTempSub ) = 1 );\r\n SubsetMDXSet( sCurSubDim, cTempSub, sMDX );\r\n Else;\r\n SubsetCreatebyMDX( cTempSub, sMDX, sCurSubDim, 1 );\r\n EndIf;\r\n nMaxSubs = SubsetGetSize( sCurSubDim, cTempSub );\r\n nCurSubs = nMaxSubs;\r\n While ( nCurSubs >= 1 );\r\n sCurSubs = SubsetGetElementName( sCurSubDim, cTempSub, nCurSubs );\r\n nColPos = SCAN( ':', sCurSubs );\r\n If ( nColPos = 0 );\r\n sHierarchy = sCurDim;\r\n sSubset = sCurSubs;\r\n Else;\r\n sHierarchy = SUBST( sCurSubs, 1, nColPos - 1 );\r\n sSubset = SUBST( sCurSubs, nColPos + 1, LONG(sCurSubs) - nColPos ); \r\n EndIf;\r\n If ( pMode <= 1 );\r\n ### Recursive call to consume process error in this process and not to broadcast it to the parent caller process\r\n ExecuteProcess( cThisProcName,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pLogOutput', pLogOutput,\r\n 'pDim', sCurDim,\r\n 'pHier', sHierarchy,\r\n 'pSub', sSubset,\r\n 'pDelim', pDelim,\r\n 'pMode', pMode\r\n );\r\n ElseIf ( pMode = 2 );\r\n ### No need for a recursive call as we suppose this call is not going to raise a process error - this will save processing time significantly\r\n HierarchySubsetDeleteAllElements( pDim, pHier, pSub );\r\n sProcessAction = Expand( 'Deleted all elements from subset %pSub% on dimension %pDim% in hierarchy %pHier%.' );\r\n EndIf; \r\n nCurSubs = nCurSubs - 1;\r\n End;\r\n EndIf;\r\n nCurDim = nCurDim + 1;\r\n End;\r\nEndIf;\r\n\r\n### End Prolog ###", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.sub.delete', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pDim', '', 'pHier', '', 'pSub', '',\r\n \t'pDelim', '&', 'pMode', 0\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process deletes public subsets from selected dimension and hierarchies. Dimensions, hierarchies\r\n# and subsets can be specified as a delimited list. Wildcards are accepted as `*` and `?` characters.\r\n\r\n# Note:\r\n# - pDim: To specify which dimensions to delete subsets from use the pDim parameter.\r\n# - To delete subsets from a single dimension only just specify that dimension name e.g. `Product`.\r\n# - To delete subsets from multiple dimensions specify each dimension name separated by a delimiter\r\n# e.g. `Product & Customer & Account`.\r\n# - To delete subsets from all dimensions then leave pDim parameter blank or supply `ALL`.\r\n# - If any invalid dimensions are specified they will be skipped but the process will continue to \r\n# process the other dimensions.\r\n# - When specifying dimension names wildcards are permitted and all dimensions that match the \r\n# wildcard search string will be searched - for syntax see below pSub parameter.\r\n# - pHier: To specify which hierarchies to delete subsets from use the pHier parameter.\r\n# - To specify default hierachy, leave parameter value empty.\r\n# - To specify all available hierarchies, set parameter value to `*`.\r\n# - When specifying hierarchy names wildcards are permitted and all hierachies that match the wildcard \r\n# search string will be searched - for syntax see below pSub parameter.\r\n# - pSub: To specify which subsets to delete use the pSub parameter.\r\n# - This parameter must be specified, a blank value will cause the process to terminate.\r\n# - To delete a single subset only just specify that subset name e.g. `SmallProducts`.\r\n# - To delete multiple subsets specify each subset name separated by a delimiter\r\n# e.g. `SmallProducts & LargeProducts`.\r\n# - pDelim: The delimiter is used when specifying multiple dimensions and/or multiple subsets.\r\n# - The default delimiter is `&`.\r\n# - Any delimiter can be used by specifying a value for pDelim.\r\n# - Choose a delimiter that won't be used in either the wildcard search strings or dimension names.\r\n# - pMode:\r\n# - When set to value less or equal to `1`: all found subsets will be destroyed.\r\n# - When set to value of `2`: all found subsets will be emptied. \r\n# __Example__:\r\n# - When specifying subset names wildcards are permitted and all subsets that match the wildcard \r\n# search string will be deleted:\r\n# - The wildcard search string follows the same format as wildcards used in Subset Editor.\r\n# - To delete all subsets that __start__ with a specific string use a trailing `*` e.g. `Bedrock*`.\r\n# - To delete all subsets that __end__ in a specific string use a leading `*` e.g. `*Bedrock`.\r\n# - To delete all subsets that __contain__ a specific string use leading and trailing `*`'s e.g. `*Bedrock*`.\r\n# - To delete a single specific subset only don't use `*`'s at all e.g. `Bedrock`.\r\n# - To specify multiple search stings list them all separated by a delimiter e.g. `Bedrock* & *Temp & *Test*`.\r\n# - Similarly you can use `?` as wildcard specifying one character - usage is similar as above specified examples for `*`.\r\n# - Specific subset names and wildcard based names can both be used together e.g. `SalesByProduct;Bedrock*`\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\n\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants\r\n\r\ncThisProcName = GetProcessName();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncTempSubDim = cThisProcName |'_Dim_'| cTimeStamp |'_'| cRandomInt;\r\ncUserName = TM1User();\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pHier:%pHier%, pSub:%pSub%, pMode:%pMode%.';\r\ncAll = 'ALL';\r\ncDimDimensions = '}Dimensions';\r\ncCharAny = '?';\r\ncStringAny = '*';\r\ncCharDimHier = ':';\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pDelim\": \"&\",\r\n \"pDim\": null,\r\n \"pHier\": \"\",\r\n \"pSub\": null,\r\n \"pLogOutput\": 0,\r\n \"pMode\": 0,\r\n \"pStrictErrorHandling\": 0\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pDelim\": '|StringToJson ( pDelim )|',\r\n \"pDim\": '|StringToJson ( pDim )|',\r\n \"pHier\": '|StringToJson ( pHier )|',\r\n \"pSub\": '|StringToJson ( pSub )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pMode\": '|NumberToString( pMode )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npDelim = JsonToString( JsonGet( pJson, 'pDelim' ) );\r\npDim = JsonToString( JsonGet( pJson, 'pDim' ) );\r\npHier = JsonToString( JsonGet( pJson, 'pHier' ) );\r\npSub = JsonToString( JsonGet( pJson, 'pSub' ) );\r\n# Numeric Parameters\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npMode = StringToNumber( JsonToString( JsonGet( pJson, 'pMode' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n### Flag - quit before parsing of parameters\r\nnSkipParsing = 0;\r\nsProcessAction = '';\r\n\r\n### LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters\r\n\r\nnErrors = 0;\r\n\r\nIf( Scan( '*', pDim ) = 0 & Scan( '?', pDim ) = 0 & Scan( pDelim, pDim ) = 0 & Scan( ':', pDim ) > 0 & pHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pHier = SubSt( pDim, Scan( ':', pDim ) + 1, Long( pDim ) );\r\n pDim = SubSt( pDim, 1, Scan( ':', pDim ) - 1 );\r\nEndIf;\r\n\r\n### Validate delimiter\r\nIf( Trim( pDelim ) @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\n### Validate dimension\r\nIf( Trim( pDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No dimension specified';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\nIf( SCAN( cCharAny, pDim ) = 0 & SCAN( cStringAny, pDim ) = 0 & SCAN( pDelim, pDim ) = 0 & SCAN( cCharDimHier, pDim ) > 0 & pHier @= '' );\r\n pHier = SubSt( pDim, SCAN( cCharDimHier, pDim ) + 1, Long( pDim ) );\r\n pDim = SubSt( pDim, 1, SCAN( cCharDimHier, pDim ) - 1 );\r\nEndIf;\r\n\r\n## Validate Hierarchy\r\n\r\nIF(pHier @= 'Leaves' );\r\n nErrors = 1;\r\n sMessage = 'Invalid Hierarchy: ' | pDim |':'|pHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nIf( Trim( pHier ) @<> '' );\r\n sHier = pHier;\r\nEndIf;\r\n\r\n### Validate subset\r\nIf( Trim( pSub ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No subsets specified';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### Destroy subset if exactly specified in parameters - important for recursive calls\r\nIf ( SCAN( cCharAny, pDim ) = 0 & SCAN( cStringAny, pDim ) = 0 & SCAN( pDelim, pDim ) = 0 &\r\n SCAN( cCharAny, pHier ) = 0 & SCAN( cStringAny, pHier ) = 0 & SCAN( pDelim, pHier ) = 0 &\r\n SCAN( cCharAny, pSub ) = 0 & SCAN( cStringAny, pSub ) = 0 & SCAN( pDelim, pSub ) = 0 );\r\n If ( DimensionExists( pDim ) = 0 );\r\n nErrors = 1;\r\n sMessage = Expand( 'Dimension %pDim% doesn''t exist.' );\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n EndIf;\r\n If ( pHier @<> '' & HierarchyExists( pDim, pHier ) = 0 );\r\n nErrors = 1;\r\n sMessage = Expand( 'Hierarchy %pHier% doesn''t exist in dimension %pDim%.' );\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n EndIf;\r\n If ( HierarchySubsetExists( pDim, pHier, pSub ) = 0 );\r\n nErrors = 1;\r\n sMessage = Expand( 'Subset %pSub% doesn''t exist in hierarchy %pHier% of dimension %pDim%.' );\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\n EndIf;\r\n If ( pHier @= '' );\r\n pHier = pDim;\r\n EndIf;\r\n If ( pMode <= 1 );\r\n HierarchySubsetDestroy( pDim, pHier, pSub );\r\n sProcessAction = Expand( 'Destroyed subset %pSub% on dimension %pDim% in hierarchy %pHier%.' );\r\n ElseIf ( pMode = 2 );\r\n HierarchySubsetDeleteAllElements( pDim, pHier, pSub );\r\n sProcessAction = Expand( 'Deleted all elements from subset %pSub% on dimension %pDim% in hierarchy %pHier%.' );\r\n EndIf;\r\n ### We don't need to parse any parameters as this was exact match, so we will finish processing\r\n nSkipParsing = 1;\r\nEndIf;\r\n\r\n### Need to process parameters before cleaning\r\nIf ( nSkipParsing = 0 );\r\n \r\n ### Validate all dimension case\r\n If( Trim( pDim ) @= '*' );\r\n pDim = cAll;\r\n EndIf;\r\n \r\n ### Handle All dimensions or a dimension list\r\n ### We will exclude hierarchies in this step and will filter them in connection with subsets in later steps\r\n If ( TRIM( pDim ) @= cAll );\r\n sMDX = Expand( '{FILTER(TM1SUBSETALL([%cDimDimensions%]), INSTR([%cDimDimensions%].CurrentMember.Name, '':'' ) = 0 )}' );\r\n Else;\r\n sDimTokenizer = TRIM( pDim );\r\n sMDX = '';\r\n ### Loop and tokenize dimension list\r\n While ( sDimTokenizer @<> '' );\r\n nPos = SCAN( pDelim, sDimTokenizer );\r\n If ( nPos = 0 );\r\n nPos = LONG( sDimTokenizer ) + 1;\r\n EndIf;\r\n sSearchDim = TRIM( SUBST( sDimTokenizer, 1, nPos - 1 ) );\r\n If( sMDX @= '' );\r\n sMDX = Expand( '{TM1FILTERBYPATTERN({FILTER(TM1SUBSETALL([%cDimDimensions%]), INSTR([%cDimDimensions%].CurrentMember.Name, '':'' ) = 0 )}, \"%sSearchDim%\")}' );\r\n Else;\r\n sMDX = Expand( '%sMDX% + {TM1FILTERBYPATTERN({FILTER(TM1SUBSETALL([%cDimDimensions%]), INSTR([%cDimDimensions%].CurrentMember.Name, '':'' ) = 0 )}, \"%sSearchDim%\")}' );\r\n EndIf;\r\n ### Consume dimension and delimiter\r\n sDimTokenizer = TRIM( DELET( sDimTokenizer, 1, nPos + LONG( pDelim ) - 1 ) );\r\n End;\r\n sMDX = Expand( '{%sMDX%}' );\r\n EndIf;\r\n \r\n ### Create dimensions subset\r\n If ( SubsetExists( cDimDimensions, cTempSub ) = 1 );\r\n SubsetMDXSet( cDimDimensions, cTempSub, sMDX );\r\n Else;\r\n SubsetCreatebyMDX( cTempSub, sMDX, cDimDimensions, 1 );\r\n EndIf;\r\n nMaxDim = SubsetGetSize( cDimDimensions, cTempSub );\r\n \r\n ### Loop through dimensions\r\n nCurDim = 1;\r\n While ( nCurDim <= nMaxDim );\r\n sCurDim = SubsetGetElementName( cDimDimensions, cTempSub, nCurDim );\r\n sCurSubDim = Expand( '}Subsets_%sCurDim%' );\r\n ### We will lookup subsets in }Subsets_ dimension of current dim\r\n If ( DimensionExists( sCurSubDim ) <> 0 );\r\n If ( pHier @= '' );\r\n sHier = sCurDim;\r\n Else;\r\n sHier = pHier;\r\n EndIf;\r\n sHierTokenizer = TRIM( sHier );\r\n sMDX = '';\r\n ### Loop and tokenize hierarchies list\r\n While ( sHierTokenizer @<> '' );\r\n nPos = SCAN( pDelim, sHierTokenizer );\r\n If ( nPos = 0 );\r\n nPos = LONG( sHierTokenizer ) + 1;\r\n EndIf;\r\n sSearchHier = TRIM( SUBST( sHierTokenizer, 1, nPos - 1 ) );\r\n sSubTokenizer = TRIM( pSub );\r\n ### Loop and tokenize subset list\r\n While ( sSubTokenizer @<> '' );\r\n nPos1 = SCAN( pDelim, sSubTokenizer );\r\n If ( nPos1 = 0 );\r\n nPos1 = LONG( sSubTokenizer ) + 1;\r\n EndIf;\r\n sSearchSubset = TRIM( SUBST( sSubTokenizer, 1, nPos1 - 1 ) );\r\n If ( sSearchHier @<> '*' );\r\n If ( sSearchHier @= sCurDim );\r\n sSearchMDX = sSearchSubset;\r\n Else;\r\n sSearchMDX = Expand( '%sSearchHier%:%sSearchSubset%' );\r\n EndIf;\r\n If( sMDX @= '' );\r\n sMDX = Expand( '{TM1FILTERBYPATTERN(TM1SUBSETALL( [%sCurSubDim%] ), \"%sSearchMDX%\")}' );\r\n Else;\r\n sMDX = Expand( '%sMDX% + {TM1FILTERBYPATTERN(TM1SUBSETALL( [%sCurSubDim%] ), \"%sSearchMDX%\")}' );\r\n EndIf;\r\n Else;\r\n # We need to handle special case of * specified as hierarchy filter - this is interpreted as ALL hierarchies - otherwise we would be skipping default hierarchy\r\n sSearchMDX1 = Expand( '%sSearchHier%:%sSearchSubset%' );\r\n sSearchMDX2 = Expand( '%sSearchSubset%' );\r\n If( sMDX @= '' );\r\n sMDX = Expand( '{TM1FILTERBYPATTERN(TM1SUBSETALL( [%sCurSubDim%] ), \"%sSearchMDX1%\")} + {TM1FILTERBYPATTERN(TM1SUBSETALL( [%sCurSubDim%] ), \"%sSearchMDX2%\")}' );\r\n Else;\r\n sMDX = Expand( '%sMDX% + {TM1FILTERBYPATTERN(TM1SUBSETALL( [%sCurSubDim%] ), \"%sSearchMDX1%\")} + {TM1FILTERBYPATTERN(TM1SUBSETALL( [%sCurSubDim%] ), \"%sSearchMDX2%\")}' );\r\n EndIf;\r\n EndIf;\r\n ### Consume subset and delimiter\r\n sSubTokenizer = TRIM( DELET( sSubTokenizer, 1, nPos1 + LONG( pDelim ) - 1 ) );\r\n End;\r\n ### Consume hierarchy and delimiter\r\n sHierTokenizer = TRIM( DELET( sHierTokenizer, 1, nPos + LONG( pDelim )- 1 ) );\r\n End;\r\n ### Query the hierarchies/subsets\r\n If ( SubsetExists( sCurSubDim, cTempSub ) = 1 );\r\n SubsetMDXSet( sCurSubDim, cTempSub, sMDX );\r\n Else;\r\n SubsetCreatebyMDX( cTempSub, sMDX, sCurSubDim, 1 );\r\n EndIf;\r\n nMaxSubs = SubsetGetSize( sCurSubDim, cTempSub );\r\n nCurSubs = nMaxSubs;\r\n While ( nCurSubs >= 1 );\r\n sCurSubs = SubsetGetElementName( sCurSubDim, cTempSub, nCurSubs );\r\n nColPos = SCAN( ':', sCurSubs );\r\n If ( nColPos = 0 );\r\n sHierarchy = sCurDim;\r\n sSubset = sCurSubs;\r\n Else;\r\n sHierarchy = SUBST( sCurSubs, 1, nColPos - 1 );\r\n sSubset = SUBST( sCurSubs, nColPos + 1, LONG(sCurSubs) - nColPos ); \r\n EndIf;\r\n If ( pMode <= 1 );\r\n ### Recursive call to consume process error in this process and not to broadcast it to the parent caller process\r\n ExecuteProcess( cThisProcName,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pLogOutput', pLogOutput,\r\n 'pDim', sCurDim,\r\n 'pHier', sHierarchy,\r\n 'pSub', sSubset,\r\n 'pDelim', pDelim,\r\n 'pMode', pMode\r\n );\r\n ElseIf ( pMode = 2 );\r\n ### No need for a recursive call as we suppose this call is not going to raise a process error - this will save processing time significantly\r\n HierarchySubsetDeleteAllElements( pDim, pHier, pSub );\r\n sProcessAction = Expand( 'Deleted all elements from subset %pSub% on dimension %pDim% in hierarchy %pHier%.' );\r\n EndIf; \r\n nCurSubs = nCurSubs - 1;\r\n End;\r\n EndIf;\r\n nCurDim = nCurDim + 1;\r\n End;\r\nEndIf;\r\n\r\n### End Prolog ###", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully deleted subset %pSub% from dimension %pDim%.' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n### End Epilog ###", @@ -10,47 +10,53 @@ "Type": "None" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pDim", - "Prompt": "OPTIONAL: Dimension name (if * then ALL dimensions )", + "Prompt": "REQUIRED: Delimited list of dimensions", "Value": "", "Type": "String" }, { "Name": "pHier", - "Prompt": "OPTIONAL: Hierarchy name (if * then ALL hierarchies for the specified dimensions)", + "Prompt": "OPTIONAL: Hierarchy name (Default = pDim)", "Value": "", "Type": "String" }, { "Name": "pSub", - "Prompt": "REQUIRED: Filter on subsets (delimiter separated list of subset names, accepts wildcards)", - "Value": "}Bedrock*", + "Prompt": "REQUIRED: Subset name", + "Value": "", "Type": "String" }, { "Name": "pDelim", - "Prompt": "OPTIONAL: Delimiter character for subset list (required if pSub parameter is used)", + "Prompt": "OPTIONAL: Delimiter for list parameters (Default = '&')", "Value": "&", "Type": "String" }, { "Name": "pMode", - "Prompt": "OPTIONAL: <=1 destroy subset, 2 delete all elements", + "Prompt": "OPTIONAL: Delete subset and elements (0 or 1 = Delete subset, 2 = Delete all elements. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [], diff --git a/bedrock_processes_json/}bedrock.hier.sub.exclude.json b/bedrock_processes_json/}bedrock.hier.sub.exclude.json index c2a00da..c175cb7 100644 --- a/bedrock_processes_json/}bedrock.hier.sub.exclude.json +++ b/bedrock_processes_json/}bedrock.hier.sub.exclude.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.hier.sub.exclude", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.sub.exclude', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pDim', '', 'pHier', '', 'pSub', '',\r\n \t'pExclusions', '', 'pDelim', '&', 'pTemp', 1\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will remove specified elements from a subset in a Hierarchy of target Dimension.\r\n# Wildcard characters `*`and `?` are accepted in list of elements to be excluded.\r\n\r\n# Note:\r\n# - If a leaf level element is specified, it will be removed on its own.\r\n# - If a consolidated element is specified it will be removed as well as its descendants.\r\n\r\n# Caution: Target hierarchy cannot be `Leaves`.\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pHier:%pHier%, pSub:%pSub%, pExclusions:%pExclusions%, pDelim:%pDelim%, pTemp:%pTemp%.'; \r\ncAttributeDim = '}ElementAttributes_' | pDim;\r\n\r\n## LogOutput parameters\r\nIF ( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n\r\n### Validate Parameters ###\r\n\r\nnErrors = 0;\r\n\r\nIf( Scan( ':', pDim ) > 0 & pHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pHier = SubSt( pDim, Scan( ':', pDim ) + 1, Long( pDim ) );\r\n pDim = SubSt( pDim, 1, Scan( ':', pDim ) - 1 );\r\nEndIf;\r\n\r\n# Validate dimension\r\nIf( Trim( pDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No dimension specified';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\nIf( DimensionExists( pDim ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid dimension: ' | pDim;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n## Validate Hierarchy\r\n\r\nIF(pHier @= 'Leaves' );\r\n nErrors = 1;\r\n sMessage = 'Invalid Hierarchy: ' | pDim |':'|pHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nIf( Trim( pHier ) @= '' );\r\n sHier = pDim;\r\nElse;\r\n sHier = pHier;\r\nEndIf;\r\n\r\nIf( HierarchyExists( pDim, sHier ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'The Hierachy ' | sHier | ' does not exists.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate subset\r\nIf( Trim( pSub ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No subset specified';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\nIf( HierarchySubsetExists( pDim,sHier, pSub ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid subset: ' | pSub | ' in dimension:Hierarchy ' | pDim |':' | sHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate Elements\r\nIf( Trim( pExclusions ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No Elements specified';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate delimiter\r\nIf( pExclusions @<> '' & pDelim @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\n## Validate pTemp\r\nIF( pTemp <> 0 & pTemp <> 1 );\r\n nErrors = 1;\r\n sMessage = 'Wrong parameter pTemp value (only 0 or 1 accepted).';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### Process Elements ###\r\nIf(nErrors = 0);\r\n nDelimIndex = 1;\r\n sExclusions = pExclusions;\r\n\r\n While( nDelimIndex <> 0 & Long( sExclusions ) > 0 );\r\n\r\n nDelimIndex = Scan( pDelim, sExclusions );\r\n If( nDelimIndex <> 0 );\r\n sExclusion = Trim( SubSt( sExclusions, 1, nDelimIndex - 1 ) );\r\n sExclusions = Trim( SubSt( sExclusions, nDelimIndex + Long( pDelim ), Long( sExclusions ) ) );\r\n Else;\r\n sExclusion = Trim( sExclusions );\r\n EndIf;\r\n If(Scan('*',sExclusion) = 0 & Scan('?',sExclusion) = 0);\r\n # Check that Element is present in the dimension\r\n If( ElementIndex ( pDim, sHier, sExclusion ) <> 0 );\r\n sExclusion = HierarchyElementPrincipalName( pDim, sHier, sExclusion );\r\n # Work through subset and remove Element\r\n nSubsetIndex = 1;\r\n nSubsetSize = HierarchySubsetGetSize( pDim, sHier, pSub );\r\n While( nSubsetIndex <= nSubsetSize );\r\n sTemp = HierarchySubsetElementGetIndex (pDim, sHier, pSub, '', nSubsetIndex);\r\n sElement = HierarchySubsetGetElementName( pDim, sHier, pSub, nSubsetIndex );\r\n # If Element is found or a descendant of the Element is found the remove from subset\r\n If( sElement @= sExclusion % ElementIsAncestor( pDim, sHier, sExclusion, sElement ) = 1 );\r\n sTemp = HierarchySubsetElementGetIndex (pDim, sHier, pSub, '', nSubsetIndex);\r\n HierarchySubsetElementDelete ( pDim, sHier, pSub, nSubsetIndex );\r\n nSubsetSize = nSubsetSize - 1;\r\n Else;\r\n nSubsetIndex = nSubsetIndex + 1;\r\n EndIf;\r\n End;\r\n \r\n EndIf;\r\n Else;\r\n # Wildcard search string\r\n sExclusion = '\"'|sExclusion|'\"';\r\n stempSub = cThisProcName| cRandomInt;\r\n sProc = '}bedrock.hier.sub.create.bymdx';\r\n sMdx = '{TM1FILTERBYPATTERN( {TM1SUBSETALL([ ' |pDim|'].['|sHier |' ])},'| sExclusion| ')}';\r\n ExecuteProcess(sProc,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pDim',pDim,\r\n \t'pHier',sHier,\r\n \t'pSub',stempSub,\r\n \t'pMDXExpr',sMdx,\r\n \t'pConvertToStatic',1,\r\n \t'pTemp', pTemp);\r\n nSubsetindex = 1;\r\n nSubsetSize = HierarchySubsetGetSize(pDim, sHier, stempSub);\r\n While (nSubsetindex <= nSubsetSize);\r\n sTemp = HierarchySubsetElementGetIndex (pDim, sHier, stempSub, '', nSubsetIndex);\r\n sElement = HierarchySubsetGetElementName(pDim, sHier, stempSub, nSubsetindex);\r\n HierarchySubsetElementDelete( pDim, sHier,stempSub,nSubsetindex );\r\n nSubsetSize = nSubsetSize -1;\r\n ## Delete Element from main subset\r\n If(HierarchySubsetElementExists(pDim, sHier, pSub, sElement)>0);\r\n nSearchIndex = 1;\r\n nSearchSize = HierarchySubsetGetSize(pDim, sHier, pSub);\r\n While( nSearchIndex <= nSearchSize );\r\n sSearchElement = HierarchySubsetGetElementName( pDim, sHier, pSub, nSearchIndex );\r\n # If Element is found or a descendant of the Element is found the remove from subset\r\n If( sElement @= sSearchElement % ElementIsAncestor( pDim, sHier, sElement, sSearchElement ) = 1 );\r\n sTemp = HierarchySubsetElementGetIndex (pDim, sHier, pSub, '', nSearchIndex);\r\n HierarchySubsetElementDelete ( pDim, sHier, pSub, nSearchIndex );\r\n nSearchSize = 0;\r\n Else;\r\n nSearchIndex = nSearchIndex + 1;\r\n EndIf;\r\n End;\r\n Endif;\r\n ######\r\n End;\r\n HierarchySubsetDestroy(pDim, sHier,stempSub);\r\n EndIf;\r\n\r\n End;\r\n\r\nEndIf;\r\n\r\n\r\n### End Prolog ###", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.sub.exclude', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pDim', '', 'pHier', '', 'pSub', '',\r\n \t'pExclusions', '', 'pDelim', '&', 'pTemp', 1\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will remove specified elements from a subset in a Hierarchy of target Dimension.\r\n# Wildcard characters `*`and `?` are accepted in list of elements to be excluded.\r\n\r\n# Note:\r\n# - If a leaf level element is specified, it will be removed on its own.\r\n# - If a consolidated element is specified it will be removed as well as its descendants.\r\n\r\n# Caution: Target hierarchy cannot be `Leaves`.\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pHier:%pHier%, pSub:%pSub%, pExclusions:%pExclusions%, pDelim:%pDelim%, pTemp:%pTemp%.'; \r\ncAttributeDim = '}ElementAttributes_' | pDim;\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pDelim\": \"&\",\r\n \"pDim\": null,\r\n \"pExclusions\": \"\",\r\n \"pHier\": \"\",\r\n \"pSub\": null,\r\n \"pLogOutput\": 0,\r\n \"pStrictErrorHandling\": 0,\r\n \"pTemp\": 1\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pDelim\": '|StringToJson ( pDelim )|',\r\n \"pDim\": '|StringToJson ( pDim )|',\r\n \"pExclusions\": '|StringToJson ( pExclusions )|',\r\n \"pHier\": '|StringToJson ( pHier )|',\r\n \"pSub\": '|StringToJson ( pSub )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|',\r\n \"pTemp\": '|NumberToString( pTemp )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npDelim = JsonToString( JsonGet( pJson, 'pDelim' ) );\r\npDim = JsonToString( JsonGet( pJson, 'pDim' ) );\r\npExclusions = JsonToString( JsonGet( pJson, 'pExclusions' ) );\r\npHier = JsonToString( JsonGet( pJson, 'pHier' ) );\r\npSub = JsonToString( JsonGet( pJson, 'pSub' ) );\r\n# Numeric Parameters\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\npTemp = StringToNumber( JsonToString( JsonGet( pJson, 'pTemp' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n## LogOutput parameters\r\nIF ( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n\r\n### Validate Parameters ###\r\n\r\nnErrors = 0;\r\n\r\nIf( Scan( ':', pDim ) > 0 & pHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pHier = SubSt( pDim, Scan( ':', pDim ) + 1, Long( pDim ) );\r\n pDim = SubSt( pDim, 1, Scan( ':', pDim ) - 1 );\r\nEndIf;\r\n\r\n# Validate dimension\r\nIf( Trim( pDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No dimension specified';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\nIf( DimensionExists( pDim ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid dimension: ' | pDim;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n## Validate Hierarchy\r\n\r\nIF(pHier @= 'Leaves' );\r\n nErrors = 1;\r\n sMessage = 'Invalid Hierarchy: ' | pDim |':'|pHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nIf( Trim( pHier ) @= '' );\r\n sHier = pDim;\r\nElse;\r\n sHier = pHier;\r\nEndIf;\r\n\r\nIf( HierarchyExists( pDim, sHier ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'The Hierachy ' | sHier | ' does not exists.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate subset\r\nIf( Trim( pSub ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No subset specified';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\nIf( HierarchySubsetExists( pDim,sHier, pSub ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid subset: ' | pSub | ' in dimension:Hierarchy ' | pDim |':' | sHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate Elements\r\nIf( Trim( pExclusions ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No Elements specified';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate delimiter\r\nIf( pExclusions @<> '' & pDelim @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\n## Validate pTemp\r\nIF( pTemp <> 0 & pTemp <> 1 );\r\n nErrors = 1;\r\n sMessage = 'Wrong parameter pTemp value (only 0 or 1 accepted).';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### Process Elements ###\r\nIf(nErrors = 0);\r\n nDelimIndex = 1;\r\n sExclusions = pExclusions;\r\n\r\n While( nDelimIndex <> 0 & Long( sExclusions ) > 0 );\r\n\r\n nDelimIndex = Scan( pDelim, sExclusions );\r\n If( nDelimIndex <> 0 );\r\n sExclusion = Trim( SubSt( sExclusions, 1, nDelimIndex - 1 ) );\r\n sExclusions = Trim( SubSt( sExclusions, nDelimIndex + Long( pDelim ), Long( sExclusions ) ) );\r\n Else;\r\n sExclusion = Trim( sExclusions );\r\n EndIf;\r\n If(Scan('*',sExclusion) = 0 & Scan('?',sExclusion) = 0);\r\n # Check that Element is present in the dimension\r\n If( ElementIndex ( pDim, sHier, sExclusion ) <> 0 );\r\n sExclusion = HierarchyElementPrincipalName( pDim, sHier, sExclusion );\r\n # Work through subset and remove Element\r\n nSubsetIndex = 1;\r\n nSubsetSize = HierarchySubsetGetSize( pDim, sHier, pSub );\r\n While( nSubsetIndex <= nSubsetSize );\r\n sTemp = HierarchySubsetElementGetIndex (pDim, sHier, pSub, '', nSubsetIndex);\r\n sElement = HierarchySubsetGetElementName( pDim, sHier, pSub, nSubsetIndex );\r\n # If Element is found or a descendant of the Element is found the remove from subset\r\n If( sElement @= sExclusion % ElementIsAncestor( pDim, sHier, sExclusion, sElement ) = 1 );\r\n sTemp = HierarchySubsetElementGetIndex (pDim, sHier, pSub, '', nSubsetIndex);\r\n HierarchySubsetElementDelete ( pDim, sHier, pSub, nSubsetIndex );\r\n nSubsetSize = nSubsetSize - 1;\r\n Else;\r\n nSubsetIndex = nSubsetIndex + 1;\r\n EndIf;\r\n End;\r\n \r\n EndIf;\r\n Else;\r\n # Wildcard search string\r\n sExclusion = '\"'|sExclusion|'\"';\r\n stempSub = cThisProcName| cRandomInt;\r\n sProc = '}bedrock.hier.sub.create.bymdx';\r\n sMdx = '{TM1FILTERBYPATTERN( {TM1SUBSETALL([ ' |pDim|'].['|sHier |' ])},'| sExclusion| ')}';\r\n ExecuteProcess(sProc,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pDim',pDim,\r\n \t'pHier',sHier,\r\n \t'pSub',stempSub,\r\n \t'pMDXExpr',sMdx,\r\n \t'pConvertToStatic',1,\r\n \t'pTemp', pTemp);\r\n nSubsetindex = 1;\r\n nSubsetSize = HierarchySubsetGetSize(pDim, sHier, stempSub);\r\n While (nSubsetindex <= nSubsetSize);\r\n sTemp = HierarchySubsetElementGetIndex (pDim, sHier, stempSub, '', nSubsetIndex);\r\n sElement = HierarchySubsetGetElementName(pDim, sHier, stempSub, nSubsetindex);\r\n HierarchySubsetElementDelete( pDim, sHier,stempSub,nSubsetindex );\r\n nSubsetSize = nSubsetSize -1;\r\n ## Delete Element from main subset\r\n If(HierarchySubsetElementExists(pDim, sHier, pSub, sElement)>0);\r\n nSearchIndex = 1;\r\n nSearchSize = HierarchySubsetGetSize(pDim, sHier, pSub);\r\n While( nSearchIndex <= nSearchSize );\r\n sSearchElement = HierarchySubsetGetElementName( pDim, sHier, pSub, nSearchIndex );\r\n # If Element is found or a descendant of the Element is found the remove from subset\r\n If( sElement @= sSearchElement % ElementIsAncestor( pDim, sHier, sElement, sSearchElement ) = 1 );\r\n sTemp = HierarchySubsetElementGetIndex (pDim, sHier, pSub, '', nSearchIndex);\r\n HierarchySubsetElementDelete ( pDim, sHier, pSub, nSearchIndex );\r\n nSearchSize = 0;\r\n Else;\r\n nSearchIndex = nSearchIndex + 1;\r\n EndIf;\r\n End;\r\n Endif;\r\n ######\r\n End;\r\n HierarchySubsetDestroy(pDim, sHier,stempSub);\r\n EndIf;\r\n\r\n End;\r\n\r\nEndIf;\r\n\r\n\r\n### End Prolog ###", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully excluded elements from subset %pSub% from dimension %pDim%.' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n### End Epilog ###", @@ -10,27 +10,15 @@ "Type": "None" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pDim", - "Prompt": "REQUIRED: Dimension name", + "Prompt": "REQUIRED: Delimited list of dimensions", "Value": "", "Type": "String" }, { "Name": "pHier", - "Prompt": "OPTIONAL: Hierarchy name (default if blank = same named hierarchy)", + "Prompt": "OPTIONAL: Hierarchy name (Default = pDim)", "Value": "", "Type": "String" }, @@ -42,21 +30,39 @@ }, { "Name": "pExclusions", - "Prompt": "OPTIONAL: Elements to Exclude From Subset (Separated by Delimiter, Accepts Wild card)", + "Prompt": "OPTIONAL: Delimited list of elements to exclude", "Value": "", "Type": "String" }, { "Name": "pDelim", - "Prompt": "OPTIONAL: Delimiter character", + "Prompt": "OPTIONAL: Delimiter for list parameters (Default = '&')", "Value": "&", "Type": "String" }, { "Name": "pTemp", - "Prompt": "OPTIONAL: Use temporary objects? (Boolean 1=True)", + "Prompt": "OPTIONAL: Delete/create temporary objects (0 = Do not delete, 1 = Delete, 2 = if view and subsets are created, keep only subsets)", "Value": 1, "Type": "Numeric" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [], diff --git a/bedrock_processes_json/}bedrock.hier.sub.exporttofile.json b/bedrock_processes_json/}bedrock.hier.sub.exporttofile.json index 1a5bc81..30301b0 100644 --- a/bedrock_processes_json/}bedrock.hier.sub.exporttofile.json +++ b/bedrock_processes_json/}bedrock.hier.sub.exporttofile.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.hier.sub.exporttofile", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.sub.exporttofile', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pDim', '', 'pHier', '', 'pSub', '',\r\n \t'pTgtDir', '', 'pTgtFile', '',\r\n \t'pTitleRecord', 1, 'pDelim', ',', 'pQuote', '\"'\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will Export a subset in a Hierarchy of a Dimension to a file. Custom record delimiter\r\n# (specified by a character or its ASCII code) can be used.\r\n# __Format of the file:__ \r\n# - 1st line: File metadata contains summary information about the dimension, hierarchy, subset\r\n# name, number of elements and date/time when file was generated.\r\n# - 2nd line and forth: Elements export data.\r\n\r\n# Note:\r\n# Valid dimension name (pDim), subset name (pSub), inclusion of header (pTitleRecord)\r\n# are mandatory otherwise the process will abort. Target folder (pTgtDir) must exist.\r\n# If needed, custom delimiter might be used by specifying parameter pDelim value as either exactly one\r\n# character or as a 3-digit (decimal) ASCII code. For example to use TAB as a delimiter, use 009.\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pHier:%pHier%, pSub:%pSub%, pTgtDir:%pTgtDir%, pTgtFile:%pTgtFile%, pTitleRecord:%pTitleRecord%.'; \r\ncAttributeDim = '}ElementAttributes_' | pDim;\r\ncLenASCIICode = 3;\r\n\r\npDelim = TRIM(pDelim);\r\n\r\n## LogOutput parameters\r\nIF ( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n\r\n### Validate Parameters ###\r\n\r\nnErrors = 0;\r\n\r\nIf( Scan( ':', pDim ) > 0 & pHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pHier = SubSt( pDim, Scan( ':', pDim ) + 1, Long( pDim ) );\r\n pDim = SubSt( pDim, 1, Scan( ':', pDim ) - 1 );\r\nEndIf;\r\n\r\n# Validate dimension\r\nIf( Trim( pDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No dimension specified';\r\n DataSourceType = 'NULL';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\nIf( DimensionExists( pDim ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid dimension: ' | pDim;\r\n DataSourceType = 'NULL';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate hierarchy\r\nIF( Trim(pHier) @= '' );\r\n pHier = pDim;\r\nEndIf;\r\n\r\nIF(\r\nHierarchyExists(pDim, pHier ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid Source Hierarchy: ' | pDim |':'|pHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate subset\r\nIf( Trim( pSub ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No subset specified';\r\n DataSourceType = 'NULL';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nIf( HierarchySubsetExists( pDim, pHier, pSub ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid subset: ' | pSub | ' in dimension:Hierarchy ' | pDim |':' | pHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n## check operating system\r\nIf( SubSt( GetProcessErrorFileDirectory, 2, 1 ) @= ':' );\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nElseIf( Scan( '/', GetProcessErrorFileDirectory ) > 0 );\r\n sOS = 'Linux';\r\n sOSDelim = '/';\r\nElse;\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nEndIf;\r\n\r\n# Validate file path\r\n# Strip off trailing backslash (if present)\r\nIf( SubSt( pTgtDir, Long( pTgtDir ), 1 ) @= sOSDelim );\r\n pTgtDir = SubSt( pTgtDir, 1, Long( pTgtDir ) - 1 );\r\nEndIf;\r\nIf( FileExists( pTgtDir ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid export path specified. Folder does not exist.';\r\n DataSourceType = 'NULL';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\npTgtDir = pTgtDir | sOSDelim;\r\n\r\n# Validate file delimiter & quote character\r\nIf( pDelim @= '' );\r\n pDelim = ',';\r\nElse;\r\n # If length of pDelim is exactly 3 chars and each of them is decimal digit, then the pDelim is entered as ASCII code\r\n nValid = 0;\r\n If ( LONG(pDelim) = cLenASCIICode );\r\n nChar = 1;\r\n While ( nChar <= cLenASCIICode );\r\n If( CODE( pDelim, nChar )>=CODE( '0', 1 ) & CODE( pDelim, nChar )<=CODE( '9', 1 ) );\r\n nValid = 1;\r\n Else;\r\n nValid = 0;\r\n EndIf;\r\n nChar = nChar + 1;\r\n End;\r\n EndIf;\r\n If ( nValid<>0 );\r\n pDelim=CHAR(StringToNumber( pDelim ));\r\n Else;\r\n pDelim = SubSt( Trim( pDelim ), 1, 1 );\r\n EndIf;\r\nEndIf;\r\nIf( pQuote @= '' );\r\n ## Use no quote character \r\nElse;\r\n # If length of pQuote is exactly 3 chars and each of them is decimal digit, then the pQuote is entered as ASCII code\r\n nValid = 0;\r\n If ( LONG(pQuote) = cLenASCIICode );\r\n nChar = 1;\r\n While ( nChar <= cLenASCIICode );\r\n If( CODE( pQuote, nChar ) >= CODE( '0', 1 ) & CODE( pQuote, nChar ) <= CODE( '9', 1 ) );\r\n nValid = 1;\r\n Else;\r\n nValid = 0;\r\n EndIf;\r\n nChar = nChar + 1;\r\n End;\r\n EndIf;\r\n If ( nValid<>0 );\r\n pQuote=CHAR(StringToNumber( pQuote ));\r\n Else;\r\n pQuote = SubSt( Trim( pQuote ), 1, 1 );\r\n EndIf;\r\nEndIf;\r\n\r\n# Validate filename\r\n# If no file name then default to Dimension.Subset.Export.csv (or Dimension.Hierarchy.Subset.Export.csv in case of alternate hierarchy usage)\r\nIf( pTgtFile @= '' );\r\n If( pHier @= pHier );\r\n pTgtFile = pDim |'.'| pSub |'.Export.csv';\r\n Else;\r\n pTgtFile = pDim |'.'| pHier |'.'| pSub |'.Export.csv';\r\n EndIf;\r\nElse;\r\n If( Scan( '.', pTgtFile ) = 0 );\r\n # No file extension specified\r\n pTgtFile = pTgtFile | '.csv';\r\n EndIf;\r\nEndIf;\r\nsFile = pTgtDir | pTgtFile;\r\n\r\n# Validate Character Set\r\nIf(Trim( pCharacterSet ) @= '' );\r\n pCharacterSet = 'TM1CS_UTF8';\r\nEndIf;\r\n\r\n### Initialise & declare variables ###\r\n\r\nnRecordCount = 0;\r\n\r\n### Determine if alias exists ###\r\n\r\nsAttributeDim = '}ElementAttributes_' | pDim;\r\nsAlias = '(no alias)';\r\nIf( DimensionExists( sAttributeDim ) = 1 );\r\n nElementIndex = 1;\r\n nElementCount = DimSiz( sAttributeDim );\r\n While( nElementIndex <= nElementCount );\r\n sAttribute = DimNm( sAttributeDim, nElementIndex );\r\n If( SubSt( DType( sAttributeDim, sAttribute ), 2, 1 ) @= 'A' );\r\n sAlias = sAttribute;\r\n nElementIndex = nElementCount;\r\n EndIf;\r\n nElementIndex = nElementIndex + 1;\r\n End;\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### Assign Data Source ###\r\n\r\nDatasourceNameForServer = pDim|':'|pHier;\r\nDatasourceNameForClient = pDim|':'|pHier;\r\nDataSourceType = 'SUBSET';\r\nDatasourceDimensionSubset = pSub;\r\nDatasourceAsciiDelimiter= pDelim;\r\nDatasourceAsciiQuoteCharacter = pQuote;\r\n\r\n### End Prolog ###", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.sub.exporttofile', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pDim', '', 'pHier', '', 'pSub', '',\r\n \t'pTgtDir', '', 'pTgtFile', '',\r\n \t'pTitleRecord', 1, 'pDelim', ',', 'pQuote', '\"'\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will Export a subset in a Hierarchy of a Dimension to a file. Custom record delimiter\r\n# (specified by a character or its ASCII code) can be used.\r\n# __Format of the file:__ \r\n# - 1st line: File metadata contains summary information about the dimension, hierarchy, subset\r\n# name, number of elements and date/time when file was generated.\r\n# - 2nd line and forth: Elements export data.\r\n\r\n# Note:\r\n# Valid dimension name (pDim), subset name (pSub), inclusion of header (pTitleRecord)\r\n# are mandatory otherwise the process will abort. Target folder (pTgtDir) must exist.\r\n# If needed, custom delimiter might be used by specifying parameter pDelim value as either exactly one\r\n# character or as a 3-digit (decimal) ASCII code. For example to use TAB as a delimiter, use 009.\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pHier:%pHier%, pSub:%pSub%, pTgtDir:%pTgtDir%, pTgtFile:%pTgtFile%, pTitleRecord:%pTitleRecord%.'; \r\ncAttributeDim = '}ElementAttributes_' | pDim;\r\ncLenASCIICode = 3;\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pCharacterSet\": \"TM1CS_UTF8\",\r\n \"pDelim\": \"&\",\r\n \"pDim\": null,\r\n \"pHier\": \"\",\r\n \"pQuote\": \"\"\",\r\n \"pSub\": null,\r\n \"pTgtDir\": \"\",\r\n \"pTgtFile\": \"\",\r\n \"pLogOutput\": 0,\r\n \"pStrictErrorHandling\": 0,\r\n \"pTitleRecord\": 1\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pCharacterSet\": '|StringToJson ( pCharacterSet )|',\r\n \"pDelim\": '|StringToJson ( pDelim )|',\r\n \"pDim\": '|StringToJson ( pDim )|',\r\n \"pHier\": '|StringToJson ( pHier )|',\r\n \"pQuote\": '|StringToJson ( pQuote )|',\r\n \"pSub\": '|StringToJson ( pSub )|',\r\n \"pTgtDir\": '|StringToJson ( pTgtDir )|',\r\n \"pTgtFile\": '|StringToJson ( pTgtFile )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|',\r\n \"pTitleRecord\": '|NumberToString( pTitleRecord )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npCharacterSet = JsonToString( JsonGet( pJson, 'pCharacterSet' ) );\r\npDelim = JsonToString( JsonGet( pJson, 'pDelim' ) );\r\npDim = JsonToString( JsonGet( pJson, 'pDim' ) );\r\npHier = JsonToString( JsonGet( pJson, 'pHier' ) );\r\npQuote = JsonToString( JsonGet( pJson, 'pQuote' ) );\r\npSub = JsonToString( JsonGet( pJson, 'pSub' ) );\r\npTgtDir = JsonToString( JsonGet( pJson, 'pTgtDir' ) );\r\npTgtFile = JsonToString( JsonGet( pJson, 'pTgtFile' ) );\r\n# Numeric Parameters\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\npTitleRecord = StringToNumber( JsonToString( JsonGet( pJson, 'pTitleRecord' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\npDelim = TRIM(pDelim);\r\n\r\n## LogOutput parameters\r\nIF ( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n\r\n### Validate Parameters ###\r\n\r\nnErrors = 0;\r\n\r\nIf( Scan( ':', pDim ) > 0 & pHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pHier = SubSt( pDim, Scan( ':', pDim ) + 1, Long( pDim ) );\r\n pDim = SubSt( pDim, 1, Scan( ':', pDim ) - 1 );\r\nEndIf;\r\n\r\n# Validate dimension\r\nIf( Trim( pDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No dimension specified';\r\n DataSourceType = 'NULL';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\nIf( DimensionExists( pDim ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid dimension: ' | pDim;\r\n DataSourceType = 'NULL';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate hierarchy\r\nIF( Trim(pHier) @= '' );\r\n pHier = pDim;\r\nEndIf;\r\n\r\nIF(\r\nHierarchyExists(pDim, pHier ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid Source Hierarchy: ' | pDim |':'|pHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate subset\r\nIf( Trim( pSub ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No subset specified';\r\n DataSourceType = 'NULL';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nIf( HierarchySubsetExists( pDim, pHier, pSub ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid subset: ' | pSub | ' in dimension:Hierarchy ' | pDim |':' | pHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n## check operating system\r\nIf( SubSt( GetProcessErrorFileDirectory, 2, 1 ) @= ':' );\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nElseIf( Scan( '/', GetProcessErrorFileDirectory ) > 0 );\r\n sOS = 'Linux';\r\n sOSDelim = '/';\r\nElse;\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nEndIf;\r\n\r\n# Validate file path\r\n# Strip off trailing backslash (if present)\r\nIf(Trim( pTgtDir ) @= '' );\r\n pTgtDir = GetProcessErrorFileDirectory;\r\nEndIf;\r\nIf( SubSt( pTgtDir, Long( pTgtDir ), 1 ) @= sOSDelim );\r\n pTgtDir = SubSt( pTgtDir, 1, Long( pTgtDir ) - 1 );\r\nEndIf;\r\nIf( FileExists( pTgtDir ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid export path specified. Folder does not exist.';\r\n DataSourceType = 'NULL';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\npTgtDir = pTgtDir | sOSDelim;\r\n\r\n# Validate file delimiter & quote character\r\nIf( pDelim @= '' );\r\n pDelim = ',';\r\nElse;\r\n # If length of pDelim is exactly 3 chars and each of them is decimal digit, then the pDelim is entered as ASCII code\r\n nValid = 0;\r\n If ( LONG(pDelim) = cLenASCIICode );\r\n nChar = 1;\r\n While ( nChar <= cLenASCIICode );\r\n If( CODE( pDelim, nChar )>=CODE( '0', 1 ) & CODE( pDelim, nChar )<=CODE( '9', 1 ) );\r\n nValid = 1;\r\n Else;\r\n nValid = 0;\r\n EndIf;\r\n nChar = nChar + 1;\r\n End;\r\n EndIf;\r\n If ( nValid<>0 );\r\n pDelim=CHAR(StringToNumber( pDelim ));\r\n Else;\r\n pDelim = SubSt( Trim( pDelim ), 1, 1 );\r\n EndIf;\r\nEndIf;\r\nIf( pQuote @= '' );\r\n ## Use no quote character \r\nElse;\r\n # If length of pQuote is exactly 3 chars and each of them is decimal digit, then the pQuote is entered as ASCII code\r\n nValid = 0;\r\n If ( LONG(pQuote) = cLenASCIICode );\r\n nChar = 1;\r\n While ( nChar <= cLenASCIICode );\r\n If( CODE( pQuote, nChar ) >= CODE( '0', 1 ) & CODE( pQuote, nChar ) <= CODE( '9', 1 ) );\r\n nValid = 1;\r\n Else;\r\n nValid = 0;\r\n EndIf;\r\n nChar = nChar + 1;\r\n End;\r\n EndIf;\r\n If ( nValid<>0 );\r\n pQuote=CHAR(StringToNumber( pQuote ));\r\n Else;\r\n pQuote = SubSt( Trim( pQuote ), 1, 1 );\r\n EndIf;\r\nEndIf;\r\n\r\n# Validate filename\r\n# If no file name then default to Dimension.Subset.Export.csv (or Dimension.Hierarchy.Subset.Export.csv in case of alternate hierarchy usage)\r\nIf( pTgtFile @= '' );\r\n If( pHier @= pHier );\r\n pTgtFile = pDim |'.'| pSub |'.Export.csv';\r\n Else;\r\n pTgtFile = pDim |'.'| pHier |'.'| pSub |'.Export.csv';\r\n EndIf;\r\nElse;\r\n If( Scan( '.', pTgtFile ) = 0 );\r\n # No file extension specified\r\n pTgtFile = pTgtFile | '.csv';\r\n EndIf;\r\nEndIf;\r\nsFile = pTgtDir | pTgtFile;\r\n\r\n# Validate Character Set\r\nIf(Trim( pCharacterSet ) @= '' );\r\n pCharacterSet = 'TM1CS_UTF8';\r\nEndIf;\r\n\r\n### Initialise & declare variables ###\r\n\r\nnRecordCount = 0;\r\n\r\n### Determine if alias exists ###\r\n\r\nsAttributeDim = '}ElementAttributes_' | pDim;\r\nsAlias = '(no alias)';\r\nIf( DimensionExists( sAttributeDim ) = 1 );\r\n nElementIndex = 1;\r\n nElementCount = DimSiz( sAttributeDim );\r\n While( nElementIndex <= nElementCount );\r\n sAttribute = DimNm( sAttributeDim, nElementIndex );\r\n If( SubSt( DType( sAttributeDim, sAttribute ), 2, 1 ) @= 'A' );\r\n sAlias = sAttribute;\r\n nElementIndex = nElementCount;\r\n EndIf;\r\n nElementIndex = nElementIndex + 1;\r\n End;\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### Assign Data Source ###\r\n\r\nDatasourceNameForServer = pDim|':'|pHier;\r\nDatasourceNameForClient = pDim|':'|pHier;\r\nDataSourceType = 'SUBSET';\r\nDatasourceDimensionSubset = pSub;\r\nDatasourceAsciiDelimiter= pDelim;\r\nDatasourceAsciiQuoteCharacter = pQuote;\r\n\r\n### End Prolog ###", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n# Set the output character set\r\nSetOutputCharacterSet( sFile, pCharacterSet );\r\n\r\n### Check for error in prolog ###\r\n\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### Check whether to write title records ###\r\n\r\nnRecordCount = nRecordCount + 1;\r\n\r\nIf( nRecordCount = 1 & pTitleRecord = 1 );\r\n\r\n nSubsetSize = HierarchySubSetGetSize( pDim, pHier, pSub );\r\n\r\n # Write params\r\n TextOutput(\r\n sFile,\r\n 'Export from dimension: ' | pDim | ',Hierarchy:'|pHier|',Subset:'|pSub|\r\n ', Total elements: ' | NumberToString( nSubsetSize ) |\r\n '. On ' | Date( Now, 1 ) | ' at ' | Time\r\n );\r\n # Write header records\r\n TextOutput(\r\n sFile,\r\n 'Subix',\r\n 'Element',\r\n 'Alias: ' | sAlias,\r\n 'Dimix',\r\n 'El Type',\r\n 'Level',\r\n 'Num Children',\r\n 'Parent 1',\r\n 'Weight 1',\r\n 'Parent 2',\r\n 'Weight 2',\r\n 'Parent 3',\r\n 'Weight 3',\r\n 'Parent 4',\r\n 'Weight 4',\r\n 'Parent 5',\r\n 'Weight 5'\r\n );\r\n\r\nEndIf;\r\n\r\n### Write dimension info to flat file ###\r\nsElement = HierarchyElementPrincipalName( pDim, pHier, vElement );\r\nsSubix = NumberToString( nRecordCount );\r\nsIndex = NumberToString( ElementIndex( pDim, pHier, vElement ) );\r\nsType = ElementType( pDim, PHier, vElement );\r\nsLevel = NumberToString( ElementLevel( pDim, pHier, vElement ) );\r\nsChild = NumberToString( ElementComponentCount( pDim, pHier, vElement ) );\r\nsParent1 = ElementParent( pDim,pHier, vElement, 1 );\r\nsParent2 = ElementParent( pDim,pHier, vElement, 2 );\r\nsParent3 = ElementParent( pDim,pHier, vElement, 3 );\r\nsParent4 = ElementParent( pDim,pHier, vElement, 4 );\r\nsParent5 = ElementParent( pDim,pHier, vElement, 5 );\r\nsParent6 = ElementParent( pDim,pHier, vElement, 6 );\r\nsParent7 = ElementParent( pDim,pHier, vElement, 7 );\r\nsParent8 = ElementParent( pDim,pHier, vElement, 8 );\r\nsWeight1 = NumberToString( ElementWeight( pDim, pHier, sParent1, vElement ) );\r\nsWeight2 = NumberToString( ElementWeight( pDim, pHier, sParent2, vElement ) );\r\nsWeight3 = NumberToString( ElementWeight( pDim, pHier, sParent3, vElement ) );\r\nsWeight4 = NumberToString( ElementWeight( pDim, pHier, sParent4, vElement ) );\r\nsWeight5 = NumberToString( ElementWeight( pDim, pHier, sParent5, vElement ) );\r\nsWeight6 = NumberToString( ElementWeight( pDim, pHier, sParent6, vElement ) );\r\nsWeight7 = NumberToString( ElementWeight( pDim, pHier, sParent7, vElement ) );\r\nsWeight8 = NumberToString( ElementWeight( pDim, pHier, sParent8, vElement ) );\r\n\r\nIf( sAlias @<> '(no alias)' );\r\n sAliasValue = ElementAttrS( pDim, pHier, vElement, sAlias );\r\nElse;\r\n sAliasValue = '';\r\nEndIf;\r\n\r\n TextOutput(\r\n sFile,\r\n sSubix,\r\n sElement,\r\n sAliasValue,\r\n sIndex,\r\n sType,\r\n sLevel,\r\n sChild,\r\n sParent1,\r\n sWeight1,\r\n sParent2,\r\n sWeight2,\r\n sParent3,\r\n sWeight3,\r\n sParent4,\r\n sWeight4,\r\n sParent5,\r\n sWeight5,\r\n sParent6,\r\n sWeight6,\r\n sParent7,\r\n sWeight7,\r\n sParent8,\r\n sWeight8\r\n );\r\n\r\n### End Data ###", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully exported subset %pSub% from dimension %pDim%.' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n### End Epilog ###", @@ -13,27 +13,15 @@ "subset": "All" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pDim", - "Prompt": "REQUIRED: Dimension name", + "Prompt": "REQUIRED: Delimited list of dimensions", "Value": "", "Type": "String" }, { "Name": "pHier", - "Prompt": "OPTIONAL: Hierarchy name (default if blank = same named hierarchy)", + "Prompt": "OPTIONAL: Hierarchy name (Default = pDim)", "Value": "", "Type": "String" }, @@ -45,38 +33,56 @@ }, { "Name": "pTgtDir", - "Prompt": "REQUIRED: Target Directory Path", + "Prompt": "OPTIONAL: Target file directory (Default = GetProcessErrorFileDirectory)", "Value": "", "Type": "String" }, { "Name": "pTgtFile", - "Prompt": "OPTIONAL: Target File Name (Default Extension .csv)", + "Prompt": "OPTIONAL: Target file name (Default = pDim |'.' | pSub | '.Export.csv')", "Value": "", "Type": "String" }, { "Name": "pTitleRecord", - "Prompt": "OPTIONAL: Boolean: 1 = Yes include header row", + "Prompt": "OPTIONAL: Delete temporary view and subsets (0 = Retain View and Subsets, 1 = Delete View and Subsets, 2 = Delete View only. Default = 1)", "Value": 1, "Type": "Numeric" }, { "Name": "pDelim", - "Prompt": "OPTIONAL: AsciiOutput delimiter character (Default=comma, exactly 3 digits = ASCII code)", - "Value": ",", + "Prompt": "OPTIONAL: Delimiter for list parameters (Default = '&')", + "Value": "&", "Type": "String" }, { "Name": "pQuote", - "Prompt": "OPTIONAL: AsciiOutput quote character (Accepts empty quote, exactly 3 digits = ASCII code)", + "Prompt": "OPTIONAL: Quote character (2 or 3 digits = ASCII code. Default = '\"')", "Value": "\"", "Type": "String" }, { "Name": "pCharacterSet", - "Prompt": "OPTIONAL: The output character set (defaults to TM1CS_UTF8 if blank)", - "Value": "", + "Prompt": "OPTIONAL: The output character set (Default = 'TM1CS_UTF8')", + "Value": "TM1CS_UTF8", + "Type": "String" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", "Type": "String" } ], @@ -89,5 +95,7 @@ "EndByte": 0 } ], - "VariablesUIData": [] + "VariablesUIData": [ + "VarType=32\fColType=827\f" + ] } \ No newline at end of file diff --git a/bedrock_processes_json/}bedrock.hier.sub.publish.json b/bedrock_processes_json/}bedrock.hier.sub.publish.json index 32e2561..26d0090 100644 --- a/bedrock_processes_json/}bedrock.hier.sub.publish.json +++ b/bedrock_processes_json/}bedrock.hier.sub.publish.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.hier.sub.publish", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.sub.publish', 'pLogOutput', pLogOutput, 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pDim', '', 'pHier', '', 'pSub', '',\r\n \t'pOverwrite', 0\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock Ver 4.0.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process converts a private subset to a public subset for the named client.\r\n#\r\n# Use case: Intended for development/prototyping or production.\r\n# 1. Make private subset public to enable public consumption.\r\n#\r\n# Note:\r\n# * A valid dimension name pDim is mandatory otherwise the process will abort.\r\n# * Also, a valid subset name pSub _belonging to the user running the process_ is mandatory otherwise the process will abort.\r\n# * This process must be run by the user owning the private subset; it canot be run by another user.\r\n#EndRegion @DOC\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSubset = cThisProcName | '_' | cTimeStamp | '_' | cRandomInt;\r\ncTempFile = GetProcessErrorFileDirectory | cTempSubset | '.csv';\r\nsMessage = \t'';\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pHier:%pHier%, pSub:%pSub%, pSubPublish:%pSubPublish%, pOverwrite:%pOverwrite%.' ;\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\n# create friendly name for user handle\r\nIf( DimIx( '}ElementAttributes_}Clients', '}TM1_DefaultDisplayValue' ) > 0 );\r\n pClient = AttrS( '}Clients', cUserName, '}TM1_DefaultDisplayValue' );\r\n If( pClient @= '' );\r\n pClient = cUserName;\r\n EndIf;\r\nElse;\r\n pClient = cUserName;\r\nEndIf;\r\n\r\n# Validate Dimension & Hierarchy\r\nIf( Scan(':', pDim ) > 0 );\r\n pHier = SubSt( pDim, Scan(':', pDim )+1, Long(pDim) - Scan(':', pDim ) );\r\n pDim = SubSt( pDim, 1, Scan(':', pDim )-1 );\r\nEndIf;\r\nIf( pHier @= '' );\r\n pHier = pDim;\r\nEndIf;\r\nIf( Trim( pDim ) @= '' );\r\n sMessage = 'No dimension specified';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( DimensionExists( pDim ) = 0 );\r\n sMessage = Expand('Dimension %pDim% does not exist on server');\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( HierarchyExists( pDim, pHier ) = 0 );\r\n sMessage = Expand('Hierarchy %pHier% does not exist in dimension %pDim%');\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\nIf( pHier @= pDim );\r\n sDimHier = pDim;\r\nElse;\r\n sDimHier = Expand('%pDim%:%pHier%');\r\nEndIf;\r\n\r\n# Validate Subset\r\nIf( Trim( pSub ) @= '' );\r\n sMessage = 'No private subset specified';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# No way to check if private subset exists with TurboIntegrator except via file system.\r\n# Could include data directory param and concatenate with user, cube and view to check\r\n# if private subset exists to handle error in the case that private sub does not exist\r\n\r\n# Check for valid overwrite parameters\r\nIf( pOverwrite <> 0 & pOverwrite <> 1 );\r\n sMessage = 'Invalid overwrite existing public subset selection: ' | NumberToString( pOverwrite );\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nIf( pOverwrite = 0 & HierarchySubsetExists( pDim, pHier, pSub ) = 1 );\r\n # If NOT overwriting current public subset AND subset of the same name already exists then cause minor error ( major error if not handled )\r\n sMessage = 'Public subset of same name already exists and Overwrite=0 specified';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### Publish the subset ###\r\n# PublishSubset publishes a named private subset on the server. This function was introduced in Planning Analytics 2.0.9.10/TM1 Server 11.8.9 and cannot be used in previous versions.\r\nPublishSubset( sDimHier, pSub, pOverwrite );\r\n\r\n### End Prolog ###", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.sub.publish', 'pLogOutput', pLogOutput, 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pDim', '', 'pHier', '', 'pSub', '',\r\n \t'pOverwrite', 0\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock Ver 4.0.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process converts a private subset to a public subset for the named client.\r\n#\r\n# Use case: Intended for development/prototyping or production.\r\n# 1. Make private subset public to enable public consumption.\r\n#\r\n# Note:\r\n# * A valid dimension name pDim is mandatory otherwise the process will abort.\r\n# * Also, a valid subset name pSub _belonging to the user running the process_ is mandatory otherwise the process will abort.\r\n# * This process must be run by the user owning the private subset; it canot be run by another user.\r\n#EndRegion @DOC\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSubset = cThisProcName | '_' | cTimeStamp | '_' | cRandomInt;\r\ncTempFile = GetProcessErrorFileDirectory | cTempSubset | '.csv';\r\nsMessage = \t'';\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pHier:%pHier%, pSub:%pSub%, pSubPublish:%pSubPublish%, pOverwrite:%pOverwrite%.' ;\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pDim\": null,\r\n \"pHier\": \"\",\r\n \"pSub\": null,\r\n \"pLogOutput\": 0,\r\n \"pOverwrite\": 0,\r\n \"pStrictErrorHandling\": 0\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pDim\": '|StringToJson ( pDim )|',\r\n \"pHier\": '|StringToJson ( pHier )|',\r\n \"pSub\": '|StringToJson ( pSub )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pOverwrite\": '|NumberToString( pOverwrite )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npDim = JsonToString( JsonGet( pJson, 'pDim' ) );\r\npHier = JsonToString( JsonGet( pJson, 'pHier' ) );\r\npSub = JsonToString( JsonGet( pJson, 'pSub' ) );\r\n# Numeric Parameters\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npOverwrite = StringToNumber( JsonToString( JsonGet( pJson, 'pOverwrite' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\n# create friendly name for user handle\r\nIf( DimIx( '}ElementAttributes_}Clients', '}TM1_DefaultDisplayValue' ) > 0 );\r\n pClient = AttrS( '}Clients', cUserName, '}TM1_DefaultDisplayValue' );\r\n If( pClient @= '' );\r\n pClient = cUserName;\r\n EndIf;\r\nElse;\r\n pClient = cUserName;\r\nEndIf;\r\n\r\n# Validate Dimension & Hierarchy\r\nIf( Scan(':', pDim ) > 0 );\r\n pHier = SubSt( pDim, Scan(':', pDim )+1, Long(pDim) - Scan(':', pDim ) );\r\n pDim = SubSt( pDim, 1, Scan(':', pDim )-1 );\r\nEndIf;\r\nIf( pHier @= '' );\r\n pHier = pDim;\r\nEndIf;\r\nIf( Trim( pDim ) @= '' );\r\n sMessage = 'No dimension specified';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( DimensionExists( pDim ) = 0 );\r\n sMessage = Expand('Dimension %pDim% does not exist on server');\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( HierarchyExists( pDim, pHier ) = 0 );\r\n sMessage = Expand('Hierarchy %pHier% does not exist in dimension %pDim%');\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\nIf( pHier @= pDim );\r\n sDimHier = pDim;\r\nElse;\r\n sDimHier = Expand('%pDim%:%pHier%');\r\nEndIf;\r\n\r\n# Validate Subset\r\nIf( Trim( pSub ) @= '' );\r\n sMessage = 'No private subset specified';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# No way to check if private subset exists with TurboIntegrator except via file system.\r\n# Could include data directory param and concatenate with user, cube and view to check\r\n# if private subset exists to handle error in the case that private sub does not exist\r\n\r\n# Check for valid overwrite parameters\r\nIf( pOverwrite <> 0 & pOverwrite <> 1 );\r\n sMessage = 'Invalid overwrite existing public subset selection: ' | NumberToString( pOverwrite );\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\nIf( pOverwrite = 0 & HierarchySubsetExists( pDim, pHier, pSub ) = 1 );\r\n # If NOT overwriting current public subset AND subset of the same name already exists then cause minor error ( major error if not handled )\r\n sMessage = 'Public subset of same name already exists and Overwrite=0 specified';\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### Publish the subset ###\r\n# PublishSubset publishes a named private subset on the server. This function was introduced in Planning Analytics 2.0.9.10/TM1 Server 11.8.9 and cannot be used in previous versions.\r\nPublishSubset( sDimHier, pSub, pOverwrite );\r\n\r\n### End Prolog ###", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully published subset %pSub% in hierarchy %pDim%:%pHier% created by cient %pClient%.' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n### End Epilog ###", @@ -10,41 +10,47 @@ "Type": "None" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pDim", - "Prompt": "REQUIRED: dimension name (if a dim:hier tuple is supplied then the hierarchy parameter will be ignored)", + "Prompt": "REQUIRED: Delimited list of dimensions", "Value": "", "Type": "String" }, { "Name": "pHier", - "Prompt": "OPTIONAL: hierarchy name (if blank assume same named hierarchy. delimited dim:hier can also be passed in the dimension parameter)", + "Prompt": "OPTIONAL: Hierarchy name (Default = pDim)", "Value": "", "Type": "String" }, { "Name": "pSub", - "Prompt": "REQUIRED: private subset name", + "Prompt": "REQUIRED: Subset name", "Value": "", "Type": "String" }, { "Name": "pOverwrite", - "Prompt": "OPTIONAL: Overwrite Existing public subset with same name? (Boolean 1=Yes)", + "Prompt": "OPTIONAL: Overwrite existing named objects (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [], diff --git a/bedrock_processes_json/}bedrock.hier.unwind.json b/bedrock_processes_json/}bedrock.hier.unwind.json index ddb52c0..209a4f2 100644 --- a/bedrock_processes_json/}bedrock.hier.unwind.json +++ b/bedrock_processes_json/}bedrock.hier.unwind.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.hier.unwind", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.unwind', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pDim', '', 'pHier', '', 'pConsol', '*',\r\n \t'pRecursive', 0, 'pDelim', '&'\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock Ver 4~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will remove all children from a specific target consolidation (pConsol) in a Hierarchy\r\n# in target Dimension. If recursive (pRecursive=1), it will also unwind all consolidations that are \r\n# descendants of the target regardless of depth. If not recursive (pRecursive=0) then only immediate children\r\n# of the target consolidation will be removed.\r\n#\r\n# Use case: Intended for both production and development/prototyping scenarios.\r\n# 1. **Production** call prior to main dimension build process in case mapping relationships have changed to ensure no double-counting steming from leaf elements \r\n# rolling into multiple parents within the same rollup or hierarhcy\r\n# 2. **Production** combine with }bedrock.hier.emptyconsols.delete to remove orphaned rollups\r\n# 3. **Development** manual cleanup of dimensions during prototyping or prior to going to production\r\n#\r\n# Note:\r\n# * A valid source dimension name (pDim) is mandatory otherwise the process will abort.\r\n# * A blank pHier parameter will process _only the same named hierarchy_ for each of the dimensions processed.\r\n# * A \\* pConsol parameter will process ALL C level items in the given hierarchy (pHier).\r\n# * A delimited list or wildcard for pDim or pHier or a delimited list of consolidations for pConsol will result in recursive calls of the process.\r\n#\r\n# Caution: \r\n# If consolidations are also used in unrelated consolidations and recursive is selected this\r\n# will result in orphan consolidations in the other rollups.\r\n#EndRegion @DOC\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncTempSubOuter = '}OuterLoop_' | cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncTempSubInner = '}InnerLoop_' | cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent= 'Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncMsgInfoContent = 'User:%cUserName% Process:%cThisProcName% Message:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pHier:%pHier%, pConsol:%pConsol%, pRecursive:%pRecursive%, pDelim:%pDelim%.' ;\r\ncHierAttr = 'Bedrock.Descendant';\r\ncAttrVal = 'Descendant';\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\nIf( Scan( '*', pDim ) = 0 & Scan( '?', pDim ) = 0 & Scan( pDelim, pDim ) = 0 & Scan( ':', pDim ) > 0 & pHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pHier = SubSt( pDim, Scan( ':', pDim ) + 1, Long( pDim ) );\r\n pDim = SubSt( pDim, 1, Scan( ':', pDim ) - 1 );\r\nEndIf;\r\n\r\n## Validate Source dimension\r\nIF( Trim( pDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIF( Scan( '*', pDim ) = 0 & Scan( '?', pDim ) = 0 & Scan( pDelim, pDim ) = 0 & DimensionExists( pDim ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid dimension: ' | pDim;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate hierarchy (can only validate hierarchy up front if dimension is fixed and doesn't contain wildcards)\r\nIF( Scan( '*', pDim ) = 0 & Scan( '?', pDim ) = 0 & Scan( pDelim, pDim ) = 0 & pHier @= '');\r\n pHier = pDim;\r\nElseIf( Scan( '*', pHier ) = 0 & Scan( '?', pHier ) = 0 & Scan( pDelim, pHier ) = 0 & pHier @<> '' & DimensionExists( pDim ) = 1 & HierarchyExists( pDim, pHier ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid dimension hierarchy: ' | pHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndif;\r\n\r\nIf( Trim( pHier ) @= '' );\r\n ## use same name as Dimension. Since wildcards are allowed, this is managed inside the code below\r\nEndIf;\r\n\r\n# Validate consol\r\nIf( pConsol @<> '');\r\n If( Scan( '*', pConsol ) = 0 & Scan( '?', pConsol ) = 0 & Scan( pDelim, pConsol ) = 0 & ElementIndex( pDim, pHier, pConsol ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Item ' | pConsol | ' does NOT exist. Please enter a valid consolidation element in the ' |pDim| ':' |pHier| ' dimension:hierarchy.'; \r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n ElseIf( Scan( '*', pConsol ) = 0 & Scan( '?', pConsol ) = 0 & Scan( pDelim, pConsol ) = 0 & ElementType( pDim, pHier, pConsol ) @<> 'C' );\r\n nErrors = 1;\r\n sMessage = 'Item ' | pConsol | ' is NOT a consolidated item. Please enter a valid consolidation element in the ' |pDim| ':' |pHier| ' dimension:hierarchy.'; \r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n ElseIf( Scan( '*', pConsol ) = 0 & Scan( '?', pConsol ) = 0 & Scan( pDelim, pConsol ) = 0 & ElementComponentCount( pDim, pHier, pConsol ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid consolidation: ' | pConsol | ' has no children.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n Endif;\r\nElseIf( Trim( pConsol ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No consolidated element specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndif;\r\n\r\n# If blank delimiter specified then convert to default\r\nIf( pDelim @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nElse;\r\n # If subset required will be set later\r\n DataSourceType = 'NULL';\r\nEndIf;\r\n\r\n### If there is no separator and wildcard in the parameters, execute the unwind of the specific consolidated element\r\nIf( Scan( '*', pDim ) = 0 & Scan( '?', pDim ) = 0 & Scan( pDelim, pDim ) = 0 & Scan( '*', pHier ) = 0 & Scan( '?', pHier ) = 0 & Scan( pDelim, pHier ) = 0 & Scan( '*', pConsol ) = 0 & Scan( '?', pConsol ) = 0 & Scan( pDelim, pConsol ) = 0 );\r\n\r\n ### In case alias used for pConsol convert to principal name \r\n If( ElementIndex( pDim, pHier, pConsol ) > 0 );\r\n pConsol = HierarchyElementPrincipalName( pDim, pHier, pConsol );\r\n EndIf;\r\n \r\n ### Create Temp Descendent Attribute\r\n AttrDelete( pDim, cHierAttr );\r\n AttrInsert( pDim, '', cHierAttr, 'S' );\r\n \r\n ### Assign data source ###\r\n If( pRecursive = 1);\r\n # Set Descendent attribute value\r\n nElementIndex = 1;\r\n nElementCount = ElementCount( pDim , pHier );\r\n While( nElementIndex <= nElementCount );\r\n sElement = ElementName( pDim, pHier, nElementIndex );\r\n If( ElementIsAncestor( pDim, pHier, pConsol, sElement ) = 1 % pConsol @= sElement );\r\n ElementAttrPutS( cAttrVal, pDim, pHier, sElement, cHierAttr );\r\n EndIf;\r\n nElementIndex = nElementIndex + 1;\r\n End;\r\n # Assign Data Source\r\n DataSourceType = 'SUBSET';\r\n DatasourceNameForServer = pDim|':'|pHier;\r\n DatasourceNameForClient = pDim|':'|pHier;\r\n DatasourceDimensionSubset = 'ALL';\r\n Else;\r\n ### Remove direct children from the target consol ###\r\n If( ElementComponentCount( pDim, pHier, pConsol ) > 0 );\r\n If( pLogOutput = 1 );\r\n LogOutput( 'INFO', Expand( 'Deleting all components from consolidation %pConsol% in hierarchy \"%pHier%\" of \"%pDim%\" dimension.' ) );\r\n EndIf;\r\n nComp = ElementComponentCount( pDim, pHier, pConsol );\r\n While( nComp > 0 );\r\n sComp = ElementComponent( pDim, pHier, pConsol, nComp );\r\n HierarchyElementComponentDelete( pDim, pHier, pConsol, sComp );\r\n nComp = nComp - 1;\r\n End;\r\n EndIf;\r\n # No data source, straight to Epilog\r\n DataSourceType = 'NULL';\r\n EndIf;\r\n\r\n### If pConsol is \"*\" and there is no separator and wildcard in the pDim & pHier parameters then unwind the whole hierarchy\r\nElseIf( Scan( '*', pDim ) = 0 & Scan( '?', pDim ) = 0 & Scan( pDelim, pDim ) = 0 & Scan( '*', pHier ) = 0 & Scan( '?', pHier ) = 0 & Scan( pDelim, pHier ) = 0 & Trim( pConsol ) @= '*' );\r\n\r\n # as pConsol is * wildcard it doesn't matter if recursive or not. We unwind everything. As speed enhancement rather than removing children delete and add back C elements to empty children in one step (not steps = count of children)\r\n nMaxEle = ElementCount( pDim, pHier );\r\n nCtrEle = 1;\r\n While( nCtrEle <= nMaxEle );\r\n sEle = ElementName( pDim, pHier, nCtrEle);\r\n If( ElementComponentCount( pDim, pHier, sEle ) > 0 );\r\n If( nCtrEle < nMaxEle );\r\n sEleNext = ElementName( pDim, pHier, nCtrEle + 1 );\r\n Else;\r\n sEleNext = '';\r\n EndIf;\r\n HierarchyElementDelete( pDim, pHier, sEle );\r\n HierarchyElementInsert( pDim, pHier, sEleNext, sEle, 'C' );\r\n EndIf;\r\n nCtrEle = nCtrEle + 1;\r\n End;\r\n\r\n # since hierarchy already fully unwound no subset; datasource = NULL\r\n DataSourceType = 'NULL';\r\n\r\n## Otherwise, if there is a separator or wildcard in the parameters, tokenize the string and self-call the process recursively.\r\nElse;\r\n # No data source, straight to Epilog\r\n DataSourceType = 'NULL';\r\n \r\n # Loop through dimensions in pDim\r\n sDims = pDim;\r\n nDimDelimiterIndex = 1;\r\n sMdx = '';\r\n # Get 1st dimension\r\n While( nDimDelimiterIndex <> 0 );\r\n # Extract 1st dimension > sDim\r\n nDimDelimiterIndex = Scan( pDelim, sDims );\r\n If( nDimDelimiterIndex = 0 );\r\n sDim = sDims;\r\n Else;\r\n sDim = Trim( SubSt( sDims, 1, nDimDelimiterIndex - 1 ) );\r\n sDims = Trim( Subst( sDims, nDimDelimiterIndex + Long(pDelim), Long( sDims ) ) );\r\n EndIf;\r\n \r\n # Create subset of dimensions using Wildcard to loop through dimensions in pDim with wildcard\r\n sDimExp = '\"'|sDim|'\"';\r\n sMdxPart = Expand('{TM1FILTERBYPATTERN( EXCEPT( TM1SUBSETALL( [}Dimensions].[}Dimensions] ), TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions].[}Dimensions] ) , \"*:*\") ) , %sDimExp% )}');\r\n If( sMdx @= ''); \r\n sMdx = sMdxPart; \r\n Else;\r\n sMdx = sMdx | ' + ' | sMdxPart;\r\n EndIf;\r\n End;\r\n \r\n If( SubsetExists( '}Dimensions' , cTempSubOuter ) = 1 );\r\n # If a delimited list of dim names includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( '}Dimensions' , cTempSubOuter, sMDX );\r\n Else;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSubOuter, sMDX, '}Dimensions' , 1 );\r\n EndIf;\r\n \r\n # Loop through dimensions in subset created based on wildcard\r\n nCountDim = SubsetGetSize( '}Dimensions' , cTempSubOuter );\r\n While( nCountDim >= 1 );\r\n sDim = SubsetGetElementName( '}Dimensions' , cTempSubOuter, nCountDim );\r\n # Validate dimension name\r\n If( DimensionExists(sDim) = 0 );\r\n nErrors = 1;\r\n sMessage = Expand( 'Dimension \"%sDim%\" does not exist.' );\r\n LogOutput( 'ERROR', Expand( cMsgErrorContent ) );\r\n Else;\r\n If( pLogOutput = 1 );\r\n sMessage = Expand( 'Dimension \"%sDim%\" being processed....' );\r\n LogOutput( 'INFO', Expand( cMsgInfoContent ) );\r\n EndIf;\r\n # Loop through hierarchies in pHier\r\n If( Trim( pHier ) @= '' );\r\n ### Use main hierarchy for each dimension if pHier is empty\r\n sHierarchies = sDim;\r\n Else;\r\n sHierarchies = pHier;\r\n EndIf;\r\n nDelimiterIndexA = 1;\r\n sHierDim = '}Dimensions' ;\r\n sMdxHier = '';\r\n While( nDelimiterIndexA <> 0 );\r\n nDelimiterIndexA = Scan( pDelim, sHierarchies );\r\n If( nDelimiterIndexA = 0 );\r\n sHierarchy = sHierarchies;\r\n Else;\r\n sHierarchy = Trim( SubSt( sHierarchies, 1, nDelimiterIndexA - 1 ) );\r\n sHierarchies = Trim( Subst( sHierarchies, nDelimiterIndexA + Long(pDelim), Long( sHierarchies ) ) );\r\n EndIf;\r\n \r\n # Create subset of Hierarchies using Wildcard\r\n If( sDim @= sHierarchy );\r\n sHierExp = '\"'| sDim |'\"';\r\n Else;\r\n sHierExp = '\"'| sDim | ':' | sHierarchy|'\"';\r\n EndIf;\r\n sMdxHierPart = Expand('{TM1FILTERBYPATTERN( {TM1SUBSETALL([%sHierDim%].[%sHierDim%])}, %sHierExp% )}');\r\n If( sMdxHier @= ''); \r\n sMdxHier = sMdxHierPart; \r\n Else;\r\n sMdxHier = sMdxHier | ' + ' | sMdxHierPart;\r\n EndIf;\r\n End;\r\n \r\n # include the named hierarchy in case ALL hierachies\r\n If( Trim(pHier) @= '*' );\r\n sMdxHier = Expand('{[%sHierDim%].[%sHierDim%].[%sDim%]} + %sMdxHier%');\r\n EndIf;\r\n \r\n If( SubsetExists( sHierDim, cTempSubInner ) = 1 );\r\n # If a delimited list of hierarchy names includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( sHierDim, cTempSubInner, sMdxHier );\r\n Else;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSubInner, sMdxHier, sHierDim, 1 );\r\n EndIf;\r\n\r\n # Loop through subset of hierarchies created based on wildcard\r\n nCountHier = SubsetGetSize( sHierDim, cTempSubInner );\r\n While( nCountHier >= 1 );\r\n sCurrHier = SubsetGetElementName( sHierDim, cTempSubInner, nCountHier );\r\n sCurrHierName = Subst( sCurrHier, Scan(':', sCurrHier)+1, Long(sCurrHier) );\r\n # Validate hierarchy name in sHierDim\r\n If( Dimix( sHierDim , sCurrHier ) = 0 );\r\n sMessage = Expand('The \"%sCurrHier%\" hierarchy does NOT exist in the \"%sDim%\" dimension.');\r\n LogOutput( 'INFO' , Expand( cMsgInfoContent ) );\r\n ElseIf( sCurrHierName @= 'Leaves' );\r\n sMessage = Expand('Skipping %sCurrHier% hierarchy. No need to unwind!');\r\n If( pLogOutput = 1 );\r\n LogOutput( 'INFO', Expand( cMsgInfoContent ) );\r\n EndIf;\r\n Else;\r\n If( pLogOutput = 1 );\r\n sMessage = Expand( 'Hierarchy \"%sCurrHierName%\" in Dimension \"%sDim%\" being processed....' );\r\n LogOutput( 'INFO', Expand( cMsgInfoContent ) );\r\n EndIf;\r\n # Loop through consolidated elements in pConsol\r\n sEles = Trim( pConsol );\r\n If( sEles @= '*' );\r\n # no need for recursive call for ALL wildcard. We can just unwind whole hierarchy\r\n nMaxEle = ElementCount( sDim, sCurrHierName );\r\n nCtrEle = 1;\r\n While( nCtrEle <= nMaxEle );\r\n sEle = ElementName( sDim, sCurrHierName, nCtrEle);\r\n If( ElementComponentCount( sDim, sCurrHierName, sEle ) > 0 );\r\n If( nCtrEle < nMaxEle );\r\n sEleNext = ElementName( sDim, sCurrHierName, nCtrEle + 1 );\r\n Else;\r\n sEleNext = '';\r\n EndIf;\r\n HierarchyElementDelete( sDim, sCurrHierName, sEle );\r\n HierarchyElementInsert( sDim, sCurrHierName, sEleNext, sEle, 'C' );\r\n EndIf;\r\n nCtrEle = nCtrEle + 1;\r\n End;\r\n Else;\r\n # a delimited list of consolidations is given. Handle with recursive call and temp descendents attribute\r\n nDelimiterIndexB = 1;\r\n While( nDelimiterIndexB <> 0 );\r\n nDelimiterIndexB = Scan( pDelim, sEles );\r\n If( nDelimiterIndexB = 0 );\r\n sEle = sEles;\r\n Else;\r\n sEle = Trim( SubSt( sEles, 1, nDelimiterIndexB - 1 ) );\r\n sEles = Trim( Subst( sEles, nDelimiterIndexB + Long(pDelim), Long( sEles ) ) );\r\n EndIf;\r\n \r\n # Wildcard search string\r\n sEle = '\"'|sEle|'\"';\r\n sMdxEle = Expand('{TM1FILTERBYPATTERN( {TM1SUBSETALL([%sCurrHier%])}, %sEle% )}');\r\n \r\n If( HierarchySubsetExists( sDim, sCurrHierName, cTempSub ) = 1 );\r\n # If a delimited list of dim names includes wildcards then we may have to re-use the subset multiple times\r\n HierarchySubsetMDXSet( sDim, sCurrHierName, cTempSub, sMDXEle );\r\n Else;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSub, sMDXEle, sCurrHier, 1 );\r\n EndIf;\r\n \r\n # Loop through subset of Consolidated elements created based on wildcard\r\n nCountElems = HierarchySubsetGetSize(sDim, sCurrHierName, cTempSub);\r\n While( nCountElems >= 1 );\r\n sElement = HierarchySubsetGetElementName(sDim, sCurrHierName, cTempSub, nCountElems);\r\n ## Check that the element is consolidated and has children\r\n If( DType( sCurrHier, sElement ) @= 'C' & ElementComponentCount( sDim, sCurrHierName, sElement ) > 0 );\r\n If( pLogOutput = 1 );\r\n LogOutput( 'INFO', Expand( 'Process called recursively for \"%sElement%\" in hierarchy \"%sDim%:%sCurrHierName%\".' ) );\r\n EndIf;\r\n ExecuteProcess( cThisProcName, 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pDim', sDim, 'pHier', sCurrHierName,\r\n 'pConsol', sElement, 'pRecursive', pRecursive,\r\n 'pDelim', pDelim\r\n );\r\n EndIf;\r\n \r\n nCountElems = nCountElems - 1;\r\n End;\r\n End;\r\n EndIf;\r\n Endif;\r\n \r\n nCountHier = nCountHier - 1;\r\n End;\r\n \r\n EndIf;\r\n \r\n nCountDim = nCountDim - 1;\r\n End;\r\nEndIf;\r\n\r\n### End Prolog ###", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.hier.unwind', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pDim', '', 'pHier', '', 'pConsol', '*',\r\n \t'pRecursive', 0, 'pDelim', '&'\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock Ver 4~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will remove all children from a specific target consolidation (pConsol) in a Hierarchy\r\n# in target Dimension. If recursive (pRecursive=1), it will also unwind all consolidations that are \r\n# descendants of the target regardless of depth. If not recursive (pRecursive=0) then only immediate children\r\n# of the target consolidation will be removed.\r\n#\r\n# Use case: Intended for both production and development/prototyping scenarios.\r\n# 1. **Production** call prior to main dimension build process in case mapping relationships have changed to ensure no double-counting steming from leaf elements \r\n# rolling into multiple parents within the same rollup or hierarhcy\r\n# 2. **Production** combine with }bedrock.hier.emptyconsols.delete to remove orphaned rollups\r\n# 3. **Development** manual cleanup of dimensions during prototyping or prior to going to production\r\n#\r\n# Note:\r\n# * A valid source dimension name (pDim) is mandatory otherwise the process will abort.\r\n# * A blank pHier parameter will process _only the same named hierarchy_ for each of the dimensions processed.\r\n# * A \\* pConsol parameter will process ALL C level items in the given hierarchy (pHier).\r\n# * A delimited list or wildcard for pDim or pHier or a delimited list of consolidations for pConsol will result in recursive calls of the process.\r\n#\r\n# Caution: \r\n# If consolidations are also used in unrelated consolidations and recursive is selected this\r\n# will result in orphan consolidations in the other rollups.\r\n#EndRegion @DOC\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncTempSubOuter = '}OuterLoop_' | cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncTempSubInner = '}InnerLoop_' | cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent= 'Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncMsgInfoContent = 'User:%cUserName% Process:%cThisProcName% Message:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pHier:%pHier%, pConsol:%pConsol%, pRecursive:%pRecursive%, pDelim:%pDelim%.' ;\r\ncHierAttr = 'Bedrock.Descendant';\r\ncAttrVal = 'Descendant';\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pConsol\": \"*\",\r\n \"pDelim\": \"&\",\r\n \"pDim\": null,\r\n \"pHier\": \"\",\r\n \"pLogOutput\": 0,\r\n \"pRecursive\": null,\r\n \"pStrictErrorHandling\": 0\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pConsol\": '|StringToJson ( pConsol )|',\r\n \"pDelim\": '|StringToJson ( pDelim )|',\r\n \"pDim\": '|StringToJson ( pDim )|',\r\n \"pHier\": '|StringToJson ( pHier )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pRecursive\": '|NumberToString( pRecursive )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npConsol = JsonToString( JsonGet( pJson, 'pConsol' ) );\r\npDelim = JsonToString( JsonGet( pJson, 'pDelim' ) );\r\npDim = JsonToString( JsonGet( pJson, 'pDim' ) );\r\npHier = JsonToString( JsonGet( pJson, 'pHier' ) );\r\n# Numeric Parameters\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npRecursive = StringToNumber( JsonToString( JsonGet( pJson, 'pRecursive' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\nIf( Scan( '*', pDim ) = 0 & Scan( '?', pDim ) = 0 & Scan( pDelim, pDim ) = 0 & Scan( ':', pDim ) > 0 & pHier @= '' );\r\n # A hierarchy has been passed as dimension. Handle the input error by splitting dim:hier into dimension & hierarchy\r\n pHier = SubSt( pDim, Scan( ':', pDim ) + 1, Long( pDim ) );\r\n pDim = SubSt( pDim, 1, Scan( ':', pDim ) - 1 );\r\nEndIf;\r\n\r\n## Validate Source dimension\r\nIF( Trim( pDim ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No dimension specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIF( Scan( '*', pDim ) = 0 & Scan( '?', pDim ) = 0 & Scan( pDelim, pDim ) = 0 & DimensionExists( pDim ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid dimension: ' | pDim;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate hierarchy (can only validate hierarchy up front if dimension is fixed and doesn't contain wildcards)\r\nIF( Scan( '*', pDim ) = 0 & Scan( '?', pDim ) = 0 & Scan( pDelim, pDim ) = 0 & pHier @= '');\r\n pHier = pDim;\r\nElseIf( Scan( '*', pHier ) = 0 & Scan( '?', pHier ) = 0 & Scan( pDelim, pHier ) = 0 & pHier @<> '' & DimensionExists( pDim ) = 1 & HierarchyExists( pDim, pHier ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid dimension hierarchy: ' | pHier;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndif;\r\n\r\nIf( Trim( pHier ) @= '' );\r\n ## use same name as Dimension. Since wildcards are allowed, this is managed inside the code below\r\nEndIf;\r\n\r\n# Validate consol\r\nIf( pConsol @<> '');\r\n If( Scan( '*', pConsol ) = 0 & Scan( '?', pConsol ) = 0 & Scan( pDelim, pConsol ) = 0 & ElementIndex( pDim, pHier, pConsol ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Item ' | pConsol | ' does NOT exist. Please enter a valid consolidation element in the ' |pDim| ':' |pHier| ' dimension:hierarchy.'; \r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n ElseIf( Scan( '*', pConsol ) = 0 & Scan( '?', pConsol ) = 0 & Scan( pDelim, pConsol ) = 0 & ElementType( pDim, pHier, pConsol ) @<> 'C' );\r\n nErrors = 1;\r\n sMessage = 'Item ' | pConsol | ' is NOT a consolidated item. Please enter a valid consolidation element in the ' |pDim| ':' |pHier| ' dimension:hierarchy.'; \r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n ElseIf( Scan( '*', pConsol ) = 0 & Scan( '?', pConsol ) = 0 & Scan( pDelim, pConsol ) = 0 & ElementComponentCount( pDim, pHier, pConsol ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Invalid consolidation: ' | pConsol | ' has no children.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n Endif;\r\nElseIf( Trim( pConsol ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No consolidated element specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndif;\r\n\r\n# If blank delimiter specified then convert to default\r\nIf( pDelim @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nElse;\r\n # If subset required will be set later\r\n DataSourceType = 'NULL';\r\nEndIf;\r\n\r\n### If there is no separator and wildcard in the parameters, execute the unwind of the specific consolidated element\r\nIf( Scan( '*', pDim ) = 0 & Scan( '?', pDim ) = 0 & Scan( pDelim, pDim ) = 0 & Scan( '*', pHier ) = 0 & Scan( '?', pHier ) = 0 & Scan( pDelim, pHier ) = 0 & Scan( '*', pConsol ) = 0 & Scan( '?', pConsol ) = 0 & Scan( pDelim, pConsol ) = 0 );\r\n\r\n ### In case alias used for pConsol convert to principal name \r\n If( ElementIndex( pDim, pHier, pConsol ) > 0 );\r\n pConsol = HierarchyElementPrincipalName( pDim, pHier, pConsol );\r\n EndIf;\r\n \r\n ### Create Temp Descendent Attribute\r\n AttrDelete( pDim, cHierAttr );\r\n AttrInsert( pDim, '', cHierAttr, 'S' );\r\n \r\n ### Assign data source ###\r\n If( pRecursive = 1);\r\n # Set Descendent attribute value\r\n nElementIndex = 1;\r\n nElementCount = ElementCount( pDim , pHier );\r\n While( nElementIndex <= nElementCount );\r\n sElement = ElementName( pDim, pHier, nElementIndex );\r\n If( ElementIsAncestor( pDim, pHier, pConsol, sElement ) = 1 % pConsol @= sElement );\r\n ElementAttrPutS( cAttrVal, pDim, pHier, sElement, cHierAttr );\r\n EndIf;\r\n nElementIndex = nElementIndex + 1;\r\n End;\r\n # Assign Data Source\r\n DataSourceType = 'SUBSET';\r\n DatasourceNameForServer = pDim|':'|pHier;\r\n DatasourceNameForClient = pDim|':'|pHier;\r\n DatasourceDimensionSubset = 'ALL';\r\n Else;\r\n ### Remove direct children from the target consol ###\r\n If( ElementComponentCount( pDim, pHier, pConsol ) > 0 );\r\n If( pLogOutput = 1 );\r\n LogOutput( 'INFO', Expand( 'Deleting all components from consolidation %pConsol% in hierarchy \"%pHier%\" of \"%pDim%\" dimension.' ) );\r\n EndIf;\r\n nComp = ElementComponentCount( pDim, pHier, pConsol );\r\n While( nComp > 0 );\r\n sComp = ElementComponent( pDim, pHier, pConsol, nComp );\r\n HierarchyElementComponentDelete( pDim, pHier, pConsol, sComp );\r\n nComp = nComp - 1;\r\n End;\r\n EndIf;\r\n # No data source, straight to Epilog\r\n DataSourceType = 'NULL';\r\n EndIf;\r\n\r\n### If pConsol is \"*\" and there is no separator and wildcard in the pDim & pHier parameters then unwind the whole hierarchy\r\nElseIf( Scan( '*', pDim ) = 0 & Scan( '?', pDim ) = 0 & Scan( pDelim, pDim ) = 0 & Scan( '*', pHier ) = 0 & Scan( '?', pHier ) = 0 & Scan( pDelim, pHier ) = 0 & Trim( pConsol ) @= '*' );\r\n\r\n # as pConsol is * wildcard it doesn't matter if recursive or not. We unwind everything. As speed enhancement rather than removing children delete and add back C elements to empty children in one step (not steps = count of children)\r\n nMaxEle = ElementCount( pDim, pHier );\r\n nCtrEle = 1;\r\n While( nCtrEle <= nMaxEle );\r\n sEle = ElementName( pDim, pHier, nCtrEle);\r\n If( ElementComponentCount( pDim, pHier, sEle ) > 0 );\r\n If( nCtrEle < nMaxEle );\r\n sEleNext = ElementName( pDim, pHier, nCtrEle + 1 );\r\n Else;\r\n sEleNext = '';\r\n EndIf;\r\n HierarchyElementDelete( pDim, pHier, sEle );\r\n HierarchyElementInsert( pDim, pHier, sEleNext, sEle, 'C' );\r\n EndIf;\r\n nCtrEle = nCtrEle + 1;\r\n End;\r\n\r\n # since hierarchy already fully unwound no subset; datasource = NULL\r\n DataSourceType = 'NULL';\r\n\r\n## Otherwise, if there is a separator or wildcard in the parameters, tokenize the string and self-call the process recursively.\r\nElse;\r\n # No data source, straight to Epilog\r\n DataSourceType = 'NULL';\r\n \r\n # Loop through dimensions in pDim\r\n sDims = pDim;\r\n nDimDelimiterIndex = 1;\r\n sMdx = '';\r\n # Get 1st dimension\r\n While( nDimDelimiterIndex <> 0 );\r\n # Extract 1st dimension > sDim\r\n nDimDelimiterIndex = Scan( pDelim, sDims );\r\n If( nDimDelimiterIndex = 0 );\r\n sDim = sDims;\r\n Else;\r\n sDim = Trim( SubSt( sDims, 1, nDimDelimiterIndex - 1 ) );\r\n sDims = Trim( Subst( sDims, nDimDelimiterIndex + Long(pDelim), Long( sDims ) ) );\r\n EndIf;\r\n \r\n # Create subset of dimensions using Wildcard to loop through dimensions in pDim with wildcard\r\n sDimExp = '\"'|sDim|'\"';\r\n sMdxPart = Expand('{TM1FILTERBYPATTERN( EXCEPT( TM1SUBSETALL( [}Dimensions].[}Dimensions] ), TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions].[}Dimensions] ) , \"*:*\") ) , %sDimExp% )}');\r\n If( sMdx @= ''); \r\n sMdx = sMdxPart; \r\n Else;\r\n sMdx = sMdx | ' + ' | sMdxPart;\r\n EndIf;\r\n End;\r\n \r\n If( SubsetExists( '}Dimensions' , cTempSubOuter ) = 1 );\r\n # If a delimited list of dim names includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( '}Dimensions' , cTempSubOuter, sMDX );\r\n Else;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSubOuter, sMDX, '}Dimensions' , 1 );\r\n EndIf;\r\n \r\n # Loop through dimensions in subset created based on wildcard\r\n nCountDim = SubsetGetSize( '}Dimensions' , cTempSubOuter );\r\n While( nCountDim >= 1 );\r\n sDim = SubsetGetElementName( '}Dimensions' , cTempSubOuter, nCountDim );\r\n # Validate dimension name\r\n If( DimensionExists(sDim) = 0 );\r\n nErrors = 1;\r\n sMessage = Expand( 'Dimension \"%sDim%\" does not exist.' );\r\n LogOutput( 'ERROR', Expand( cMsgErrorContent ) );\r\n Else;\r\n If( pLogOutput = 1 );\r\n sMessage = Expand( 'Dimension \"%sDim%\" being processed....' );\r\n LogOutput( 'INFO', Expand( cMsgInfoContent ) );\r\n EndIf;\r\n # Loop through hierarchies in pHier\r\n If( Trim( pHier ) @= '' );\r\n ### Use main hierarchy for each dimension if pHier is empty\r\n sHierarchies = sDim;\r\n Else;\r\n sHierarchies = pHier;\r\n EndIf;\r\n nDelimiterIndexA = 1;\r\n sHierDim = '}Dimensions' ;\r\n sMdxHier = '';\r\n While( nDelimiterIndexA <> 0 );\r\n nDelimiterIndexA = Scan( pDelim, sHierarchies );\r\n If( nDelimiterIndexA = 0 );\r\n sHierarchy = sHierarchies;\r\n Else;\r\n sHierarchy = Trim( SubSt( sHierarchies, 1, nDelimiterIndexA - 1 ) );\r\n sHierarchies = Trim( Subst( sHierarchies, nDelimiterIndexA + Long(pDelim), Long( sHierarchies ) ) );\r\n EndIf;\r\n \r\n # Create subset of Hierarchies using Wildcard\r\n If( sDim @= sHierarchy );\r\n sHierExp = '\"'| sDim |'\"';\r\n Else;\r\n sHierExp = '\"'| sDim | ':' | sHierarchy|'\"';\r\n EndIf;\r\n sMdxHierPart = Expand('{TM1FILTERBYPATTERN( {TM1SUBSETALL([%sHierDim%].[%sHierDim%])}, %sHierExp% )}');\r\n If( sMdxHier @= ''); \r\n sMdxHier = sMdxHierPart; \r\n Else;\r\n sMdxHier = sMdxHier | ' + ' | sMdxHierPart;\r\n EndIf;\r\n End;\r\n \r\n # include the named hierarchy in case ALL hierachies\r\n If( Trim(pHier) @= '*' );\r\n sMdxHier = Expand('{[%sHierDim%].[%sHierDim%].[%sDim%]} + %sMdxHier%');\r\n EndIf;\r\n \r\n If( SubsetExists( sHierDim, cTempSubInner ) = 1 );\r\n # If a delimited list of hierarchy names includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( sHierDim, cTempSubInner, sMdxHier );\r\n Else;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSubInner, sMdxHier, sHierDim, 1 );\r\n EndIf;\r\n\r\n # Loop through subset of hierarchies created based on wildcard\r\n nCountHier = SubsetGetSize( sHierDim, cTempSubInner );\r\n While( nCountHier >= 1 );\r\n sCurrHier = SubsetGetElementName( sHierDim, cTempSubInner, nCountHier );\r\n sCurrHierName = Subst( sCurrHier, Scan(':', sCurrHier)+1, Long(sCurrHier) );\r\n # Validate hierarchy name in sHierDim\r\n If( Dimix( sHierDim , sCurrHier ) = 0 );\r\n sMessage = Expand('The \"%sCurrHier%\" hierarchy does NOT exist in the \"%sDim%\" dimension.');\r\n LogOutput( 'INFO' , Expand( cMsgInfoContent ) );\r\n ElseIf( sCurrHierName @= 'Leaves' );\r\n sMessage = Expand('Skipping %sCurrHier% hierarchy. No need to unwind!');\r\n If( pLogOutput = 1 );\r\n LogOutput( 'INFO', Expand( cMsgInfoContent ) );\r\n EndIf;\r\n Else;\r\n If( pLogOutput = 1 );\r\n sMessage = Expand( 'Hierarchy \"%sCurrHierName%\" in Dimension \"%sDim%\" being processed....' );\r\n LogOutput( 'INFO', Expand( cMsgInfoContent ) );\r\n EndIf;\r\n # Loop through consolidated elements in pConsol\r\n sEles = Trim( pConsol );\r\n If( sEles @= '*' );\r\n # no need for recursive call for ALL wildcard. We can just unwind whole hierarchy\r\n nMaxEle = ElementCount( sDim, sCurrHierName );\r\n nCtrEle = 1;\r\n While( nCtrEle <= nMaxEle );\r\n sEle = ElementName( sDim, sCurrHierName, nCtrEle);\r\n If( ElementComponentCount( sDim, sCurrHierName, sEle ) > 0 );\r\n If( nCtrEle < nMaxEle );\r\n sEleNext = ElementName( sDim, sCurrHierName, nCtrEle + 1 );\r\n Else;\r\n sEleNext = '';\r\n EndIf;\r\n HierarchyElementDelete( sDim, sCurrHierName, sEle );\r\n HierarchyElementInsert( sDim, sCurrHierName, sEleNext, sEle, 'C' );\r\n EndIf;\r\n nCtrEle = nCtrEle + 1;\r\n End;\r\n Else;\r\n # a delimited list of consolidations is given. Handle with recursive call and temp descendents attribute\r\n nDelimiterIndexB = 1;\r\n While( nDelimiterIndexB <> 0 );\r\n nDelimiterIndexB = Scan( pDelim, sEles );\r\n If( nDelimiterIndexB = 0 );\r\n sEle = sEles;\r\n Else;\r\n sEle = Trim( SubSt( sEles, 1, nDelimiterIndexB - 1 ) );\r\n sEles = Trim( Subst( sEles, nDelimiterIndexB + Long(pDelim), Long( sEles ) ) );\r\n EndIf;\r\n \r\n # Wildcard search string\r\n sEle = '\"'|sEle|'\"';\r\n sMdxEle = Expand('{TM1FILTERBYPATTERN( {TM1SUBSETALL([%sCurrHier%])}, %sEle% )}');\r\n \r\n If( HierarchySubsetExists( sDim, sCurrHierName, cTempSub ) = 1 );\r\n # If a delimited list of dim names includes wildcards then we may have to re-use the subset multiple times\r\n HierarchySubsetMDXSet( sDim, sCurrHierName, cTempSub, sMDXEle );\r\n Else;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSub, sMDXEle, sCurrHier, 1 );\r\n EndIf;\r\n \r\n # Loop through subset of Consolidated elements created based on wildcard\r\n nCountElems = HierarchySubsetGetSize(sDim, sCurrHierName, cTempSub);\r\n While( nCountElems >= 1 );\r\n sElement = HierarchySubsetGetElementName(sDim, sCurrHierName, cTempSub, nCountElems);\r\n ## Check that the element is consolidated and has children\r\n If( DType( sCurrHier, sElement ) @= 'C' & ElementComponentCount( sDim, sCurrHierName, sElement ) > 0 );\r\n If( pLogOutput = 1 );\r\n LogOutput( 'INFO', Expand( 'Process called recursively for \"%sElement%\" in hierarchy \"%sDim%:%sCurrHierName%\".' ) );\r\n EndIf;\r\n ExecuteProcess( cThisProcName, 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pDim', sDim, 'pHier', sCurrHierName,\r\n 'pConsol', sElement, 'pRecursive', pRecursive,\r\n 'pDelim', pDelim\r\n );\r\n EndIf;\r\n \r\n nCountElems = nCountElems - 1;\r\n End;\r\n End;\r\n EndIf;\r\n Endif;\r\n \r\n nCountHier = nCountHier - 1;\r\n End;\r\n \r\n EndIf;\r\n \r\n nCountDim = nCountDim - 1;\r\n End;\r\nEndIf;\r\n\r\n### End Prolog ###", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n### Check for errors in prolog ###\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### If Leaf or already unwound then skip\r\nIf( ElementComponentCount( pDim, pHier, vElement ) = 0 );\r\n ItemSkip;\r\nEndIf;\r\n \r\n### Break all parent/child links below target consol ###\r\nIf( pConsol @= '*' );\r\n sAttrVal = cAttrVal;\r\nElse;\r\n sAttrVal = ElementAttrS( pDim, pHier, vElement, cHierAttr );\r\nEndIf;\r\n\r\nIf( sAttrVal @= cAttrVal );\r\n bFastUnwind = 1;\r\n\r\n # Cannot check nPars > 1 as due to ordering of elements processes some parents may have already been removed\r\n nPars = ElementParentCount( pDim, pHier, vElement );\r\n nPar = 1;\r\n While( nPar <= nPars );\r\n sPar = ElementParent( pDim, pHier, vElement, nPar );\r\n If( ElementAttrS( pDim, pHier, sPar, cHierAttr ) @<> cAttrVal );\r\n # Parent does not belong to unwinding intersection. Cannot delete C children, must unwind.\r\n bFastUnwind = 0;\r\n EndIf;\r\n nPar = nPar + 1;\r\n End;\r\n \r\n If( bFastUnwind = 1 );\r\n # delete and recreate C element (Fast)\r\n sEleNext = ElementName( pDim, pHier, ElementIndex( pDim, pHier, vElement ) + 1 );\r\n HierarchyElementDelete( pDim, pHier, vElement );\r\n HierarchyElementInsert( pDim, pHier, sEleNext, vElement, 'C' );\r\n Else;\r\n # unwind C element without deletion (Slow for consols with many children)\r\n nComp = ElementComponentCount( pDim, pHier, vElement );\r\n While( nComp > 0 );\r\n sComp = ElementComponent( pDim, pHier, vElement, nComp );\r\n HierarchyElementComponentDelete( pDim, pHier, vElement, sComp );\r\n nComp = nComp - 1;\r\n End;\r\n EndIf;\r\n \r\nEndIf;\r\n\r\n### End Metadata ###", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\nElse;\r\n\r\n ### Remove Descendent attribute\r\n IF( Scan( '*', pDim ) = 0 & Scan( '?', pDim ) = 0 & Scan( pDelim, pDim ) = 0 & Scan( '*', pHier ) = 0 & Scan( '?', pHier ) = 0 & Scan( pDelim, pHier ) = 0 & Scan( '*', pConsol ) = 0 & Scan( '?', pConsol ) = 0 & Scan( pDelim, pConsol ) = 0 );\r\n AttrDelete( pDim, cHierAttr );\r\n EndIf;\r\nEndIf;\r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully unwound the appropriate consolidated items the %pDim%:%pHier% dimension:hierarchy.' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n### End Epilog ###", @@ -13,47 +13,53 @@ "subset": "All" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pDim", - "Prompt": "REQUIRED: Target Dimension, accepts wildcards (if = *, then all the dimensions)", + "Prompt": "REQUIRED: Delimited list of dimensions", "Value": "", "Type": "String" }, { "Name": "pHier", - "Prompt": "OPTIONAL: Target Hierarchy (will use default is left blank), accepts wildcards (if = *, then all hierarchies)", + "Prompt": "OPTIONAL: Hierarchy name (Default = pDim)", "Value": "", "Type": "String" }, { "Name": "pConsol", - "Prompt": "OPTIONAL: Target Consolidation, accepts wildcards ( * will unwind ALL)", + "Prompt": "OPTIONAL: Delimited list of target consolidations for Unwinding (Default = '*')", "Value": "*", "Type": "String" }, { "Name": "pRecursive", - "Prompt": "REQUIRED: Boolean: 1 = True (break from node down not just direct children)", + "Prompt": "REQUIRED: Break all descendants, not just direct children (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { "Name": "pDelim", - "Prompt": "OPTIONAL: delimiter character for element list (default value if blank = '&')", + "Prompt": "OPTIONAL: Delimiter for list parameters (Default = '&')", "Value": "&", "Type": "String" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [ diff --git a/bedrock_processes_json/}bedrock.process.template.json b/bedrock_processes_json/}bedrock.process.template.json index f932f36..04691bb 100644 --- a/bedrock_processes_json/}bedrock.process.template.json +++ b/bedrock_processes_json/}bedrock.process.template.json @@ -11,21 +11,21 @@ }, "Parameters": [ { - "Name": "pLogOutput", - "Prompt": "Write status messages to tm1server.log file?", - "Value": 0, + "Name": "pTemp", + "Prompt": "OPTIONAL: Delete/create temporary objects (0 = Do not delete, 1 = Delete, 2 = if view and subsets are created, keep only subsets)", + "Value": 1, "Type": "Numeric" }, { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { - "Name": "pTemp", - "Prompt": "Use temporary objects for views & subsets?", - "Value": 1, + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, "Type": "Numeric" } ], diff --git a/bedrock_processes_json/}bedrock.security.client.clone.json b/bedrock_processes_json/}bedrock.security.client.clone.json index 0e351eb..3b2186d 100644 --- a/bedrock_processes_json/}bedrock.security.client.clone.json +++ b/bedrock_processes_json/}bedrock.security.client.clone.json @@ -1,56 +1,62 @@ { "Name": "}bedrock.security.client.clone", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.security.client.clone', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pSrcClient', '', 'pTgtClient', '',\r\n \t'pMode', 'REPLACE', 'pDelim', '&'\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will copy security from one user to another. Target client(s) will be created if it doesn't exist.\r\n\r\n# Use case: Intended for production.\r\n# 1/ When a company hires new employees their profile can be set up by cloning an existing employee.\r\n\r\n# Note:\r\n# Naturally, a valid source client (pSrcClient) is mandatory otherwise the process will abort.\r\n# Also, a valid target client(s) (pTgtClient) must be specified, otherwise the process will abort:\r\n# - Multiple target clients can be specified separated by a delimiter.\r\n# - If target client doesn't already exist then Bedrock.Security.Client.Create will be called.\r\n# - The process has 2 modes REPLACE (default) clears any existing group memberships. ADD only adds new ones. \r\n#EndRegion @DOC\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\nsRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncUserName = TM1User();\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pSrcClient:%pSrcClient%, pTgtClient:%pTgtClient%, pMode:%pMode%, pDelim:%pDelim%.' ; \r\n \r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\n# If blank delimiter specified then convert to default\r\nIf( pDelim @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\n# If blank mode specified then convert to default\r\nIf( pMode @= '' );\r\n pMode = 'REPLACE';\r\nEndIf;\r\n\r\n# If unsupported mode specified then abort\r\nIf( pMode @= 'ADD' % pMode @= 'REPLACE' );\r\n # all is OK\r\nElse; \r\n nErrors = 1;\r\n sMessage = 'Invalid mode specified. Must be ADD or REPLACE';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# If no source client has been specified then terminate process\r\nIf( Trim( pSrcClient ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No source client specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( DimIx( '}Clients', pSrcClient ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Source client does not exist';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElse;\r\n pSrcClient = DimensionElementPrincipalName( '}Clients', pSrcClient );\r\nEndIf;\r\n\r\n# If no target clients have been specified then terminate process\r\nIf( Trim( pTgtClient ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No target client(s) specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( DimIx( '}Clients', pTgtClient ) > 0 );\r\n pTgtClient = DimensionElementPrincipalName( '}Clients', pTgtClient );\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### Split pClients into individual Clients and add only if they don't exist ###\r\n\r\nsClients = Trim( pTgtClient );\r\nnDelimiterIndex = 1;\r\n\r\n# loop delimited string of target clients\r\nWhile( nDelimiterIndex <> 0 );\r\n nDelimiterIndex = Scan( pDelim, sClients );\r\n If( nDelimiterIndex = 0 );\r\n sClient = sClients;\r\n Else;\r\n sClient = Trim( SubSt( sClients, 1, nDelimiterIndex - 1 ) );\r\n sClients = Trim( Subst( sClients, nDelimiterIndex + Long(pDelim), Long( sClients ) ) );\r\n EndIf;\r\n # Don't attempt to add a blank client\r\n If( sClient @<> '' );\r\n If( DimIx( '}Clients', sClient ) = 0 );\r\n ExecuteProcess( '}bedrock.security.client.create', 'pStrictErrorHandling', pStrictErrorHandling, 'pClient', sClient);\r\n EndIf;\r\n EndIf;\r\nEnd;\r\n\r\n\r\n### End Prolog ###", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.security.client.clone', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pSrcClient', '', 'pTgtClient', '',\r\n \t'pMode', 'REPLACE', 'pDelim', '&'\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will copy security from one user to another. Target client(s) will be created if it doesn't exist.\r\n\r\n# Use case: Intended for production.\r\n# 1/ When a company hires new employees their profile can be set up by cloning an existing employee.\r\n\r\n# Note:\r\n# Naturally, a valid source client (pSrcClient) is mandatory otherwise the process will abort.\r\n# Also, a valid target client(s) (pTgtClient) must be specified, otherwise the process will abort:\r\n# - Multiple target clients can be specified separated by a delimiter.\r\n# - If target client doesn't already exist then Bedrock.Security.Client.Create will be called.\r\n# - The process has 2 modes REPLACE (default) clears any existing group memberships. ADD only adds new ones. \r\n#EndRegion @DOC\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\nsRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncUserName = TM1User();\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pSrcClient:%pSrcClient%, pTgtClient:%pTgtClient%, pMode:%pMode%, pDelim:%pDelim%.' ;\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pDelim\": \"&\",\r\n \"pMode\": \"Replace\",\r\n \"pSrcClient\": null,\r\n \"pTgtClient\": null,\r\n \"pLogOutput\": 0,\r\n \"pStrictErrorHandling\": 0\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pDelim\": '|StringToJson ( pDelim )|',\r\n \"pMode\": '|StringToJson ( pMode )|',\r\n \"pSrcClient\": '|StringToJson ( pSrcClient )|',\r\n \"pTgtClient\": '|StringToJson ( pTgtClient )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npDelim = JsonToString( JsonGet( pJson, 'pDelim' ) );\r\npMode = JsonToString( JsonGet( pJson, 'pMode' ) );\r\npSrcClient = JsonToString( JsonGet( pJson, 'pSrcClient' ) );\r\npTgtClient = JsonToString( JsonGet( pJson, 'pTgtClient' ) );\r\n# Numeric Parameters\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\n# If blank delimiter specified then convert to default\r\nIf( pDelim @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\n# If blank mode specified then convert to default\r\nIf( pMode @= '' );\r\n pMode = 'REPLACE';\r\nEndIf;\r\n\r\n# If unsupported mode specified then abort\r\nIf( pMode @= 'ADD' % pMode @= 'REPLACE' );\r\n # all is OK\r\nElse; \r\n nErrors = 1;\r\n sMessage = 'Invalid mode specified. Must be ADD or REPLACE';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# If no source client has been specified then terminate process\r\nIf( Trim( pSrcClient ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No source client specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( DimIx( '}Clients', pSrcClient ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Source client does not exist';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElse;\r\n pSrcClient = DimensionElementPrincipalName( '}Clients', pSrcClient );\r\nEndIf;\r\n\r\n# If no target clients have been specified then terminate process\r\nIf( Trim( pTgtClient ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No target client(s) specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( DimIx( '}Clients', pTgtClient ) > 0 );\r\n pTgtClient = DimensionElementPrincipalName( '}Clients', pTgtClient );\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### Split pClients into individual Clients and add only if they don't exist ###\r\n\r\nsClients = Trim( pTgtClient );\r\nnDelimiterIndex = 1;\r\n\r\n# loop delimited string of target clients\r\nWhile( nDelimiterIndex <> 0 );\r\n nDelimiterIndex = Scan( pDelim, sClients );\r\n If( nDelimiterIndex = 0 );\r\n sClient = sClients;\r\n Else;\r\n sClient = Trim( SubSt( sClients, 1, nDelimiterIndex - 1 ) );\r\n sClients = Trim( Subst( sClients, nDelimiterIndex + Long(pDelim), Long( sClients ) ) );\r\n EndIf;\r\n # Don't attempt to add a blank client\r\n If( sClient @<> '' );\r\n If( DimIx( '}Clients', sClient ) = 0 );\r\n ExecuteProcess( '}bedrock.security.client.create', 'pStrictErrorHandling', pStrictErrorHandling, 'pClient', sClient);\r\n EndIf;\r\n EndIf;\r\nEnd;\r\n\r\n\r\n### End Prolog ###", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n\r\n### Update group memberships ###\r\nsClients = Trim( pTgtClient );\r\nnDelimiterIndex = 1;\r\n\r\n# loop delimited string of target clients\r\nWhile( nDelimiterIndex <> 0 );\r\n nDelimiterIndex = Scan( pDelim, sClients );\r\n If( nDelimiterIndex = 0 );\r\n sClient = sClients;\r\n Else;\r\n sClient = Trim( SubSt( sClients, 1, nDelimiterIndex - 1 ) );\r\n sClients = Trim( Subst( sClients, nDelimiterIndex + Long(pDelim), Long( sClients ) ) );\r\n EndIf;\r\n If( DimIx( '}Clients', sClient ) >= 1 );\r\n sClient = DimensionElementPrincipalName( '}Clients', sClient );\r\n # loop all security groups\r\n nGroupIndex = 1;\r\n nMaxGroups = DimSiz( '}Groups' );\r\n While( nGroupIndex <= nMaxGroups );\r\n sGroup = DimNm( '}Groups', nGroupIndex );\r\n If( sGroup @= CellGetS( '}ClientGroups', pSrcClient, sGroup ) );\r\n AssignClientToGroup( sClient, sGroup );\r\n Else;\r\n If( pMode @= 'REPLACE' );\r\n # don't need to check if user in group. If user not in group then no error with RemoveClientFromGroup function\r\n RemoveClientFromGroup( sClient, sGroup );\r\n EndIf;\r\n EndIf;\r\n nGroupIndex = nGroupIndex + 1;\r\n # exit loop of }Groups \r\n End;\r\n EndIf;\r\n # exit loop of target clients \r\nEnd;\r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully cloned %pSrcClient% to %pTgtClient% by %pMode%.' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n### End Epilog ###", "HasSecurityAccess": true, - "UIData": "_ParameterConstraints=e30=\f", + "UIData": "", "DataSource": { "Type": "None" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pSrcClient", - "Prompt": "REQUIRED: Source Client", + "Prompt": "REQUIRED: Source client", "Value": "", "Type": "String" }, { "Name": "pTgtClient", - "Prompt": "REQUIRED: List of Target Clients Separated by Delimiter", + "Prompt": "REQUIRED: Delimited list of target client", "Value": "", "Type": "String" }, { "Name": "pMode", - "Prompt": "OPTIONAL: Mode REPLACE or ADD (default = REPLACE)", - "Value": "REPLACE", + "Prompt": "OPTIONAL: 'Add' or 'Replace' (Default = 'Replace')", + "Value": "Replace", "Type": "String" }, { "Name": "pDelim", - "Prompt": "OPTIONAL: Delimiter (Use for a list of target users. Defaults to & if blank.)", + "Prompt": "OPTIONAL: Delimiter for list parameters (Default = '&')", "Value": "&", "Type": "String" }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, { "Name": "pPassword", - "Prompt": "OBSOLETE: This parameter does nothing and is only included for backwards compatability", + "Prompt": "OBSOLETE: This parameter does nothing and is only included for backwards compatibility", "Value": "", "Type": "String" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [], diff --git a/bedrock_processes_json/}bedrock.security.client.create.json b/bedrock_processes_json/}bedrock.security.client.create.json index ed819e8..bb75016 100644 --- a/bedrock_processes_json/}bedrock.security.client.create.json +++ b/bedrock_processes_json/}bedrock.security.client.create.json @@ -1,50 +1,56 @@ { "Name": "}bedrock.security.client.create", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.security.client.create', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n\t 'pClient', '', 'pAlias', '', 'pPassword', '', 'pDelim', '&' \r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will create clients and max ports.\r\n\r\n# Use case: Intended for production.\r\n# 1/ Create clients for multiple new hires simultaneously.\r\n\r\n# Note:\r\n# Naturally, a client (pClient) is mandatory otherwise the process will abort.\r\n# - Multiple clients can be specified separated by a delimiter.\r\n# - If client already exists then the process will not attempt to re-create it but will reset max ports.\r\n# - Each client will have to be assigned to a group afterwards.\r\n#EndRegion @DOC\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncUserName = TM1User();\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pClient:%pClient%, pPassword:******, pDelim:%pDelim%.' ; \r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\n# If blank delimiter specified then convert to default\r\nIf( pDelim @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\n# If no clients have been specified then terminate process\r\nIf( Trim( pClient ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No clients specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n# Alias\r\nIf( pAlias @<> '' );\r\n If( DimensionExists( '}ElementAttributes_}Clients' ) = 0 );\r\n AttrInsert( '}Clients', '', '}TM1_DefaultDisplayValue', 'A' );\r\n ElseIf( DimIx( '}ElementAttributes_}Clients', '}TM1_DefaultDisplayValue' ) = 0 );\r\n AttrInsert( '}Clients', '', '}TM1_DefaultDisplayValue', 'A' );\r\n EndIf;\r\nEndIf;\r\n\r\n### Split pClient into individual Clients and add ###\r\nsClients = pClient;\r\nnDelimiterIndex = 1;\r\nWhile( nDelimiterIndex <> 0 );\r\n nDelimiterIndex = Scan( pDelim, sClients );\r\n If( nDelimiterIndex = 0 );\r\n sClient = sClients;\r\n Else;\r\n sClient = Trim( SubSt( sClients, 1, nDelimiterIndex - 1 ) );\r\n sClients = Trim( Subst( sClients, nDelimiterIndex + Long(pDelim), Long( sClients ) ) );\r\n EndIf;\r\n # Don't attempt to add a blank client\r\n If( sClient @<> '' );\r\n If( DimIx( '}Clients', sClient ) = 0 );\r\n If( nErrors = 0 );\r\n AddClient( sClient );\r\n EndIf;\r\n EndIf;\r\n EndIf;\r\nEnd;\r\n\r\nIf( nErrors = 0 );\r\n DimensionSortOrder( '}Clients', 'ByName', 'Ascending', 'ByName' , 'Ascending' );\r\nEndIf;\r\n\r\n\r\n### End Prolog ###", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.security.client.create', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n\t 'pClient', '', 'pAlias', '', 'pPassword', '', 'pDelim', '&' \r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will create clients and max ports.\r\n\r\n# Use case: Intended for production.\r\n# 1/ Create clients for multiple new hires simultaneously.\r\n\r\n# Note:\r\n# Naturally, a client (pClient) is mandatory otherwise the process will abort.\r\n# - Multiple clients can be specified separated by a delimiter.\r\n# - If client already exists then the process will not attempt to re-create it but will reset max ports.\r\n# - Each client will have to be assigned to a group afterwards.\r\n#EndRegion @DOC\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncUserName = TM1User();\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pClient:%pClient%, pPassword:******, pDelim:%pDelim%.' ;\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pAlias\": \"\",\r\n \"pClient\": null,\r\n \"pDelim\": \"&\",\r\n \"pLogOutput\": 0,\r\n \"pStrictErrorHandling\": 0\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pAlias\": '|StringToJson ( pAlias )|',\r\n \"pClient\": '|StringToJson ( pClient )|',\r\n \"pDelim\": '|StringToJson ( pDelim )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npAlias = JsonToString( JsonGet( pJson, 'pAlias' ) );\r\npClient = JsonToString( JsonGet( pJson, 'pClient' ) );\r\npDelim = JsonToString( JsonGet( pJson, 'pDelim' ) );\r\n# Numeric Parameters\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\n# If blank delimiter specified then convert to default\r\nIf( pDelim @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\n# If no clients have been specified then terminate process\r\nIf( Trim( pClient ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No clients specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n# Alias\r\nIf( pAlias @<> '' );\r\n If( DimensionExists( '}ElementAttributes_}Clients' ) = 0 );\r\n AttrInsert( '}Clients', '', '}TM1_DefaultDisplayValue', 'A' );\r\n ElseIf( DimIx( '}ElementAttributes_}Clients', '}TM1_DefaultDisplayValue' ) = 0 );\r\n AttrInsert( '}Clients', '', '}TM1_DefaultDisplayValue', 'A' );\r\n EndIf;\r\nEndIf;\r\n\r\n### Split pClient into individual Clients and add ###\r\nsClients = pClient;\r\nnDelimiterIndex = 1;\r\nWhile( nDelimiterIndex <> 0 );\r\n nDelimiterIndex = Scan( pDelim, sClients );\r\n If( nDelimiterIndex = 0 );\r\n sClient = sClients;\r\n Else;\r\n sClient = Trim( SubSt( sClients, 1, nDelimiterIndex - 1 ) );\r\n sClients = Trim( Subst( sClients, nDelimiterIndex + Long(pDelim), Long( sClients ) ) );\r\n EndIf;\r\n # Don't attempt to add a blank client\r\n If( sClient @<> '' );\r\n If( DimIx( '}Clients', sClient ) = 0 );\r\n If( nErrors = 0 );\r\n AddClient( sClient );\r\n EndIf;\r\n EndIf;\r\n EndIf;\r\nEnd;\r\n\r\nIf( nErrors = 0 );\r\n DimensionSortOrder( '}Clients', 'ByName', 'Ascending', 'ByName' , 'Ascending' );\r\nEndIf;\r\n\r\n\r\n### End Prolog ###", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n\r\n### Update password & Alias\r\n\r\nIf( nErrors = 0 );\r\n\r\n sAliases = pAlias;\r\n sClients = pClient;\r\n nDelimiterIndex = 1;\r\n\r\n While( nDelimiterIndex > 0 );\r\n nDelimiterIndex = Scan( pDelim, sAliases );\r\n If( nDelimiterIndex = 0 );\r\n sAlias = sAliases;\r\n Else;\r\n sAlias = Trim( SubSt( sAliases, 1, nDelimiterIndex - 1 ) );\r\n sAliases = Trim( Subst( sAliases, nDelimiterIndex + Long(pDelim), Long( sAliases ) ) );\r\n EndIf;\r\n nDelimiterIndex = Scan( pDelim, sClients );\r\n If( nDelimiterIndex = 0 );\r\n sClient = sClients;\r\n Else;\r\n sClient = Trim( SubSt( sClients, 1, nDelimiterIndex - 1 ) );\r\n sClients = Trim( Subst( sClients, nDelimiterIndex + Long(pDelim), Long( sClients ) ) );\r\n EndIf;\r\n \r\n If( DimIx( '}Clients', sClient ) > 0 );\r\n If( sAlias @<> '' );\r\n AttrPutS( sAlias, '}Clients', sClient, '}TM1_DefaultDisplayValue', 1 );\r\n EndIf;\r\n EndIf;\r\n End;\r\n\r\nEndIf;\r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully added user(s) %pClient% to }Clients Dimension.' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n### End Epilog ###", "HasSecurityAccess": true, - "UIData": "_ParameterConstraints=e30=\f", + "UIData": "", "DataSource": { "Type": "None" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pClient", - "Prompt": "REQUIRED: Single user name or list of users separated by delimiter", + "Prompt": "REQUIRED: Delimited list of clients", "Value": "", "Type": "String" }, { "Name": "pAlias", - "Prompt": "OPTIONAL: single or delimited list of }TM1_DefaultDisplayValue alias to assign to user (if list of users then size of list of aliases must be the same!)", + "Prompt": "OPTIONAL: Set alias for subset", "Value": "", "Type": "String" }, { "Name": "pDelim", - "Prompt": "OPTIONAL: Delimiter (Blank = &)", + "Prompt": "OPTIONAL: Delimiter for list parameters (Default = '&')", "Value": "&", "Type": "String" }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, { "Name": "pPassword", - "Prompt": "OBSOLETE: This parameter does nothing and is only included for backwards compatability", + "Prompt": "OBSOLETE: This parameter does nothing and is only included for backwards compatibility", "Value": "", "Type": "String" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [], diff --git a/bedrock_processes_json/}bedrock.security.client.delete.json b/bedrock_processes_json/}bedrock.security.client.delete.json index c934b35..bdd9896 100644 --- a/bedrock_processes_json/}bedrock.security.client.delete.json +++ b/bedrock_processes_json/}bedrock.security.client.delete.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.security.client.delete", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n\tExecuteProcess( '}bedrock.security.client.delete', 'pLogOutput', pLogOutput,\r\n\t 'pStrictErrorHandling', pStrictErrorHandling,\r\n\t 'pClient', '', 'pDelim', '&'\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will delete clients.\r\n\r\n# Use case: Intended for development and production.\r\n# 1/ Clean up users after go live.\r\n# 2/ Remove old employees from the system on termination.\r\n\r\n# Note:\r\n# Naturally, a valid client(s) (pClient) is mandatory otherwise the process will abort:\r\n# - Multiple clients can be specified separated by a delimiter. \r\n#EndRegion @DOC\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName | '_' | cTimeStamp | '_' | cRandomInt;\r\ncTempFile = GetProcessErrorFileDirectory | cTempSub | '.csv';\r\ncClientDim = '}Clients';\r\ncClientHier = cClientDim;\r\ncUserName = TM1User();\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgInfoLevel = 'INFO';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pClient:%pClient%, pDelim:%pDelim%.' ; \r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\n# If blank delimiter specified then convert to default\r\nIf( pDelim @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\n# If no clients have been specified then terminate process\r\nIf( Trim( pClient ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No clients specified';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Check alias exists\r\nIf( DimensionExists('}ElementAttributes_'|cClientDim) = 0 % DimIx('}ElementAttributes_'|cClientDim, '}TM1_DefaultDisplayValue') = 0 );\r\n AttrInsert( cClientDim, '', '}TM1_DefaultDisplayValue', 'A' );\r\nEndIf;\r\n\r\n### Split pClient into individual clients and delete ###\r\n#sClients = pClient;\r\n#nDelimiterIndex = 1;\r\n#While( nDelimiterIndex <> 0 );\r\n# nDelimiterIndex = Scan( pDelim, sClients );\r\n# If( nDelimiterIndex = 0 );\r\n# sClient = sClients;\r\n# Else;\r\n# sClient = Trim( SubSt( sClients, 1, nDelimiterIndex - 1 ) );\r\n# sClients = Trim( Subst( sClients, nDelimiterIndex + Long(pDelim), Long( sClients ) ) );\r\n# EndIf;\r\n# \r\n# If( Scan( '*', sClient ) = 0);\r\n# If( sClient @<> '' );\r\n# If( DimIx( cClientDim, sClient ) <> 0 );\r\n# sClient = DimensionElementPrincipalName(cClientDim,sClient);\r\n# If( sClient @<> 'Admin' & sClient @<> TM1User() );\r\n# DeleteClient(sClient);\r\n# ElseIf( sClient @= 'Admin' );\r\n# nErrors = 1;\r\n# sMessage = 'Skipping attempt to delete Admin user.';\r\n# LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n# ElseIf( sClient @= TM1User() );\r\n# nErrors = 1;\r\n# sMessage = 'Skipping attempt to delete self.';\r\n# LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n# EndIf;\r\n# Else;\r\n# nErrors = 1;\r\n# sMessage = 'Client: ' | sClient | ' does not exist.';\r\n# LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n# Endif;\r\n# If( nErrors > 0 );\r\n# ItemReject( Expand( cMsgErrorContent ) );\r\n# EndIf;\r\n# Endif; \r\n# Else;\r\n# # Wildcard search string\r\n# iCount = 0;\r\n# iCheck = 1;\r\n# sChar = sClient;\r\n# While (iCheck > 0);\r\n# iCheck = Scan('*',sChar);\r\n# If( iCheck > 0 );\r\n# iCount = iCount + 1;\r\n# sChar = Subst(sChar,iCheck+1,(long(sChar)-iCheck));\r\n# Endif;\r\n# End;\r\n# If(iCount = 1);\r\n# ##If the wilcardsearch is *String, below code will get executed\r\n# if(Subst(sClient,iCount,1) @= '*');\r\n# sClient1 = '\"'| Subst(sClient,iCount+1,(Long(sClient)- iCount))|'\"';\r\n# sTempCount = NumbertoString(Long(sClient)-iCount);\r\n# sMdx = '{FILTER({TM1SUBSETALL(['|cClientDim|'].['|cClientHier|'])},\r\n# (Right( ['|cClientDim|'].['|cClientHier|'].[}TM1_DefaultDisplayValue],'| sTempCount|') ='|sClient1|'))}+\r\n# {FILTER({TM1SUBSETALL(['|cClientDim|'].['|cClientHier|'])},\r\n# (Right( ['|cClientDim|'].['|cClientHier|'].CurrentMember.Name,'| sTempCount|') ='|sClient1|'))}';\r\n# If( SubsetExists( cClientDim, cTempSub ) = 1 );\r\n# # If a delimited list of Client names includes wildcards then we may have to re-use the subset multiple times\r\n# SubsetMDXSet( cClientDim, cTempSub, sMDX );\r\n# Else;\r\n# # temp subset, therefore no need to destroy in epilog\r\n# SubsetCreatebyMDX( cTempSub, sMDX, cClientDim, 1 );\r\n# EndIf;\r\n# \r\n# nHier_Sub_Size = HierarchySubsetGetSize(cClientDim, cClientHier, cTempSub);\r\n# nCount = nHier_Sub_Size;\r\n# While (nCount >= 1);\r\n# sTemp = HierarchySubsetElementGetIndex(cClientDim, cClientHier, cTempSub, '', 1);\r\n# sElement = HierarchySubsetGetElementName(cClientDim, cClientHier, cTempSub, nCount);\r\n# If( sElement @<> 'Admin' & sElement @<> TM1User() );\r\n# DeleteClient(sElement);\r\n# ElseIf( sElement @= 'Admin' );\r\n# LogOutput( 'WARN', 'Skipping attempt to delete Admin user.' );\r\n# ElseIf( sElement @= TM1User() );\r\n# LogOutput( 'WARN', 'Skipping attempt to delete self.' );\r\n# EndIf;\r\n# nCount = nCount -1;\r\n# End;\r\n# ##If the wilcardsearch is String*, below code will get executed\r\n# ElseIf(Subst(sClient,Long(sClient),1) @= '*');\r\n#\r\n# sClient1 = '\"'| Subst(sClient,iCount,(Long(sClient)- iCount))|'\"';\r\n# sMdx = '{FILTER({TM1SUBSETALL(['|cClientDim|'].['|cClientHier|'])},\r\n# (INSTR('| NumbertoString(iCount)|', ['|cClientDim|'].['|cClientHier|'].[}TM1_DefaultDisplayValue],'|sClient1|') ='| NumbertoString(iCount)|'))}+\r\n# {FILTER({TM1SUBSETALL(['|cClientDim|'].['|cClientHier|'])},\r\n# (INSTR('| NumbertoString(iCount)|', ['|cClientDim|'].['|cClientHier|'].CurrentMember.Name,'|sClient1|') ='| NumbertoString(iCount)|'))}';\r\n# If( SubsetExists( cClientDim, cTempSub ) = 1 );\r\n# # If a delimited list of Client names includes wildcards then we may have to re-use the subset multiple times\r\n# SubsetMDXSet( cClientDim, cTempSub, sMDX );\r\n# Else;\r\n# # temp subset, therefore no need to destroy in epilog\r\n# SubsetCreatebyMDX( cTempSub, sMDX, cClientDim, 1 );\r\n# EndIf;\r\n#\r\n# nHier_Sub_Size = HierarchySubsetGetSize(cClientDim, cClientHier, cTempSub);\r\n# nCount = nHier_Sub_Size;\r\n# While (nCount >= 1);\r\n# sTemp = HierarchySubsetElementGetIndex (cClientDim, cClientHier, cTempSub, '', 1);\r\n# sElement = HierarchySubsetGetElementName(cClientDim, cClientHier, cTempSub, nCount);\r\n# If( sElement @<> 'Admin' & sElement @<> TM1User() );\r\n# DeleteClient(sElement);\r\n# ElseIf( sElement @= 'Admin' );\r\n# LogOutput( 'WARN', 'Skipping attempt to delete Admin user.' );\r\n# ElseIf( sElement @= TM1User() );\r\n# LogOutput( 'WARN', 'Skipping attempt to delete self.' );\r\n# EndIf;\r\n# nCount = nCount -1;\r\n# End;\r\n# Endif;\r\n# Else;\r\n# ##If the wilcardsearch is *String*, below code will get executed\r\n# sClient1 = '\"'| Subst(sClient,iCount,(Long(sClient)- iCount))|'\"';\r\n# sMdx = '{FILTER({TM1SUBSETALL(['|cClientDim|'].['|cClientHier|'])},\r\n# (INSTR(1,['|cClientDim|'].['|cClientHier|'].[}TM1_DefaultDisplayValue],'|sClient1|') <> 0))}+\r\n# {FILTER({TM1SUBSETALL(['|cClientDim|'].['|cClientHier|'])},\r\n# (INSTR(1,['|cClientDim|'].['|cClientHier|'].CurrentMember.Name,'|sClient1|') <> 0))}';\r\n# If( SubsetExists( cClientDim, cTempSub ) = 1 );\r\n# # If a delimited list of Client names includes wildcards then we may have to re-use the subset multiple times\r\n# SubsetMDXSet( cClientDim, cTempSub, sMDX );\r\n# Else;\r\n# # temp subset, therefore no need to destroy in epilog\r\n# SubsetCreatebyMDX( cTempSub, sMDX, cClientDim, 1 );\r\n# EndIf;\r\n#\r\n# nHier_Sub_Size = HierarchySubsetGetSize(cClientDim, cClientHier, cTempSub);\r\n# nCount = nHier_Sub_Size;\r\n# While (nCount >= 1);\r\n# sTemp = HierarchySubsetElementGetIndex (cClientDim, cClientHier, cTempSub, '', 1);\r\n# sElement = HierarchySubsetGetElementName(cClientDim, cClientHier, cTempSub, nCount);\r\n# If( sElement @<> 'Admin' & sElement @<> TM1User() );\r\n# DeleteClient(sElement);\r\n# ElseIf( sElement @= 'Admin' );\r\n# LogOutput( 'WARN', 'Skipping attempt to delete Admin user.' );\r\n# ElseIf( sElement @= TM1User() );\r\n# LogOutput( 'WARN', 'Skipping attempt to delete self.' );\r\n# EndIf;\r\n# nCount = nCount -1;\r\n# End;\r\n# Endif;\r\n# EndIf;\r\n#End;\r\n\r\nsDim = cClientDim;\r\nsCurrHierName = cClientHier;\r\nsEles = pClient;\r\nnDelimiterIndexB = 1;\r\nWhile( nDelimiterIndexB <> 0 );\r\n \r\n nDelimiterIndexB = Scan( pDelim, sEles );\r\n If( nDelimiterIndexB = 0 );\r\n sEle = sEles;\r\n Else;\r\n sEle = Trim( SubSt( sEles, 1, nDelimiterIndexB - 1 ) );\r\n sEles = Trim( Subst( sEles, nDelimiterIndexB + Long(pDelim), Long( sEles ) ) );\r\n EndIf;\r\n \r\n # Check if a wildcard has been used to specify the Element name.\r\n # If it hasn't then just delete the Element if it exists\r\n If( Scan( '*', sEle ) = 0 & Scan( '?', sEle ) = 0);\r\n If( HierarchyElementExists( sDim,sCurrHierName, sEle ) = 1 );\r\n If( sEle @<> 'Admin' & sEle @<> TM1User() );\r\n DeleteClient( sEle );\r\n Else;\r\n cMsgErrorContent = 'Attempt to %sEle%. Did not delete.';\r\n LogOutput( 'WARN', Expand( cMsgErrorContent ) );\r\n EndIF;\r\n If( pLogOutput = 1 );\r\n cMsgInfoContent = Expand( 'Attempted to delete Element %sEle%.' );\r\n LogOutput( cMsgInfoLevel, Expand( cMsgInfoContent ) );\r\n EndIf;\r\n Else;\r\n If( pLogOutput >= 1 );\r\n cMsgInfoContent = Expand('The Hierarchy %sCurrHier% does not contain element %sEle%.');\r\n LogOutput( cMsgInfoLevel, Expand( cMsgInfoContent ) );\r\n EndIf;\r\n Endif;\r\n Else;\r\n # Wildcard search string\r\n sEle = '\"'|sEle|'\"';\r\n sMdxEle = '{TM1FILTERBYPATTERN( {TM1SUBSETALL([ ' | sCurrHierName |' ])},'| sEle| ')}';\r\n\r\n If( HierarchySubsetExists( sDim, sCurrHierName, cTempSub ) = 1 );\r\n # If a delimited list of ele names includes wildcards then we may have to re-use the subset multiple times\r\n HierarchySubsetMDXSet( sDim, sCurrHierName, cTempSub, sMDXEle );\r\n Else;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSub, sMDXEle, sCurrHierName, 1 );\r\n EndIf;\r\n\r\n # Loop through subset of hierarchy elements created based on wildcard\r\n nCountElems = HierarchySubsetGetSize(sDim, sCurrHierName, cTempSub);\r\n While( nCountElems >= 1 );\r\n sElement = HierarchySubsetGetElementName(sDim, sCurrHierName, cTempSub, nCountElems);\r\n If( sElement @<> 'Admin' & sElement @<> TM1User() );\r\n DeleteClient( sEle );\r\n Else;\r\n cMsgErrorContent = 'Attempt to %sElement%. Did not delete.';\r\n LogOutput( 'WARN', Expand( cMsgErrorContent ) );\r\n EndIF;\r\n If( pLogOutput = 1 );\r\n cMsgInfoContent = Expand( 'Attempted to delete Element %sElement%.' );\r\n LogOutput( cMsgInfoLevel, Expand( cMsgInfoContent ) );\r\n EndIf;\r\n nCountElems = nCountElems - 1;\r\n End;\r\n EndIf;\r\n\r\nEnd;\r\n\r\nIf( nErrors = 0 );\r\n DimensionSortOrder( cClientDim, 'ByName', 'Ascending', 'ByName' , 'Ascending' );\r\nEndIf;\r\n\r\n\r\n### End Prolog ###", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n\tExecuteProcess( '}bedrock.security.client.delete', 'pLogOutput', pLogOutput,\r\n\t 'pStrictErrorHandling', pStrictErrorHandling,\r\n\t 'pClient', '', 'pDelim', '&'\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will delete clients.\r\n\r\n# Use case: Intended for development and production.\r\n# 1/ Clean up users after go live.\r\n# 2/ Remove old employees from the system on termination.\r\n\r\n# Note:\r\n# Naturally, a valid client(s) (pClient) is mandatory otherwise the process will abort:\r\n# - Multiple clients can be specified separated by a delimiter. \r\n#EndRegion @DOC\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName | '_' | cTimeStamp | '_' | cRandomInt;\r\ncTempFile = GetProcessErrorFileDirectory | cTempSub | '.csv';\r\ncClientDim = '}Clients';\r\ncClientHier = cClientDim;\r\ncUserName = TM1User();\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgInfoLevel = 'INFO';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pClient:%pClient%, pDelim:%pDelim%.' ;\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pClient\": null,\r\n \"pDelim\": \"&\",\r\n \"pLogOutput\": 0,\r\n \"pStrictErrorHandling\": 0\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pClient\": '|StringToJson ( pClient )|',\r\n \"pDelim\": '|StringToJson ( pDelim )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npClient = JsonToString( JsonGet( pJson, 'pClient' ) );\r\npDelim = JsonToString( JsonGet( pJson, 'pDelim' ) );\r\n# Numeric Parameters\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\n# If blank delimiter specified then convert to default\r\nIf( pDelim @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\n# If no clients have been specified then terminate process\r\nIf( Trim( pClient ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No clients specified';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Check alias exists\r\nIf( DimensionExists('}ElementAttributes_'|cClientDim) = 0 % DimIx('}ElementAttributes_'|cClientDim, '}TM1_DefaultDisplayValue') = 0 );\r\n AttrInsert( cClientDim, '', '}TM1_DefaultDisplayValue', 'A' );\r\nEndIf;\r\n\r\n### Split pClient into individual clients and delete ###\r\n#sClients = pClient;\r\n#nDelimiterIndex = 1;\r\n#While( nDelimiterIndex <> 0 );\r\n# nDelimiterIndex = Scan( pDelim, sClients );\r\n# If( nDelimiterIndex = 0 );\r\n# sClient = sClients;\r\n# Else;\r\n# sClient = Trim( SubSt( sClients, 1, nDelimiterIndex - 1 ) );\r\n# sClients = Trim( Subst( sClients, nDelimiterIndex + Long(pDelim), Long( sClients ) ) );\r\n# EndIf;\r\n# \r\n# If( Scan( '*', sClient ) = 0);\r\n# If( sClient @<> '' );\r\n# If( DimIx( cClientDim, sClient ) <> 0 );\r\n# sClient = DimensionElementPrincipalName(cClientDim,sClient);\r\n# If( sClient @<> 'Admin' & sClient @<> TM1User() );\r\n# DeleteClient(sClient);\r\n# ElseIf( sClient @= 'Admin' );\r\n# nErrors = 1;\r\n# sMessage = 'Skipping attempt to delete Admin user.';\r\n# LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n# ElseIf( sClient @= TM1User() );\r\n# nErrors = 1;\r\n# sMessage = 'Skipping attempt to delete self.';\r\n# LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n# EndIf;\r\n# Else;\r\n# nErrors = 1;\r\n# sMessage = 'Client: ' | sClient | ' does not exist.';\r\n# LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n# Endif;\r\n# If( nErrors > 0 );\r\n# ItemReject( Expand( cMsgErrorContent ) );\r\n# EndIf;\r\n# Endif; \r\n# Else;\r\n# # Wildcard search string\r\n# iCount = 0;\r\n# iCheck = 1;\r\n# sChar = sClient;\r\n# While (iCheck > 0);\r\n# iCheck = Scan('*',sChar);\r\n# If( iCheck > 0 );\r\n# iCount = iCount + 1;\r\n# sChar = Subst(sChar,iCheck+1,(long(sChar)-iCheck));\r\n# Endif;\r\n# End;\r\n# If(iCount = 1);\r\n# ##If the wilcardsearch is *String, below code will get executed\r\n# if(Subst(sClient,iCount,1) @= '*');\r\n# sClient1 = '\"'| Subst(sClient,iCount+1,(Long(sClient)- iCount))|'\"';\r\n# sTempCount = NumbertoString(Long(sClient)-iCount);\r\n# sMdx = '{FILTER({TM1SUBSETALL(['|cClientDim|'].['|cClientHier|'])},\r\n# (Right( ['|cClientDim|'].['|cClientHier|'].[}TM1_DefaultDisplayValue],'| sTempCount|') ='|sClient1|'))}+\r\n# {FILTER({TM1SUBSETALL(['|cClientDim|'].['|cClientHier|'])},\r\n# (Right( ['|cClientDim|'].['|cClientHier|'].CurrentMember.Name,'| sTempCount|') ='|sClient1|'))}';\r\n# If( SubsetExists( cClientDim, cTempSub ) = 1 );\r\n# # If a delimited list of Client names includes wildcards then we may have to re-use the subset multiple times\r\n# SubsetMDXSet( cClientDim, cTempSub, sMDX );\r\n# Else;\r\n# # temp subset, therefore no need to destroy in epilog\r\n# SubsetCreatebyMDX( cTempSub, sMDX, cClientDim, 1 );\r\n# EndIf;\r\n# \r\n# nHier_Sub_Size = HierarchySubsetGetSize(cClientDim, cClientHier, cTempSub);\r\n# nCount = nHier_Sub_Size;\r\n# While (nCount >= 1);\r\n# sTemp = HierarchySubsetElementGetIndex(cClientDim, cClientHier, cTempSub, '', 1);\r\n# sElement = HierarchySubsetGetElementName(cClientDim, cClientHier, cTempSub, nCount);\r\n# If( sElement @<> 'Admin' & sElement @<> TM1User() );\r\n# DeleteClient(sElement);\r\n# ElseIf( sElement @= 'Admin' );\r\n# LogOutput( 'WARN', 'Skipping attempt to delete Admin user.' );\r\n# ElseIf( sElement @= TM1User() );\r\n# LogOutput( 'WARN', 'Skipping attempt to delete self.' );\r\n# EndIf;\r\n# nCount = nCount -1;\r\n# End;\r\n# ##If the wilcardsearch is String*, below code will get executed\r\n# ElseIf(Subst(sClient,Long(sClient),1) @= '*');\r\n#\r\n# sClient1 = '\"'| Subst(sClient,iCount,(Long(sClient)- iCount))|'\"';\r\n# sMdx = '{FILTER({TM1SUBSETALL(['|cClientDim|'].['|cClientHier|'])},\r\n# (INSTR('| NumbertoString(iCount)|', ['|cClientDim|'].['|cClientHier|'].[}TM1_DefaultDisplayValue],'|sClient1|') ='| NumbertoString(iCount)|'))}+\r\n# {FILTER({TM1SUBSETALL(['|cClientDim|'].['|cClientHier|'])},\r\n# (INSTR('| NumbertoString(iCount)|', ['|cClientDim|'].['|cClientHier|'].CurrentMember.Name,'|sClient1|') ='| NumbertoString(iCount)|'))}';\r\n# If( SubsetExists( cClientDim, cTempSub ) = 1 );\r\n# # If a delimited list of Client names includes wildcards then we may have to re-use the subset multiple times\r\n# SubsetMDXSet( cClientDim, cTempSub, sMDX );\r\n# Else;\r\n# # temp subset, therefore no need to destroy in epilog\r\n# SubsetCreatebyMDX( cTempSub, sMDX, cClientDim, 1 );\r\n# EndIf;\r\n#\r\n# nHier_Sub_Size = HierarchySubsetGetSize(cClientDim, cClientHier, cTempSub);\r\n# nCount = nHier_Sub_Size;\r\n# While (nCount >= 1);\r\n# sTemp = HierarchySubsetElementGetIndex (cClientDim, cClientHier, cTempSub, '', 1);\r\n# sElement = HierarchySubsetGetElementName(cClientDim, cClientHier, cTempSub, nCount);\r\n# If( sElement @<> 'Admin' & sElement @<> TM1User() );\r\n# DeleteClient(sElement);\r\n# ElseIf( sElement @= 'Admin' );\r\n# LogOutput( 'WARN', 'Skipping attempt to delete Admin user.' );\r\n# ElseIf( sElement @= TM1User() );\r\n# LogOutput( 'WARN', 'Skipping attempt to delete self.' );\r\n# EndIf;\r\n# nCount = nCount -1;\r\n# End;\r\n# Endif;\r\n# Else;\r\n# ##If the wilcardsearch is *String*, below code will get executed\r\n# sClient1 = '\"'| Subst(sClient,iCount,(Long(sClient)- iCount))|'\"';\r\n# sMdx = '{FILTER({TM1SUBSETALL(['|cClientDim|'].['|cClientHier|'])},\r\n# (INSTR(1,['|cClientDim|'].['|cClientHier|'].[}TM1_DefaultDisplayValue],'|sClient1|') <> 0))}+\r\n# {FILTER({TM1SUBSETALL(['|cClientDim|'].['|cClientHier|'])},\r\n# (INSTR(1,['|cClientDim|'].['|cClientHier|'].CurrentMember.Name,'|sClient1|') <> 0))}';\r\n# If( SubsetExists( cClientDim, cTempSub ) = 1 );\r\n# # If a delimited list of Client names includes wildcards then we may have to re-use the subset multiple times\r\n# SubsetMDXSet( cClientDim, cTempSub, sMDX );\r\n# Else;\r\n# # temp subset, therefore no need to destroy in epilog\r\n# SubsetCreatebyMDX( cTempSub, sMDX, cClientDim, 1 );\r\n# EndIf;\r\n#\r\n# nHier_Sub_Size = HierarchySubsetGetSize(cClientDim, cClientHier, cTempSub);\r\n# nCount = nHier_Sub_Size;\r\n# While (nCount >= 1);\r\n# sTemp = HierarchySubsetElementGetIndex (cClientDim, cClientHier, cTempSub, '', 1);\r\n# sElement = HierarchySubsetGetElementName(cClientDim, cClientHier, cTempSub, nCount);\r\n# If( sElement @<> 'Admin' & sElement @<> TM1User() );\r\n# DeleteClient(sElement);\r\n# ElseIf( sElement @= 'Admin' );\r\n# LogOutput( 'WARN', 'Skipping attempt to delete Admin user.' );\r\n# ElseIf( sElement @= TM1User() );\r\n# LogOutput( 'WARN', 'Skipping attempt to delete self.' );\r\n# EndIf;\r\n# nCount = nCount -1;\r\n# End;\r\n# Endif;\r\n# EndIf;\r\n#End;\r\n\r\nsDim = cClientDim;\r\nsCurrHierName = cClientHier;\r\nsEles = pClient;\r\nnDelimiterIndexB = 1;\r\nWhile( nDelimiterIndexB <> 0 );\r\n \r\n nDelimiterIndexB = Scan( pDelim, sEles );\r\n If( nDelimiterIndexB = 0 );\r\n sEle = sEles;\r\n Else;\r\n sEle = Trim( SubSt( sEles, 1, nDelimiterIndexB - 1 ) );\r\n sEles = Trim( Subst( sEles, nDelimiterIndexB + Long(pDelim), Long( sEles ) ) );\r\n EndIf;\r\n \r\n # Check if a wildcard has been used to specify the Element name.\r\n # If it hasn't then just delete the Element if it exists\r\n If( Scan( '*', sEle ) = 0 & Scan( '?', sEle ) = 0);\r\n If( HierarchyElementExists( sDim,sCurrHierName, sEle ) = 1 );\r\n If( sEle @<> 'Admin' & sEle @<> TM1User() );\r\n DeleteClient( sEle );\r\n Else;\r\n cMsgErrorContent = 'Attempt to %sEle%. Did not delete.';\r\n LogOutput( 'WARN', Expand( cMsgErrorContent ) );\r\n EndIF;\r\n If( pLogOutput = 1 );\r\n cMsgInfoContent = Expand( 'Attempted to delete Element %sEle%.' );\r\n LogOutput( cMsgInfoLevel, Expand( cMsgInfoContent ) );\r\n EndIf;\r\n Else;\r\n If( pLogOutput >= 1 );\r\n cMsgInfoContent = Expand('The Hierarchy %sCurrHier% does not contain element %sEle%.');\r\n LogOutput( cMsgInfoLevel, Expand( cMsgInfoContent ) );\r\n EndIf;\r\n Endif;\r\n Else;\r\n # Wildcard search string\r\n sEle = '\"'|sEle|'\"';\r\n sMdxEle = '{TM1FILTERBYPATTERN( {TM1SUBSETALL([ ' | sCurrHierName |' ])},'| sEle| ')}';\r\n\r\n If( HierarchySubsetExists( sDim, sCurrHierName, cTempSub ) = 1 );\r\n # If a delimited list of ele names includes wildcards then we may have to re-use the subset multiple times\r\n HierarchySubsetMDXSet( sDim, sCurrHierName, cTempSub, sMDXEle );\r\n Else;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSub, sMDXEle, sCurrHierName, 1 );\r\n EndIf;\r\n\r\n # Loop through subset of hierarchy elements created based on wildcard\r\n nCountElems = HierarchySubsetGetSize(sDim, sCurrHierName, cTempSub);\r\n While( nCountElems >= 1 );\r\n sElement = HierarchySubsetGetElementName(sDim, sCurrHierName, cTempSub, nCountElems);\r\n If( sElement @<> 'Admin' & sElement @<> TM1User() );\r\n DeleteClient( sEle );\r\n Else;\r\n cMsgErrorContent = 'Attempt to %sElement%. Did not delete.';\r\n LogOutput( 'WARN', Expand( cMsgErrorContent ) );\r\n EndIF;\r\n If( pLogOutput = 1 );\r\n cMsgInfoContent = Expand( 'Attempted to delete Element %sElement%.' );\r\n LogOutput( cMsgInfoLevel, Expand( cMsgInfoContent ) );\r\n EndIf;\r\n nCountElems = nCountElems - 1;\r\n End;\r\n EndIf;\r\n\r\nEnd;\r\n\r\nIf( nErrors = 0 );\r\n DimensionSortOrder( cClientDim, 'ByName', 'Ascending', 'ByName' , 'Ascending' );\r\nEndIf;\r\n\r\n\r\n### End Prolog ###", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully deleted Client %pClient% from dimension %cClientDim%.' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n### End Epilog ###", @@ -10,28 +10,34 @@ "Type": "None" }, "Parameters": [ + { + "Name": "pClient", + "Prompt": "REQUIRED: Delimited list of clients", + "Value": "", + "Type": "String" + }, + { + "Name": "pDelim", + "Prompt": "OPTIONAL: Delimiter for list parameters (Default = '&')", + "Value": "&", + "Type": "String" + }, { "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { - "Name": "pClient", - "Prompt": "REQUIRED: Clients (Separated by delimiter (e.g. Client1&Client2), Accepts Wild card (e.g. *Client,*Client*, Client*))", - "Value": "", - "Type": "String" - }, - { - "Name": "pDelim", - "Prompt": "OPTIONAL: Delimiter (default value if blank = '&')", - "Value": "&", + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", "Type": "String" } ], diff --git a/bedrock_processes_json/}bedrock.security.client.group.assign.json b/bedrock_processes_json/}bedrock.security.client.group.assign.json index 0d03915..d89ce3a 100644 --- a/bedrock_processes_json/}bedrock.security.client.group.assign.json +++ b/bedrock_processes_json/}bedrock.security.client.group.assign.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.security.client.group.assign", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.security.client.group.assign', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pClient', '', 'pGroup', '',\r\n \t'pDelim','&', 'pAddOrRemove', 'Add', 'pSecurityRefresh', 'Yes'\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will assign Client and Group Security.\r\n\r\n# Use case: Intended for production.\r\n# 1/ After adding new user(s) using '}bedrock.security.client.create' they must be assigned to groups.\r\n\r\n# Note:\r\n# Naturally, valid client (pClient) is mandatory otherwise the process can't make assignments:\r\n# - This process can either add or remove clients to groups based on pAddOrRemove.\r\n# - This process can work on a single client or multiple clients separated by a delimiter.\r\n# - This process can work on a single group or multiple groups separated by a delimiter.\r\n# - Therefore, it can be used to:\r\n# - Add/remove a single client to/from a single group.\r\n# - Add/remove many clients to/from a single group.\r\n# - Add/remove a single client to/from many groups.\r\n# - Add/remove many clients to/from many groups.\r\n# - The caller can choose whether or not to refresh security at the end. Default is yes.\r\n#EndRegion @DOC\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncUserName = TM1User();\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pClient:%pClient%, pGroup:%pGroup%, pDelim:%pDelim%, pAddOrRemove:%pAddOrRemove%, pSecurityRefresh:%pSecurityRefresh%.' ; \r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\n# If no clients have been specified then terminate process\r\nIf( Trim( pClient ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No clients specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# If no groups have been specified then terminate process\r\nIf( Trim( pGroup ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No groups specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# If pSecurityRefresh is blank then default to yes\r\nIf( Trim( pSecurityRefresh ) @= '' );\r\n pSecurityRefresh = 'Yes';\r\nEndIf;\r\n\r\n# If pAddOrDelete has not been specified correctly then terminate process\r\nIf( Upper( pAddOrRemove ) @<> 'ADD' & Upper( pAddOrRemove ) @<> 'REMOVE' );\r\n nErrors = 1;\r\n sMessage = 'Incorrect value for pAddOrRemove: ' | pAddOrRemove | '. Valid values are Add or Remove';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# If pSecurityRefresh has not been specified correctly then terminate process\r\nIf( Upper( pSecurityRefresh ) @<> 'YES' & Upper( pSecurityRefresh ) @<> 'NO' );\r\n nErrors = 1;\r\n sMessage = 'Incorrect value for pSecurityRefresh: ' | pSecurityRefresh | '. Valid values are Yes or No';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# If blank delimiter specified then convert to default\r\nIf( pDelim @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### Add/remove clients to/from groups ###\r\n\r\n# Loop through list of clients\r\nsClients = pClient;\r\nnClientDelimIndex = 1;\r\nWhile( nClientDelimIndex <> 0 );\r\n nClientDelimIndex = Scan( pDelim, sClients );\r\n If( nClientDelimIndex = 0 );\r\n sClient = sClients;\r\n Else;\r\n sClient = Trim( SubSt( sClients, 1, nClientDelimIndex - 1 ) );\r\n sClients = Trim( Subst( sClients, nClientDelimIndex + Long(pDelim), Long( sClients ) ) );\r\n EndIf;\r\n \r\n If(Scan('*', sClient) = 0 & Scan('?', sClient) = 0);\r\n # Don't attempt to process a blank client\r\n If( sClient @<> '' );\r\n # Check that client exists\r\n If( DimIx( '}Clients', sClient ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Client: ' | sClient | ' does not exists';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n ELSE;\r\n # Loop through list of Groups\r\n sGroups = pGroup;\r\n nGroupDelimIndex = 1;\r\n While( nGroupDelimIndex <> 0 );\r\n nGroupDelimIndex = Scan( pDelim, sGroups );\r\n If( nGroupDelimIndex = 0 );\r\n sGroup = sGroups;\r\n Else;\r\n sGroup = Trim( SubSt( sGroups, 1, nGroupDelimIndex - 1 ) );\r\n sGroups = Trim( Subst( sGroups, nGroupDelimIndex + Long(pDelim), Long( sGroups ) ) );\r\n EndIf;\r\n If( Scan( '*', sGroup ) = 0 & Scan('?', sGroup ) = 0 );\r\n # Don't attempt to process a blank Group\r\n If( sGroup @<> '' );\r\n # Check that group exists\r\n If( DimIx( '}Groups', sGroup ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Group: ' | sGroup | ' does not exists';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n ELSE;\r\n # Add/Remove Client\r\n If( Upper( pAddOrRemove ) @= 'ADD' );\r\n AssignClientToGroup( sClient, sGroup );\r\n ElseIf( Upper( pAddOrRemove ) @= 'REMOVE' );\r\n RemoveClientFromGroup( sClient, sGroup );\r\n EndIf;\r\n EndIf;\r\n EndIf;\r\n ELSE;\r\n # Wildcard search string\r\n sGroup = '\"'|sGroup|'\"';\r\n sGroupDim = '}Groups';\r\n sMdx = '{TM1FILTERBYPATTERN( {TM1SUBSETALL([ ' |sGroupDim| '])},'| sGroup| ')}';\r\n If( SubsetExists( sGroupDim, cTempSub ) = 1 );\r\n # If a delimited list of Groups includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( sGroupDim, cTempSub, sMDX );\r\n Else;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSub, sMDX, sGroupDim, 1 );\r\n EndIf;\r\n nCountGrp = SubsetGetSize( sGroupDim, cTempSub );\r\n While( nCountGrp >= 1 );\r\n sGroup = SubsetGetElementName( sGroupDim, cTempSub, nCountGrp );\r\n # Add/Remove Client\r\n If( Upper( pAddOrRemove ) @= 'ADD' );\r\n AssignClientToGroup( sClient, sGroup );\r\n ElseIf( Upper( pAddOrRemove ) @= 'REMOVE' );\r\n RemoveClientFromGroup( sClient, sGroup );\r\n EndIf;\r\n nCountGrp = nCountGrp - 1;\r\n End;\r\n Endif; \r\n End;\r\n EndIf;\r\n EndIf;\r\n ELSE;\r\n # Wildcard search string\r\n sClientDim = '}Clients';\r\n sClient = '\"'|sClient|'\"';\r\n sMdx = '{TM1FILTERBYPATTERN( {TM1SUBSETALL([ ' |sClientDim| '])},'| sClient| ')}';\r\n If( SubsetExists( sClientDim, cTempSub ) = 1 );\r\n # If a delimited list of Clients includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( sClientDim, cTempSub, sMDX );\r\n Else;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSub, sMDX, sClientDim, 1 );\r\n EndIf;\r\n # Loop through dimensions in clients with wildcard\r\n nCountClient = SubsetGetSize( '}Clients' , cTempSub );\r\n While( nCountClient >= 1 );\r\n \r\n sClient = SubsetGetElementName( '}Clients' , cTempSub, nCountClient );\r\n # Validate client name\r\n If( Dimix('}Clients', sClient) = 0 );\r\n nErrors = 1;\r\n sMessage = Expand( 'Client \"%sClient%\" does not exist.' );\r\n LogOutput( 'ERROR', Expand( cMsgErrorContent ) );\r\n Else;\r\n # Loop through list of Groups\r\n sGroups = pGroup;\r\n nGroupDelimIndex = 1;\r\n While( nGroupDelimIndex <> 0 );\r\n nGroupDelimIndex = Scan( pDelim, sGroups );\r\n If( nGroupDelimIndex = 0 );\r\n sGroup = sGroups;\r\n Else;\r\n sGroup = Trim( SubSt( sGroups, 1, nGroupDelimIndex - 1 ) );\r\n sGroups = Trim( Subst( sGroups, nGroupDelimIndex + Long(pDelim), Long( sGroups ) ) );\r\n EndIf;\r\n If( Scan( '*', sGroup ) = 0 & Scan('?',sGroup ) = 0);\r\n # Don't attempt to process a blank Group\r\n If( sGroup @<> '' );\r\n # Check that group exists\r\n If( DimIx( '}Groups', sGroup ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Group: ' | sGroup | ' does not exists';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n ELSE;\r\n # Add/Remove Client\r\n If( Upper( pAddOrRemove ) @= 'ADD' );\r\n AssignClientToGroup( sClient, sGroup );\r\n ElseIf( Upper( pAddOrRemove ) @= 'REMOVE' );\r\n RemoveClientFromGroup( sClient, sGroup );\r\n EndIf;\r\n EndIf;\r\n EndIf;\r\n ELSE;\r\n # Wildcard search string\r\n sGroup = '\"'|sGroup|'\"';\r\n sGroupDim = '}Groups';\r\n sMdx = '{TM1FILTERBYPATTERN( {TM1SUBSETALL([ ' |sGroupDim| '])},'| sGroup| ')}';\r\n If( SubsetExists( sGroupDim, cTempSub ) = 1 );\r\n # If a delimited list of objects includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( sGroupDim, cTempSub, sMDX );\r\n Else;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSub, sMDX, sGroupDim, 1 );\r\n EndIf;\r\n nCountGrp = SubsetGetSize( sGroupDim, cTempSub );\r\n While( nCountGrp >= 1 );\r\n sGroup = SubsetGetElementName( sGroupDim, cTempSub, nCountGrp );\r\n # Add/Remove Client\r\n If( Upper( pAddOrRemove ) @= 'ADD' );\r\n AssignClientToGroup( sClient, sGroup );\r\n ElseIf( Upper( pAddOrRemove ) @= 'REMOVE' );\r\n RemoveClientFromGroup( sClient, sGroup );\r\n EndIf;\r\n nCountGrp = nCountGrp - 1;\r\n End;\r\n EndIf;\r\n End;\r\n Endif;\r\n nCountClient = nCountClient - 1;\r\n End;\r\n Endif; \r\nEnd;\r\n\r\n\r\n### Refresh Security ###\r\n\r\nIf( Upper( pSecurityRefresh ) @= 'YES' );\r\n SecurityRefresh;\r\nEndIf;\r\n\r\n\r\n### End Prolog ###", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.security.client.group.assign', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pClient', '', 'pGroup', '',\r\n \t'pDelim','&', 'pAddOrRemove', 'Add', 'pSecurityRefresh', 'Yes'\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will assign Client and Group Security.\r\n\r\n# Use case: Intended for production.\r\n# 1/ After adding new user(s) using '}bedrock.security.client.create' they must be assigned to groups.\r\n\r\n# Note:\r\n# Naturally, valid client (pClient) is mandatory otherwise the process can't make assignments:\r\n# - This process can either add or remove clients to groups based on pAddOrRemove.\r\n# - This process can work on a single client or multiple clients separated by a delimiter.\r\n# - This process can work on a single group or multiple groups separated by a delimiter.\r\n# - Therefore, it can be used to:\r\n# - Add/remove a single client to/from a single group.\r\n# - Add/remove many clients to/from a single group.\r\n# - Add/remove a single client to/from many groups.\r\n# - Add/remove many clients to/from many groups.\r\n# - The caller can choose whether or not to refresh security at the end. Default is yes.\r\n#EndRegion @DOC\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncUserName = TM1User();\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pClient:%pClient%, pGroup:%pGroup%, pDelim:%pDelim%, pAddOrRemove:%pAddOrRemove%, pSecurityRefresh:%pSecurityRefresh%.' ;\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pAddOrRemove\": null,\r\n \"pClient\": null,\r\n \"pDelim\": \"&\",\r\n \"pGroup\": null,\r\n \"pSecurityRefresh\": \"Yes\",\r\n \"pLogOutput\": 0,\r\n \"pStrictErrorHandling\": 0\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pAddOrRemove\": '|StringToJson ( pAddOrRemove )|',\r\n \"pClient\": '|StringToJson ( pClient )|',\r\n \"pDelim\": '|StringToJson ( pDelim )|',\r\n \"pGroup\": '|StringToJson ( pGroup )|',\r\n \"pSecurityRefresh\": '|StringToJson ( pSecurityRefresh )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npAddOrRemove = JsonToString( JsonGet( pJson, 'pAddOrRemove' ) );\r\npClient = JsonToString( JsonGet( pJson, 'pClient' ) );\r\npDelim = JsonToString( JsonGet( pJson, 'pDelim' ) );\r\npGroup = JsonToString( JsonGet( pJson, 'pGroup' ) );\r\npSecurityRefresh = JsonToString( JsonGet( pJson, 'pSecurityRefresh' ) );\r\n# Numeric Parameters\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\n# If no clients have been specified then terminate process\r\nIf( Trim( pClient ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No clients specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# If no groups have been specified then terminate process\r\nIf( Trim( pGroup ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No groups specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# If pSecurityRefresh is blank then default to yes\r\nIf( Trim( pSecurityRefresh ) @= '' );\r\n pSecurityRefresh = 'Yes';\r\nEndIf;\r\n\r\n# If pAddOrDelete has not been specified correctly then terminate process\r\nIf( Upper( pAddOrRemove ) @<> 'ADD' & Upper( pAddOrRemove ) @<> 'REMOVE' );\r\n nErrors = 1;\r\n sMessage = 'Incorrect value for pAddOrRemove: ' | pAddOrRemove | '. Valid values are Add or Remove';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# If pSecurityRefresh has not been specified correctly then terminate process\r\nIf( Upper( pSecurityRefresh ) @<> 'YES' & Upper( pSecurityRefresh ) @<> 'NO' );\r\n nErrors = 1;\r\n sMessage = 'Incorrect value for pSecurityRefresh: ' | pSecurityRefresh | '. Valid values are Yes or No';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# If blank delimiter specified then convert to default\r\nIf( pDelim @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### Add/remove clients to/from groups ###\r\n\r\n# Loop through list of clients\r\nsClients = pClient;\r\nnClientDelimIndex = 1;\r\nWhile( nClientDelimIndex <> 0 );\r\n nClientDelimIndex = Scan( pDelim, sClients );\r\n If( nClientDelimIndex = 0 );\r\n sClient = sClients;\r\n Else;\r\n sClient = Trim( SubSt( sClients, 1, nClientDelimIndex - 1 ) );\r\n sClients = Trim( Subst( sClients, nClientDelimIndex + Long(pDelim), Long( sClients ) ) );\r\n EndIf;\r\n \r\n If(Scan('*', sClient) = 0 & Scan('?', sClient) = 0);\r\n # Don't attempt to process a blank client\r\n If( sClient @<> '' );\r\n # Check that client exists\r\n If( DimIx( '}Clients', sClient ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Client: ' | sClient | ' does not exists';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n ELSE;\r\n # Loop through list of Groups\r\n sGroups = pGroup;\r\n nGroupDelimIndex = 1;\r\n While( nGroupDelimIndex <> 0 );\r\n nGroupDelimIndex = Scan( pDelim, sGroups );\r\n If( nGroupDelimIndex = 0 );\r\n sGroup = sGroups;\r\n Else;\r\n sGroup = Trim( SubSt( sGroups, 1, nGroupDelimIndex - 1 ) );\r\n sGroups = Trim( Subst( sGroups, nGroupDelimIndex + Long(pDelim), Long( sGroups ) ) );\r\n EndIf;\r\n If( Scan( '*', sGroup ) = 0 & Scan('?', sGroup ) = 0 );\r\n # Don't attempt to process a blank Group\r\n If( sGroup @<> '' );\r\n # Check that group exists\r\n If( DimIx( '}Groups', sGroup ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Group: ' | sGroup | ' does not exists';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n ELSE;\r\n # Add/Remove Client\r\n If( Upper( pAddOrRemove ) @= 'ADD' );\r\n AssignClientToGroup( sClient, sGroup );\r\n ElseIf( Upper( pAddOrRemove ) @= 'REMOVE' );\r\n RemoveClientFromGroup( sClient, sGroup );\r\n EndIf;\r\n EndIf;\r\n EndIf;\r\n ELSE;\r\n # Wildcard search string\r\n sGroup = '\"'|sGroup|'\"';\r\n sGroupDim = '}Groups';\r\n sMdx = '{TM1FILTERBYPATTERN( {TM1SUBSETALL([ ' |sGroupDim| '])},'| sGroup| ')}';\r\n If( SubsetExists( sGroupDim, cTempSub ) = 1 );\r\n # If a delimited list of Groups includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( sGroupDim, cTempSub, sMDX );\r\n Else;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSub, sMDX, sGroupDim, 1 );\r\n EndIf;\r\n nCountGrp = SubsetGetSize( sGroupDim, cTempSub );\r\n While( nCountGrp >= 1 );\r\n sGroup = SubsetGetElementName( sGroupDim, cTempSub, nCountGrp );\r\n # Add/Remove Client\r\n If( Upper( pAddOrRemove ) @= 'ADD' );\r\n AssignClientToGroup( sClient, sGroup );\r\n ElseIf( Upper( pAddOrRemove ) @= 'REMOVE' );\r\n RemoveClientFromGroup( sClient, sGroup );\r\n EndIf;\r\n nCountGrp = nCountGrp - 1;\r\n End;\r\n Endif; \r\n End;\r\n EndIf;\r\n EndIf;\r\n ELSE;\r\n # Wildcard search string\r\n sClientDim = '}Clients';\r\n sClient = '\"'|sClient|'\"';\r\n sMdx = '{TM1FILTERBYPATTERN( {TM1SUBSETALL([ ' |sClientDim| '])},'| sClient| ')}';\r\n If( SubsetExists( sClientDim, cTempSub ) = 1 );\r\n # If a delimited list of Clients includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( sClientDim, cTempSub, sMDX );\r\n Else;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSub, sMDX, sClientDim, 1 );\r\n EndIf;\r\n # Loop through dimensions in clients with wildcard\r\n nCountClient = SubsetGetSize( '}Clients' , cTempSub );\r\n While( nCountClient >= 1 );\r\n \r\n sClient = SubsetGetElementName( '}Clients' , cTempSub, nCountClient );\r\n # Validate client name\r\n If( Dimix('}Clients', sClient) = 0 );\r\n nErrors = 1;\r\n sMessage = Expand( 'Client \"%sClient%\" does not exist.' );\r\n LogOutput( 'ERROR', Expand( cMsgErrorContent ) );\r\n Else;\r\n # Loop through list of Groups\r\n sGroups = pGroup;\r\n nGroupDelimIndex = 1;\r\n While( nGroupDelimIndex <> 0 );\r\n nGroupDelimIndex = Scan( pDelim, sGroups );\r\n If( nGroupDelimIndex = 0 );\r\n sGroup = sGroups;\r\n Else;\r\n sGroup = Trim( SubSt( sGroups, 1, nGroupDelimIndex - 1 ) );\r\n sGroups = Trim( Subst( sGroups, nGroupDelimIndex + Long(pDelim), Long( sGroups ) ) );\r\n EndIf;\r\n If( Scan( '*', sGroup ) = 0 & Scan('?',sGroup ) = 0);\r\n # Don't attempt to process a blank Group\r\n If( sGroup @<> '' );\r\n # Check that group exists\r\n If( DimIx( '}Groups', sGroup ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Group: ' | sGroup | ' does not exists';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n ELSE;\r\n # Add/Remove Client\r\n If( Upper( pAddOrRemove ) @= 'ADD' );\r\n AssignClientToGroup( sClient, sGroup );\r\n ElseIf( Upper( pAddOrRemove ) @= 'REMOVE' );\r\n RemoveClientFromGroup( sClient, sGroup );\r\n EndIf;\r\n EndIf;\r\n EndIf;\r\n ELSE;\r\n # Wildcard search string\r\n sGroup = '\"'|sGroup|'\"';\r\n sGroupDim = '}Groups';\r\n sMdx = '{TM1FILTERBYPATTERN( {TM1SUBSETALL([ ' |sGroupDim| '])},'| sGroup| ')}';\r\n If( SubsetExists( sGroupDim, cTempSub ) = 1 );\r\n # If a delimited list of objects includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( sGroupDim, cTempSub, sMDX );\r\n Else;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSub, sMDX, sGroupDim, 1 );\r\n EndIf;\r\n nCountGrp = SubsetGetSize( sGroupDim, cTempSub );\r\n While( nCountGrp >= 1 );\r\n sGroup = SubsetGetElementName( sGroupDim, cTempSub, nCountGrp );\r\n # Add/Remove Client\r\n If( Upper( pAddOrRemove ) @= 'ADD' );\r\n AssignClientToGroup( sClient, sGroup );\r\n ElseIf( Upper( pAddOrRemove ) @= 'REMOVE' );\r\n RemoveClientFromGroup( sClient, sGroup );\r\n EndIf;\r\n nCountGrp = nCountGrp - 1;\r\n End;\r\n EndIf;\r\n End;\r\n Endif;\r\n nCountClient = nCountClient - 1;\r\n End;\r\n Endif; \r\nEnd;\r\n\r\n\r\n### Refresh Security ###\r\n\r\nIf( Upper( pSecurityRefresh ) @= 'YES' );\r\n SecurityRefresh;\r\nEndIf;\r\n\r\n\r\n### End Prolog ###", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully performed %pAddOrRemove% for client %pClient% to group %pGroup%.' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n\r\n### End Epilog ###", @@ -10,47 +10,53 @@ "Type": "None" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pClient", - "Prompt": "REQUIRED: Client Names Separated by Delimiter and accepts wildcards", + "Prompt": "REQUIRED: Delimited list of clients", "Value": "", "Type": "String" }, { "Name": "pGroup", - "Prompt": "REQUIRED: Group Names Separated by Delimiter and excepts wildcards", + "Prompt": "REQUIRED: Delimited list of groups", "Value": "", "Type": "String" }, { "Name": "pDelim", - "Prompt": "OPTIONAL: Delimiter (default value if blank = '&')", + "Prompt": "OPTIONAL: Delimiter for list parameters (Default = '&')", "Value": "&", "Type": "String" }, { "Name": "pAddOrRemove", - "Prompt": "REQUIRED: Add or Remove", + "Prompt": "REQUIRED: ('Add' or 'Remove'. Default = 'Add')", "Value": "Add", "Type": "String" }, { "Name": "pSecurityRefresh", - "Prompt": "REQUIRED: Refresh Security?", + "Prompt": "OPTIONAL: Refresh security after process execution ('Yes' or 'No'. Default = 'Yes')", "Value": "Yes", "Type": "String" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [], diff --git a/bedrock_processes_json/}bedrock.security.client.password.reset.json b/bedrock_processes_json/}bedrock.security.client.password.reset.json index 567caf6..87dfadc 100644 --- a/bedrock_processes_json/}bedrock.security.client.password.reset.json +++ b/bedrock_processes_json/}bedrock.security.client.password.reset.json @@ -10,35 +10,41 @@ "Type": "None" }, "Parameters": [ + { + "Name": "pClient", + "Prompt": "REQUIRED: Delimited list of clients", + "Value": "", + "Type": "String" + }, + { + "Name": "pDelim", + "Prompt": "OPTIONAL: Delimiter for list parameters (Default = '&')", + "Value": "&", + "Type": "String" + }, { "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { - "Name": "pClient", - "Prompt": "REQUIRED: Clients (Separated by delimiter (e.g. Client1&Client2), Accepts Wild card (e.g. *Client,*Client*, Client*))", - "Value": "", + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters.", + "Value": "{}", "Type": "String" }, { "Name": "pPassword", - "Prompt": "REQUIRED: New Password", + "Prompt": "OBSOLETE: This parameter does nothing and is only included for backwards compatibility", "Value": "", "Type": "String" - }, - { - "Name": "pDelim", - "Prompt": "OPTIONAL: Delimiter character (default value if blank = '&')", - "Value": "&", - "Type": "String" } ], "Variables": [], diff --git a/bedrock_processes_json/}bedrock.security.cube.cellsecurity.create.json b/bedrock_processes_json/}bedrock.security.cube.cellsecurity.create.json index 62ceaac..73eed13 100644 --- a/bedrock_processes_json/}bedrock.security.cube.cellsecurity.create.json +++ b/bedrock_processes_json/}bedrock.security.cube.cellsecurity.create.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.security.cube.cellsecurity.create", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.security.cube.cellsecurity.create', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n\t 'pCube', '', 'pDim', ''\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will create a cell security cube for the specified cube for the specified list of dimensions \r\n# using the TI function _CellSecurityCubeCreate_. The benefit of this process is not needing to write a custom\r\n# process each time in order to create a cell security cube.\r\n\r\n# Use case: Intended for development.\r\n# 1/ Set up cell security cubes\r\n\r\n# Note:\r\n# * Naturally, a valid cube (pCube) is mandatory otherwise the process will abort.\r\n# * If cell security has already been set up the TI will abort.\r\n# * The pDim parameter must map _ALL_ the dimensions in order in the cube with a 0 or 1.\r\n#EndRegion @DOC\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncUserName = TM1User();\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% Message:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pCube:%pCube%, pDim:%pDim%.' ; \r\ncDelim = ':';\r\n\r\n## LogOutput parameters\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\n# If no cube has been specified then terminate process\r\nIf( Trim( pCube ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No cube specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( CubeExists( pCube ) = 0 );\r\n nErrors = 1;\r\n sMessage = Expand('Cube %pCube% does not exist.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Check if cell security cube already exists\r\nIf( CubeExists( '}CellSecurity_' | pCube ) = 1 );\r\n nErrors = 1;\r\n sMessage = 'Cell Security cube already exists.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### Count dimensions in cube\r\nnDims = CubeDimensionCountGet( pCube );\r\n\r\n### If pDim is wildcard, then = ALL (no restrictions on dimensions)\r\npDim = Trim( pDim );\r\nIf( pDim @= '*' );\r\n pDim = Fill( '1:', 2 * nDims - 1 );\r\nEndIf;\r\n### Count dimensions mapped in pDim ###\r\nsDimensions = pDim;\r\nnDelimiterIndex = 1;\r\nnMapDims = 0;\r\niDim = 1;\r\nWhile( nDelimiterIndex <> 0 );\r\n nMapDims = iDim;\r\n nDelimiterIndex = Scan( cDelim, sDimensions );\r\n If( nDelimiterIndex = 0 );\r\n sDimension = sDimensions;\r\n Else;\r\n sDimension = Trim( SubSt( sDimensions, 1, nDelimiterIndex - 1 ) );\r\n sDimensions = Trim( Subst( sDimensions, nDelimiterIndex + Long(cDelim), Long( sDimensions ) ) );\r\n EndIf;\r\n # Redundant?\r\n If( sDimension @= '1' );\r\n sMessage = ' INCLUDE in cell security cube';\r\n ElseIf( sDimension @= '0' );\r\n sMessage = ' EXCLUDE from cell security cube';\r\n Else;\r\n sMessage = ' INVALID map parameter: ' | sDimension;\r\n EndIF;\r\n iDim = iDim + 1;\r\nEnd;\r\n\r\n### Check dimension count of dimension map vs. dimensions in cube ###\r\nIf( nDims <> nMapDims );\r\n nErrors = 1;\r\n sMessage = 'Parameter count of dimension map does not match dimension count of cube!';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElse;\r\n nRet = CellSecurityCubeCreate ( pCube, pDim );\r\n If( nRet = 1 );\r\n sMessage = '}CellSecurity_' | pCube | ' successfully created';\r\n LogOutput( 'INFO', Expand( cMsgErrorContent ) );\r\n Else;\r\n sMessage = 'Error. Could not create }CellSecurity_' | pCube;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n EndIf;\r\nEndIf;\r\n\r\n### End Prolog ###", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.security.cube.cellsecurity.create', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n\t 'pCube', '', 'pDim', ''\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will create a cell security cube for the specified cube for the specified list of dimensions \r\n# using the TI function _CellSecurityCubeCreate_. The benefit of this process is not needing to write a custom\r\n# process each time in order to create a cell security cube.\r\n\r\n# Use case: Intended for development.\r\n# 1/ Set up cell security cubes\r\n\r\n# Note:\r\n# * Naturally, a valid cube (pCube) is mandatory otherwise the process will abort.\r\n# * If cell security has already been set up the TI will abort.\r\n# * The pDim parameter must map _ALL_ the dimensions in order in the cube with a 0 or 1.\r\n#EndRegion @DOC\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncUserName = TM1User();\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% Message:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pCube:%pCube%, pDim:%pDim%.' ; \r\ncDelim = ':';\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pCube\": null,\r\n \"pDim\": null,\r\n \"pLogOutput\": 0,\r\n \"pStrictErrorHandling\": 0\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pCube\": '|StringToJson ( pCube )|',\r\n \"pDim\": '|StringToJson ( pDim )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npCube = JsonToString( JsonGet( pJson, 'pCube' ) );\r\npDim = JsonToString( JsonGet( pJson, 'pDim' ) );\r\n# Numeric Parameters\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n## LogOutput parameters\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\n# If no cube has been specified then terminate process\r\nIf( Trim( pCube ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No cube specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElseIf( CubeExists( pCube ) = 0 );\r\n nErrors = 1;\r\n sMessage = Expand('Cube %pCube% does not exist.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Check if cell security cube already exists\r\nIf( CubeExists( '}CellSecurity_' | pCube ) = 1 );\r\n nErrors = 1;\r\n sMessage = 'Cell Security cube already exists.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### Count dimensions in cube\r\nnDims = CubeDimensionCountGet( pCube );\r\n\r\n### If pDim is wildcard, then = ALL (no restrictions on dimensions)\r\npDim = Trim( pDim );\r\nIf( pDim @= '*' );\r\n pDim = Fill( '1:', 2 * nDims - 1 );\r\nEndIf;\r\n### Count dimensions mapped in pDim ###\r\nsDimensions = pDim;\r\nnDelimiterIndex = 1;\r\nnMapDims = 0;\r\niDim = 1;\r\nWhile( nDelimiterIndex <> 0 );\r\n nMapDims = iDim;\r\n nDelimiterIndex = Scan( cDelim, sDimensions );\r\n If( nDelimiterIndex = 0 );\r\n sDimension = sDimensions;\r\n Else;\r\n sDimension = Trim( SubSt( sDimensions, 1, nDelimiterIndex - 1 ) );\r\n sDimensions = Trim( Subst( sDimensions, nDelimiterIndex + Long(cDelim), Long( sDimensions ) ) );\r\n EndIf;\r\n # Redundant?\r\n If( sDimension @= '1' );\r\n sMessage = ' INCLUDE in cell security cube';\r\n ElseIf( sDimension @= '0' );\r\n sMessage = ' EXCLUDE from cell security cube';\r\n Else;\r\n sMessage = ' INVALID map parameter: ' | sDimension;\r\n EndIF;\r\n iDim = iDim + 1;\r\nEnd;\r\n\r\n### Check dimension count of dimension map vs. dimensions in cube ###\r\nIf( nDims <> nMapDims );\r\n nErrors = 1;\r\n sMessage = 'Parameter count of dimension map does not match dimension count of cube!';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nElse;\r\n nRet = CellSecurityCubeCreate ( pCube, pDim );\r\n If( nRet = 1 );\r\n sMessage = '}CellSecurity_' | pCube | ' successfully created';\r\n LogOutput( 'INFO', Expand( cMsgErrorContent ) );\r\n Else;\r\n sMessage = 'Error. Could not create }CellSecurity_' | pCube;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n EndIf;\r\nEndIf;\r\n\r\n### End Prolog ###", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully created cell security for %pCube% and %pDim%.' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n### End Epilog ###", @@ -10,28 +10,34 @@ "Type": "None" }, "Parameters": [ + { + "Name": "pCube", + "Prompt": "REQUIRED: Cube name", + "Value": "", + "Type": "String" + }, + { + "Name": "pDim", + "Prompt": "REQUIRED: Delimited list of dimensions", + "Value": "", + "Type": "String" + }, { "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { - "Name": "pCube", - "Prompt": "REQUIRED: Cube to create cell security for", - "Value": "", - "Type": "String" - }, - { - "Name": "pDim", - "Prompt": "REQUIRED: Map of dimensions to include in cell security as a array of 1:0 colon delimited e.g. \"1:0:0:1:0\"", - "Value": "", + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", "Type": "String" } ], diff --git a/bedrock_processes_json/}bedrock.security.cube.cellsecurity.destroy.json b/bedrock_processes_json/}bedrock.security.cube.cellsecurity.destroy.json index b2cc459..731a8a0 100644 --- a/bedrock_processes_json/}bedrock.security.cube.cellsecurity.destroy.json +++ b/bedrock_processes_json/}bedrock.security.cube.cellsecurity.destroy.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.security.cube.cellsecurity.destroy", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.security.cube.cellsecurity.destroy', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n\t 'pCube', '', 'pDelim', '&'\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will destroy the cell security cube(s) for the specified cube(s).\r\n\r\n# Use case: Intended for development.\r\n# 1/ Remove cell level security for one or more cubes.\r\n\r\n# Note:\r\n# Naturally, a valid cube (pCube) is mandatory otherwise the process will abort.\r\n# If the cube does not have cell security set up, it will skip that cube but log an error.\r\n# Multiple cubes can be specified separated by the pDelim or by using wildcards (*).\r\n#EndRegion @DOC\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\nDatasourceASCIIQuoteCharacter = '';\r\ncUserName = TM1User();\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% Message:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pCube:%pCube%, pDelim:%pDelim%.' ; \r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n## check operating system\r\nIf( SubSt( GetProcessErrorFileDirectory, 2, 1 ) @= ':' );\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nElseIf( Scan( '/', GetProcessErrorFileDirectory ) > 0 );\r\n sOS = 'Linux';\r\n sOSDelim = '/';\r\nElse;\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nEndIf;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\n# If blank delimiter specified then convert to default\r\nIf( pDelim @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\n# If no cubes have been specified then terminate process\r\nIf( Trim( pCube ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No cube(s) specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### Split pCubes into individual Cubes ###\r\nsCubes = pCube;\r\nnDelimiterIndex = 1;\r\nWhile( nDelimiterIndex <> 0 );\r\n nDelimiterIndex = Scan( pDelim, sCubes );\r\n If( nDelimiterIndex = 0 );\r\n sCube = sCubes;\r\n Else;\r\n sCube = Trim( SubSt( sCubes, 1, nDelimiterIndex - 1 ) );\r\n sCubes = Trim( Subst( sCubes, nDelimiterIndex + Long(pDelim), Long( sCubes ) ) );\r\n EndIf;\r\n \r\n # Check if a wildcard has been used to specify the Cube name.\r\n # If it hasn't then just delete the Cube if it exists\r\n # If it has then search the relevant Cube folder to find the matches\r\n If( Scan( '*', sCube ) = 0 );\r\n If( CubeExists( sCube ) = 1 ); \r\n If(CubeExists( '}CellSecurity_' | sCube ) = 1);\r\n nRet = CellSecurityCubeDestroy( sCube );\r\n If( nRet = 1 );\r\n sMessage = '}CellSecurity_' | sCube | ' successfully destroyed.';\r\n LogOutput( 'INFO', Expand( cMsgErrorContent ) );\r\n Else;\r\n nErrors = 1;\r\n sMessage = 'Error. Could not destroy }CellSecurity_' | sCube;\r\n LogOutput( 'ERROR', Expand( cMsgErrorContent ) );\r\n EndIf;\r\n Endif;\r\n Endif;\r\n Else;\r\n # Wildcard search string\r\n sSearch = Expand('.%sOSDelim%%sCube%.cub');\r\n\r\n # Find all Cubes that match search string\r\n sFilename = WildcardFileSearch( sSearch, '' );\r\n While( sFilename @<> '' );\r\n # Trim .cub off the filename\r\n sCube = SubSt( sFilename, 1, Long( sFilename ) - 4 );\r\n # Destroy Cube\r\n If( CubeExists( sCube ) = 1 ); \r\n If(CubeExists( '}CellSecurity_' | sCube ) = 1);\r\n nRet = CellSecurityCubeDestroy( sCube );\r\n If( nRet = 1 );\r\n sMessage = '}CellSecurity_' | sCube | ' successfully destroyed.';\r\n LogOutput( 'INFO', Expand( cMsgErrorContent ) );\r\n Else;\r\n nErrors = 1;\r\n sMessage = 'Error. Could not destroy }CellSecurity_' | sCube;\r\n LogOutput( 'ERROR', Expand( cMsgErrorContent ) );\r\n EndIf;\r\n Endif;\r\n Endif;\r\n sFilename = WildcardFileSearch( sSearch, sFilename );\r\n End;\r\n EndIf;\r\n\r\nEnd;\r\n\r\n### End Prolog ###", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.security.cube.cellsecurity.destroy', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n\t 'pCube', '', 'pDelim', '&'\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will destroy the cell security cube(s) for the specified cube(s).\r\n\r\n# Use case: Intended for development.\r\n# 1/ Remove cell level security for one or more cubes.\r\n\r\n# Note:\r\n# Naturally, a valid cube (pCube) is mandatory otherwise the process will abort.\r\n# If the cube does not have cell security set up, it will skip that cube but log an error.\r\n# Multiple cubes can be specified separated by the pDelim or by using wildcards (*).\r\n#EndRegion @DOC\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\nDatasourceASCIIQuoteCharacter = '';\r\ncUserName = TM1User();\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% Message:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pCube:%pCube%, pDelim:%pDelim%.' ;\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pCube\": null,\r\n \"pDelim\": \"&\",\r\n \"pLogOutput\": 0,\r\n \"pStrictErrorHandling\": 0\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pCube\": '|StringToJson ( pCube )|',\r\n \"pDelim\": '|StringToJson ( pDelim )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npCube = JsonToString( JsonGet( pJson, 'pCube' ) );\r\npDelim = JsonToString( JsonGet( pJson, 'pDelim' ) );\r\n# Numeric Parameters\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n## check operating system\r\nIf( SubSt( GetProcessErrorFileDirectory, 2, 1 ) @= ':' );\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nElseIf( Scan( '/', GetProcessErrorFileDirectory ) > 0 );\r\n sOS = 'Linux';\r\n sOSDelim = '/';\r\nElse;\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nEndIf;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\n# If blank delimiter specified then convert to default\r\nIf( pDelim @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\n# If no cubes have been specified then terminate process\r\nIf( Trim( pCube ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No cube(s) specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### Split pCubes into individual Cubes ###\r\nsCubes = pCube;\r\nnDelimiterIndex = 1;\r\nWhile( nDelimiterIndex <> 0 );\r\n nDelimiterIndex = Scan( pDelim, sCubes );\r\n If( nDelimiterIndex = 0 );\r\n sCube = sCubes;\r\n Else;\r\n sCube = Trim( SubSt( sCubes, 1, nDelimiterIndex - 1 ) );\r\n sCubes = Trim( Subst( sCubes, nDelimiterIndex + Long(pDelim), Long( sCubes ) ) );\r\n EndIf;\r\n \r\n # Check if a wildcard has been used to specify the Cube name.\r\n # If it hasn't then just delete the Cube if it exists\r\n # If it has then search the relevant Cube folder to find the matches\r\n If( Scan( '*', sCube ) = 0 );\r\n If( CubeExists( sCube ) = 1 ); \r\n If(CubeExists( '}CellSecurity_' | sCube ) = 1);\r\n nRet = CellSecurityCubeDestroy( sCube );\r\n If( nRet = 1 );\r\n sMessage = '}CellSecurity_' | sCube | ' successfully destroyed.';\r\n LogOutput( 'INFO', Expand( cMsgErrorContent ) );\r\n Else;\r\n nErrors = 1;\r\n sMessage = 'Error. Could not destroy }CellSecurity_' | sCube;\r\n LogOutput( 'ERROR', Expand( cMsgErrorContent ) );\r\n EndIf;\r\n Endif;\r\n Endif;\r\n Else;\r\n # Wildcard search string\r\n sSearch = Expand('.%sOSDelim%%sCube%.cub');\r\n\r\n # Find all Cubes that match search string\r\n sFilename = WildcardFileSearch( sSearch, '' );\r\n While( sFilename @<> '' );\r\n # Trim .cub off the filename\r\n sCube = SubSt( sFilename, 1, Long( sFilename ) - 4 );\r\n # Destroy Cube\r\n If( CubeExists( sCube ) = 1 ); \r\n If(CubeExists( '}CellSecurity_' | sCube ) = 1);\r\n nRet = CellSecurityCubeDestroy( sCube );\r\n If( nRet = 1 );\r\n sMessage = '}CellSecurity_' | sCube | ' successfully destroyed.';\r\n LogOutput( 'INFO', Expand( cMsgErrorContent ) );\r\n Else;\r\n nErrors = 1;\r\n sMessage = 'Error. Could not destroy }CellSecurity_' | sCube;\r\n LogOutput( 'ERROR', Expand( cMsgErrorContent ) );\r\n EndIf;\r\n Endif;\r\n Endif;\r\n sFilename = WildcardFileSearch( sSearch, sFilename );\r\n End;\r\n EndIf;\r\n\r\nEnd;\r\n\r\n### End Prolog ###", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully detsroyed cell security for cube %pCube%.' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\nsProcessReturnCode = pCube;\r\n\r\n### End Epilog ###", @@ -10,28 +10,34 @@ "Type": "None" }, "Parameters": [ + { + "Name": "pCube", + "Prompt": "REQUIRED: Cube name", + "Value": "", + "Type": "String" + }, + { + "Name": "pDelim", + "Prompt": "OPTIONAL: Delimiter for list parameters (Default = '&')", + "Value": "&", + "Type": "String" + }, { "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { - "Name": "pCube", - "Prompt": "REQUIRED: List of Cubes (Separated by Delimiter, Accepts Wild card)", - "Value": "", - "Type": "String" - }, - { - "Name": "pDelim", - "Prompt": "OPTIONAL: Delimiter (Defaults to & if left blank.)", - "Value": "&", + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", "Type": "String" } ], diff --git a/bedrock_processes_json/}bedrock.security.evaluate.mdx.json b/bedrock_processes_json/}bedrock.security.evaluate.mdx.json index 3103a8a..19d2abb 100644 --- a/bedrock_processes_json/}bedrock.security.evaluate.mdx.json +++ b/bedrock_processes_json/}bedrock.security.evaluate.mdx.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.security.evaluate.mdx", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess('}bedrock.security.evaluate.mdx', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pNameSpace', 0,\r\n 'pFilePath', pFilePath,\r\n 'pFileName', pFileName,\r\n 'pDelim', pDelim,\r\n 'pQuote', pQuote\r\n );\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will find out which dimensions have security on them - element security - and evaluate dynamic subsets with expressions impacted by the latest MDX security changes \r\n\r\n# Use case: Intended for development or production.\r\n\r\n\r\n# Note:\r\n# \r\n#EndRegion @DOC\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nStringGlobalVariable('sGlobPrivateSubsetsTotalString');\r\nsGlobPrivateSubsetsTotalString = '';\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncUserName = TM1User();\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pNameSpace:%pNameSpace%, pFilePath:%pFilePath%, pFileName:%pFileName%, pDelim:%pDelim%, pQuote:%pQuote%.' ; \r\ncMsgInfoContent = 'User:%cUserName% Process:%cThisProcName% InfoMsg:%sMessage%';\r\ncSecurityPrefix = '}ElementSecurity_';\r\ncDimDim = '}Dimensions';\r\ncUserDim = '}Clients';\r\ncUserAttrDim= '}ElementAttributes_}Clients';\r\ncUserAlias = '}TM1_DefaultDisplayValue';\r\ncSubsetPrefix = '}Subsets_';\r\ncGroupDim = '}Groups';\r\ncSecCube = '}ClientGroups';\r\n\r\npFieldDelim = TRIM(pDelim);\r\nsCRChar = Char( 13 );\r\nsLFChar = Char( 10 );\r\nsCRLF = Char( 13 ) | Char( 10 );\r\ncLenASCIICode = 3;\r\nnDataCount = 0;\r\nnErrors = 0;\r\n\r\ncKeyWordList = 'DRILLDOWN&.Children&FirstChild&Ancestors&Ascendants&Cousin&DrillUp&FirstSibling&IsAncestor&FirstSibling&LastChild&LastSibling&Descendants';\r\ncKeyWordList = UPPER ( cKeyWordList );\r\ncKeyWordDelimiter = '&';\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\n\r\n# Namespace\r\nIf( pNameSpace <> 0 & pNameSpace <> 1 );\r\n nErrors = 1;\r\n sMessage = 'NameSpace parameter not valid';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n## check operating system\r\nIf( SubSt( GetProcessErrorFileDirectory, 2, 1 ) @= ':' );\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nElseIf( Scan( '/', GetProcessErrorFileDirectory ) > 0 );\r\n sOS = 'Linux';\r\n sOSDelim = '/';\r\nElse;\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nEndIf;\r\n\r\n# Validate file path\r\nIf(Trim( pFilePath ) @= '' );\r\n pFilePath = GetProcessErrorFileDirectory;\r\nEndIf;\r\nIf( SubSt( pFilePath, Long( pFilePath ), 1 ) @= sOSDelim );\r\n pFilePath = SubSt( pFilePath, 1, Long( pFilePath ) -1 );\r\nEndIf;\r\nIf( FileExists( pFilePath ) = 0 );\r\n sMessage = Expand('Invalid export directory: %pFilePath%');\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\npFilePath = pFilePath | sOSDelim;\r\n\r\n# Validate file name\r\nIf( pFileName @= '' );\r\n sBaseFileName = Expand('%cThisProcName%_Export');\r\n sExt = '.csv';\r\n pFileName = sBaseFileName | '.csv';\r\nElse;\r\n # determine file extension. If no file extension entered then use .csv as default\r\n If( Scan( '.', pFileName ) = 0 );\r\n sExt = '.csv';\r\n sBaseFileName = pFileName;\r\n Else;\r\n sExt = SubSt( pFileName, Scan( '.', pFileName ), Long( pFileName ) );\r\n sBaseFileName = SubSt( pFileName, 1, Scan( '.', pFileName ) - 1 );\r\n EndIf;\r\n pFileName = sBaseFileName | sExt;\r\nEndIf;\r\ncExportFile = pFilePath | pFileName;\r\n\r\n# Validate file delimiter & quote character\r\nIf( pFieldDelim @= '' );\r\n pFieldDelim = ',';\r\nElse;\r\n # If length of pFieldDelim is exactly 3 chars and each of them is decimal digit, then the pFieldDelim is entered as ASCII code\r\n nValid = 0;\r\n If ( LONG(pFieldDelim) = cLenASCIICode );\r\n nChar = 1;\r\n While ( nChar <= cLenASCIICode );\r\n If( CODE( pFieldDelim, nChar ) >= CODE( '0', 1 ) & CODE( pFieldDelim, nChar ) <= CODE( '9', 1 ) );\r\n nValid = 1;\r\n Else;\r\n nValid = 0;\r\n EndIf;\r\n nChar = nChar + 1;\r\n End;\r\n EndIf;\r\n If ( nValid<>0 );\r\n pFieldDelim=CHAR(StringToNumber( pFieldDelim ));\r\n Else;\r\n pFieldDelim = SubSt( Trim( pFieldDelim ), 1, 1 );\r\n EndIf;\r\nEndIf;\r\nIf( pQuote @= '' );\r\n ## Use no quote character \r\nElse;\r\n # If length of pQuote is exactly 3 chars and each of them is decimal digit, then the pQuote is entered as ASCII code\r\n nValid = 0;\r\n If ( LONG(pQuote) = cLenASCIICode );\r\n nChar = 1;\r\n While ( nChar <= cLenASCIICode );\r\n If( CODE( pQuote, nChar ) >= CODE( '0', 1 ) & CODE( pQuote, nChar ) <= CODE( '9', 1 ) );\r\n nValid = 1;\r\n Else;\r\n nValid = 0;\r\n EndIf;\r\n nChar = nChar + 1;\r\n End;\r\n EndIf;\r\n If ( nValid<>0 );\r\n pQuote=CHAR(StringToNumber( pQuote ));\r\n Else;\r\n pQuote = SubSt( Trim( pQuote ), 1, 1 );\r\n EndIf;\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\nDatasourceAsciiDelimiter = pFieldDelim;\r\nDatasourceAsciiQuoteCharacter = '';\r\nsTotalRowString = '';\r\n\r\nsTitleRow = '%pQuote%DIMENSION%pQuote%%pFieldDelim%%pQuote%HAS SECURITY%pQuote%%pFieldDelim%%pQuote%SUBSET NAME%pQuote%';\r\nsTitleRow = sTitleRow|'%pFieldDelim%%pQuote%IS PRIVATE%pQuote%%pFieldDelim%%pQuote%MDX EXPRESSION%pQuote%';\r\nsTitleRow = sTitleRow|'%pFieldDelim%%pQuote%KEYWORDS%pQuote%%pFieldDelim%%pQuote%ELEMENTS%pQuote%%pFieldDelim%%pQuote%USERS WITH NO ACCESS%pQuote%';\r\nTextOutput( cExportFile, Expand(sTitleRow) );\r\nsTotalRowString = Expand(sTitleRow);\r\n\r\niDim = 1;\r\nnMaxDim = DimSiz ( cDimDim );\r\n\r\nWhile ( iDim <= nMaxDim );\r\n sDim = DimNm ( cDimDim, iDim );\r\n sSecurityCube = cSecurityPrefix | sDim;\r\n If ( CubeExists ( sSecurityCube ) = 1 );\r\n IF( pLogoutput = 1 );\r\n sMessage = 'The dimension ' | sDim | ' has element security assigned';\r\n LogOutput('INFO', Expand( cMsgInfoContent ) );\r\n ENDIF;\r\n # now we need to go find subsets - two ways of doing this - data directory or }subset dimension\r\n # data directory is the only place to find private subs but need to know the username to loop through\r\n ######################################################################################################################################### \r\n iUser = 1;\r\n nMaxUser = DimSiz ( cUserDim );\r\n While ( iUser <= nMaxUser );\r\n sUser = DimNm ( cUserDim, iUser );\r\n # if CAMId is used folder structure is different\r\n If ( DimIx ( cUserAttrDim, cUserAlias ) > 0 );\r\n sAlias = AttrS ( cUserDim, sUser, cUserAlias );\r\n If ( sAlias @= '' );\r\n sAlias = sUser;\r\n EndIf;\r\n EndIf; \r\n sNamespacePrefix = '';\r\n # if CAMId is used folder structure is different\r\n If ( pNamespace = 1 );\r\n # this \\ or / is hardcoded as it is the CAMID }TM1_DefaultDisplayValue alias which sometimes uses back- and sometimes forward-slash. We aren't sanning for directory separator.\r\n nEnd = Scan( '/', sAlias);\r\n If ( nEnd = 0 );\r\n nEnd = Scan ( '\\', sAlias );\r\n EndIf; \r\n sNamespace = SubSt ( sAlias, 1, nEnd - 1 );\r\n sAlias = SubSt ( sAlias, nEnd + 1, Long ( sAlias ) - nEnd );\r\n sNamespacePrefix = sNameSpace | sOSDelim;\r\n EndIf; \r\n sSubset = WildcardFileSearch( Expand('%sNameSpacePrefix%%sAlias%%sOSDelim%%sDim%}subs%sOSDelim%*.sub') , '');\r\n # loop through all subsets\r\n While ( sSubset @<> '' );\r\n sSubsetName = Subst ( sSubset, 1, LONG ( sSubset ) - 4 );\r\n sFile = Expand('%sNameSpacePrefix%%sAlias%%sOSDelim%%sDim%}subs%sOSDelim%%sSubset%') ;\r\n IF( pLogoutput = 1 );\r\n sMessage = Expand('Private subset called %sSubsetName% found for user %sAlias% in dimension %sDim%. File = %sFile%');\r\n LogOutput('INFO', Expand( cMsgInfoContent ) );\r\n ENDIF;\r\n # run the sub process to evaluate the MDX\r\n If ( sSubset @<> '' );\r\n nRet = ExecuteProcess('}bedrock.security.evaluate.mdx.private',\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pUser', sUser,\r\n 'pDimension', sDim,\r\n 'pSubset', sSubsetName,\r\n 'pSubsetFile', sFile,\r\n 'pFilePath', pFilePath,\r\n 'pFileName', '',\r\n 'pDelim', pDelim,\r\n 'pQuote', pQuote,\r\n 'pWriteOutput', 0\r\n );\r\n If( nRet <> ProcessExitNormal() );\r\n nErrors = nErrors + 1;\r\n sMessage= 'Error in evaluating private subsets.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n EndIf;\r\n\r\n EndIf; \r\n sSubset = WildcardFileSearch( Expand('%sNameSpacePrefix%%sAlias%%sOSDelim%%sDim%}subs%sOSDelim%*.sub') , sSubset); \r\n End; \r\n iUser = iUser + 1;\r\n End; \r\n ########################################################################################################################################## \r\n # for public subsets we can use the subsets dimension\r\n ######################################################################################################################################### \r\n\r\n \r\n sSubsetDim = cSubsetPrefix | sDim;\r\n iSub = 1;\r\n nSubsetMax = DimSiz ( sSubsetDim );\r\n # loop through all subsets\r\n While ( iSub <= nSubsetMax );\r\n sSubsetName = DimNm ( sSubsetDim, iSub );\r\n sMDX = '';\r\n sMDX = SubsetMDXGet ( sDim, sSubsetName );\r\n sMDX = UPPER ( sMDX );\r\n If ( sMDX @<> '' );\r\n ## Remove line breaks from MDX string\r\n nMDXLen = Long( sMDX );\r\n nMDXCount = 1;\r\n While( nMDXCount <= nMDXLen );\r\n sCharPoint = Subst( sMDX, nMDXCount, 1 );\r\n IF( sCharPoint @= sCRChar % sCharPoint @= sLFChar );\r\n Delet( sMDX, nMDXCount, 1 );\r\n nMDXLen = Long( sMDX );\r\n ENDIF;\r\n \r\n nMDXCount = nMDXCount + 1;\r\n End;\r\n nMDXLen = Long( sMDX );\r\n sMDXLastChar = Subst( sMDX, nMDXLen, 1 );\r\n While( sMDXLastChar @<> '}' );\r\n sMDX = Subst( sMDX, 1, nMDXLen - 1 );\r\n nMDXLen = Long( sMDX );\r\n sMDXLastChar = Subst( sMDX, nMDXLen, 1 );\r\n End;\r\n sRow = '%pQuote%%sDim%%pQuote%%pFieldDelim%%pQuote%Y%pQuote%%pFieldDelim%%pQuote%%sSubsetName%%pQuote%%pFieldDelim%%pQuote%NO%pQuote%%pFieldDelim%%pQuote%%sMDX%%pQuote%';\r\n IF( pLogoutput = 1 );\r\n sMessage = Expand('Public subset called %sSubsetName% found in dimension %sDim% with MDX %sMDX%');\r\n LogOutput('INFO', Expand( cMsgInfoContent ) );\r\n ENDIF;\r\n # now parse the MDX \r\n nKeywordFlag = 0;\r\n sKeyWordString = '';\r\n sKeywordList = cKeywordList;\r\n nKeywordLength = Long ( sKeywordList );\r\n While ( nKeywordLength > 0 );\r\n nDelimiter = Scan ( cKeywordDelimiter, sKeyWordList );\r\n If ( nDelimiter = 0 );\r\n sKeyword = sKeyWordList;\r\n sKeyWordList = '';\r\n Else;\r\n nEnd = nDelimiter - 1;\r\n sKeyWord = SubSt ( sKeywordList, 1, nEnd );\r\n sKeyWordList = Subst ( sKeywordList, nEnd + 2, nKeywordLength - nEnd);\r\n EndIf; \r\n If ( Scan( sKeyWord, sMDX ) > 0 );\r\n nKeyWordFlag = nKeyWordFlag + 1;\r\n IF( Long( sKeyWordString ) = 0 );\r\n sKeyWordString = sKeyWordString | sKeyWord;\r\n ELSE;\r\n sKeyWordString = sKeyWordString | pDelim | ' ' | sKeyWord;\r\n ENDIF;\r\n IF( pLogoutput = 1 );\r\n sMessage = 'Keyword ' | sKeyWord | ' found in ' | sMDX;\r\n LogOutput('INFO', Expand( cMsgInfoContent ) );\r\n ENDIF;\r\n EndIf; \r\n nKeywordLength = Long ( sKeywordList );\r\n End; \r\n # if keywords found then see if we can match an element in the MDX with one in the dimension\r\n # element will be included within [] but there will be [dimension][hierarchy][subset][attribute] so could be a false positive\r\n If ( nKeyWordFlag > 0 );\r\n sRow = sRow|'%pFieldDelim%%pQuote%%sKeyWordString%%pQuote%';\r\n sUsersString = '';\r\n sElementString = '';\r\n sMDXTemp = sMDX;\r\n sStarter = '[';\r\n sEnder = ']';\r\n nMDXLength = Long ( sMDXTemp );\r\n While ( nMDXLength > 0 );\r\n nStarter = SCAN ( sStarter, sMDXTemp );\r\n If ( nStarter > 0 );\r\n nEnder = SCAN ( sEnder, sMDXTemp );\r\n sElement = SubSt ( sMDXTemp, nStarter + 1, nEnder - nStarter -1);\r\n nToGo = nMDXLength - nEnder + 1;\r\n sMDXTemp = Subst ( sMDXTemp, nEnder + 1, nToGo );\r\n # check if that is actually an element\r\n If ( DimIx ( sDim, sElement ) > 0 );\r\n IF( Scan( sElement, sElementString ) = 0 );\r\n IF( sElementString @= '' );\r\n sElementString = sElementString | sElement;\r\n ELSE;\r\n sElementString = sElementString | pDelim | ' ' | sElement;\r\n ENDIF;\r\n ENDIF;\r\n IF( pLogoutput = 1 );\r\n sMessage = sElement | ' is referenced in the MDX and exists in the dimension';\r\n LogOutput('INFO', Expand( cMsgInfoContent ) );\r\n ENDIF;\r\n #loop thropugh all users\r\n iUser = 1;\r\n nMaxUser = DimSiz ( cUserDim );\r\n While ( iUser <= nMaxUser );\r\n sUser = DimNm ( cUserDim, iUser );\r\n # now need to loop through relevant groups to see access\r\n # loop through all groups to check access to this element\r\n nUserCheck = 0;\r\n iGroup = 1;\r\n nGroupMax = DimSiz ( cGroupDim );\r\n While ( iGroup <= nGroupMax );\r\n sGroup = DimNm ( cGroupDim, iGroup );\r\n #skip the admin groups!\r\n If ( sGroup @<> 'ADMIN' & sGroup @<> 'SecurityAdmin' & sGroup @<> 'DataAdmin' & sGroup @<> 'OperationsAdmin' );\r\n nCheck = 1;\r\n # if we have a user check membership and we don;t need to continue if not in that group\r\n If ( CellGetS ( cSecCube, sUser, sGroup ) @= '' );\r\n nCheck = 0;\r\n EndIf; \r\n If ( nCheck = 1 );\r\n # get the groups security assignment\r\n sAccess = CellGetS ( sSecurityCube, sElement, sGroup );\r\n # if the user has rights to that element then all is good and we can quit the loops\r\n If ( sAccess @<> '' & sAccess @<> 'NONE' );\r\n nUserCheck = 1;\r\n iGroup = nGroupMax + 1;\r\n EndIf;\r\n EndIf;\r\n Else;\r\n # if the user is in an admin group them they will have access\r\n \r\n If ( CellGetS ( cSecCube, sUser, sGroup ) @<> '' );\r\n nUserCheck = 1;\r\n iGroup = nGroupMax + 1;\r\n EndIf; \r\n EndIf; \r\n iGroup = iGroup + 1;\r\n End; \r\n If ( nUserCheck = 0 );\r\n IF( Scan( sUser, sUsersString ) = 0 );\r\n IF( sUsersString @= '' );\r\n sUsersString = sUsersString | sUser;\r\n ELSE;\r\n sUsersString = sUsersString | pDelim | ' ' | sUser;\r\n ENDIF;\r\n ENDIF;\r\n IF( pLogoutput = 1 );\r\n sMessage = Expand('Public subset %sSubsetName% contains a keyword and a specific element %sElement% that the user %sUser% do not have access to');\r\n LogOutput('INFO', Expand( cMsgInfoContent ) );\r\n ENDIF;\r\n EndIf;\r\n iUser = iUser + 1;\r\n End;\r\n EndIf;\r\n nMDXLength = Long ( sMDXTemp );\r\n Else;\r\n nMDXLength = 0;\r\n EndIf; \r\n End; \r\n \r\n sRow = sRow|'%pFieldDelim%%pQuote%%sElementString%%pQuote%%pFieldDelim%%pQuote%%sUsersString%%pQuote%';\r\n sTotalRowString = sTotalRowString | sCRLF | Expand(sRow);\r\n # Output data\r\n #TextOutput( cExportFile, Expand(sRow) );\r\n EndIf; \r\n EndIf; \r\n iSub = iSub + 1;\r\n End; \r\n\r\n ########################################################################################################################################## \r\n EndIf; \r\n iDim = iDim + 1;\r\nEnd;", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess('}bedrock.security.evaluate.mdx', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pNameSpace', 0,\r\n 'pFilePath', pFilePath,\r\n 'pFileName', pFileName,\r\n 'pDelim', pDelim,\r\n 'pQuote', pQuote\r\n );\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will find out which dimensions have security on them - element security - and evaluate dynamic subsets with expressions impacted by the latest MDX security changes \r\n\r\n# Use case: Intended for development or production.\r\n\r\n\r\n# Note:\r\n# \r\n#EndRegion @DOC\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nStringGlobalVariable('sGlobPrivateSubsetsTotalString');\r\nsGlobPrivateSubsetsTotalString = '';\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncUserName = TM1User();\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pNameSpace:%pNameSpace%, pFilePath:%pFilePath%, pFileName:%pFileName%, pDelim:%pDelim%, pQuote:%pQuote%.' ; \r\ncMsgInfoContent = 'User:%cUserName% Process:%cThisProcName% InfoMsg:%sMessage%';\r\ncSecurityPrefix = '}ElementSecurity_';\r\ncDimDim = '}Dimensions';\r\ncUserDim = '}Clients';\r\ncUserAttrDim= '}ElementAttributes_}Clients';\r\ncUserAlias = '}TM1_DefaultDisplayValue';\r\ncSubsetPrefix = '}Subsets_';\r\ncGroupDim = '}Groups';\r\ncSecCube = '}ClientGroups';\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pDelim\": \"&\",\r\n \"pFileName\": \"\",\r\n \"pFilePath\": \"\",\r\n \"pQuote\": \"\"\",\r\n \"pLogOutput\": 0,\r\n \"pNameSpace\": 0,\r\n \"pStrictErrorHandling\": 0\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pDelim\": '|StringToJson ( pDelim )|',\r\n \"pFileName\": '|StringToJson ( pFileName )|',\r\n \"pFilePath\": '|StringToJson ( pFilePath )|',\r\n \"pQuote\": '|StringToJson ( pQuote )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pNameSpace\": '|NumberToString( pNameSpace )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npDelim = JsonToString( JsonGet( pJson, 'pDelim' ) );\r\npFileName = JsonToString( JsonGet( pJson, 'pFileName' ) );\r\npFilePath = JsonToString( JsonGet( pJson, 'pFilePath' ) );\r\npQuote = JsonToString( JsonGet( pJson, 'pQuote' ) );\r\n# Numeric Parameters\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npNameSpace = StringToNumber( JsonToString( JsonGet( pJson, 'pNameSpace' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\npFieldDelim = TRIM(pDelim);\r\nsCRChar = Char( 13 );\r\nsLFChar = Char( 10 );\r\nsCRLF = Char( 13 ) | Char( 10 );\r\ncLenASCIICode = 3;\r\nnDataCount = 0;\r\nnErrors = 0;\r\n\r\ncKeyWordList = 'DRILLDOWN&.Children&FirstChild&Ancestors&Ascendants&Cousin&DrillUp&FirstSibling&IsAncestor&FirstSibling&LastChild&LastSibling&Descendants';\r\ncKeyWordList = UPPER ( cKeyWordList );\r\ncKeyWordDelimiter = '&';\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\n\r\n# Namespace\r\nIf( pNameSpace <> 0 & pNameSpace <> 1 );\r\n nErrors = 1;\r\n sMessage = 'NameSpace parameter not valid';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n## check operating system\r\nIf( SubSt( GetProcessErrorFileDirectory, 2, 1 ) @= ':' );\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nElseIf( Scan( '/', GetProcessErrorFileDirectory ) > 0 );\r\n sOS = 'Linux';\r\n sOSDelim = '/';\r\nElse;\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nEndIf;\r\n\r\n# Validate file path\r\nIf(Trim( pFilePath ) @= '' );\r\n pFilePath = GetProcessErrorFileDirectory;\r\nEndIf;\r\nIf( SubSt( pFilePath, Long( pFilePath ), 1 ) @= sOSDelim );\r\n pFilePath = SubSt( pFilePath, 1, Long( pFilePath ) -1 );\r\nEndIf;\r\nIf( FileExists( pFilePath ) = 0 );\r\n sMessage = Expand('Invalid export directory: %pFilePath%');\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\npFilePath = pFilePath | sOSDelim;\r\n\r\n# Validate file name\r\nIf( pFileName @= '' );\r\n sBaseFileName = Expand('%cThisProcName%_Export');\r\n sExt = '.csv';\r\n pFileName = sBaseFileName | '.csv';\r\nElse;\r\n # determine file extension. If no file extension entered then use .csv as default\r\n If( Scan( '.', pFileName ) = 0 );\r\n sExt = '.csv';\r\n sBaseFileName = pFileName;\r\n Else;\r\n sExt = SubSt( pFileName, Scan( '.', pFileName ), Long( pFileName ) );\r\n sBaseFileName = SubSt( pFileName, 1, Scan( '.', pFileName ) - 1 );\r\n EndIf;\r\n pFileName = sBaseFileName | sExt;\r\nEndIf;\r\ncExportFile = pFilePath | pFileName;\r\n\r\n# Validate file delimiter & quote character\r\nIf( pFieldDelim @= '' );\r\n pFieldDelim = ',';\r\nElse;\r\n # If length of pFieldDelim is exactly 3 chars and each of them is decimal digit, then the pFieldDelim is entered as ASCII code\r\n nValid = 0;\r\n If ( LONG(pFieldDelim) = cLenASCIICode );\r\n nChar = 1;\r\n While ( nChar <= cLenASCIICode );\r\n If( CODE( pFieldDelim, nChar ) >= CODE( '0', 1 ) & CODE( pFieldDelim, nChar ) <= CODE( '9', 1 ) );\r\n nValid = 1;\r\n Else;\r\n nValid = 0;\r\n EndIf;\r\n nChar = nChar + 1;\r\n End;\r\n EndIf;\r\n If ( nValid<>0 );\r\n pFieldDelim=CHAR(StringToNumber( pFieldDelim ));\r\n Else;\r\n pFieldDelim = SubSt( Trim( pFieldDelim ), 1, 1 );\r\n EndIf;\r\nEndIf;\r\nIf( pQuote @= '' );\r\n ## Use no quote character \r\nElse;\r\n # If length of pQuote is exactly 3 chars and each of them is decimal digit, then the pQuote is entered as ASCII code\r\n nValid = 0;\r\n If ( LONG(pQuote) = cLenASCIICode );\r\n nChar = 1;\r\n While ( nChar <= cLenASCIICode );\r\n If( CODE( pQuote, nChar ) >= CODE( '0', 1 ) & CODE( pQuote, nChar ) <= CODE( '9', 1 ) );\r\n nValid = 1;\r\n Else;\r\n nValid = 0;\r\n EndIf;\r\n nChar = nChar + 1;\r\n End;\r\n EndIf;\r\n If ( nValid<>0 );\r\n pQuote=CHAR(StringToNumber( pQuote ));\r\n Else;\r\n pQuote = SubSt( Trim( pQuote ), 1, 1 );\r\n EndIf;\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\nDatasourceAsciiDelimiter = pFieldDelim;\r\nDatasourceAsciiQuoteCharacter = '';\r\nsTotalRowString = '';\r\n\r\nsTitleRow = '%pQuote%DIMENSION%pQuote%%pFieldDelim%%pQuote%HAS SECURITY%pQuote%%pFieldDelim%%pQuote%SUBSET NAME%pQuote%';\r\nsTitleRow = sTitleRow|'%pFieldDelim%%pQuote%IS PRIVATE%pQuote%%pFieldDelim%%pQuote%MDX EXPRESSION%pQuote%';\r\nsTitleRow = sTitleRow|'%pFieldDelim%%pQuote%KEYWORDS%pQuote%%pFieldDelim%%pQuote%ELEMENTS%pQuote%%pFieldDelim%%pQuote%USERS WITH NO ACCESS%pQuote%';\r\nTextOutput( cExportFile, Expand(sTitleRow) );\r\nsTotalRowString = Expand(sTitleRow);\r\n\r\niDim = 1;\r\nnMaxDim = DimSiz ( cDimDim );\r\n\r\nWhile ( iDim <= nMaxDim );\r\n sDim = DimNm ( cDimDim, iDim );\r\n sSecurityCube = cSecurityPrefix | sDim;\r\n If ( CubeExists ( sSecurityCube ) = 1 );\r\n IF( pLogoutput = 1 );\r\n sMessage = 'The dimension ' | sDim | ' has element security assigned';\r\n LogOutput('INFO', Expand( cMsgInfoContent ) );\r\n ENDIF;\r\n # now we need to go find subsets - two ways of doing this - data directory or }subset dimension\r\n # data directory is the only place to find private subs but need to know the username to loop through\r\n ######################################################################################################################################### \r\n iUser = 1;\r\n nMaxUser = DimSiz ( cUserDim );\r\n While ( iUser <= nMaxUser );\r\n sUser = DimNm ( cUserDim, iUser );\r\n # if CAMId is used folder structure is different\r\n If ( DimIx ( cUserAttrDim, cUserAlias ) > 0 );\r\n sAlias = AttrS ( cUserDim, sUser, cUserAlias );\r\n If ( sAlias @= '' );\r\n sAlias = sUser;\r\n EndIf;\r\n EndIf; \r\n sNamespacePrefix = '';\r\n # if CAMId is used folder structure is different\r\n If ( pNamespace = 1 );\r\n # this \\ or / is hardcoded as it is the CAMID }TM1_DefaultDisplayValue alias which sometimes uses back- and sometimes forward-slash. We aren't sanning for directory separator.\r\n nEnd = Scan( '/', sAlias);\r\n If ( nEnd = 0 );\r\n nEnd = Scan ( '\\', sAlias );\r\n EndIf; \r\n sNamespace = SubSt ( sAlias, 1, nEnd - 1 );\r\n sAlias = SubSt ( sAlias, nEnd + 1, Long ( sAlias ) - nEnd );\r\n sNamespacePrefix = sNameSpace | sOSDelim;\r\n EndIf; \r\n sSubset = WildcardFileSearch( Expand('%sNameSpacePrefix%%sAlias%%sOSDelim%%sDim%}subs%sOSDelim%*.sub') , '');\r\n # loop through all subsets\r\n While ( sSubset @<> '' );\r\n sSubsetName = Subst ( sSubset, 1, LONG ( sSubset ) - 4 );\r\n sFile = Expand('%sNameSpacePrefix%%sAlias%%sOSDelim%%sDim%}subs%sOSDelim%%sSubset%') ;\r\n IF( pLogoutput = 1 );\r\n sMessage = Expand('Private subset called %sSubsetName% found for user %sAlias% in dimension %sDim%. File = %sFile%');\r\n LogOutput('INFO', Expand( cMsgInfoContent ) );\r\n ENDIF;\r\n # run the sub process to evaluate the MDX\r\n If ( sSubset @<> '' );\r\n nRet = ExecuteProcess('}bedrock.security.evaluate.mdx.private',\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pUser', sUser,\r\n 'pDimension', sDim,\r\n 'pSubset', sSubsetName,\r\n 'pSubsetFile', sFile,\r\n 'pFilePath', pFilePath,\r\n 'pFileName', '',\r\n 'pDelim', pDelim,\r\n 'pQuote', pQuote,\r\n 'pWriteOutput', 0\r\n );\r\n If( nRet <> ProcessExitNormal() );\r\n nErrors = nErrors + 1;\r\n sMessage= 'Error in evaluating private subsets.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n EndIf;\r\n\r\n EndIf; \r\n sSubset = WildcardFileSearch( Expand('%sNameSpacePrefix%%sAlias%%sOSDelim%%sDim%}subs%sOSDelim%*.sub') , sSubset); \r\n End; \r\n iUser = iUser + 1;\r\n End; \r\n ########################################################################################################################################## \r\n # for public subsets we can use the subsets dimension\r\n ######################################################################################################################################### \r\n\r\n \r\n sSubsetDim = cSubsetPrefix | sDim;\r\n iSub = 1;\r\n nSubsetMax = DimSiz ( sSubsetDim );\r\n # loop through all subsets\r\n While ( iSub <= nSubsetMax );\r\n sSubsetName = DimNm ( sSubsetDim, iSub );\r\n sMDX = '';\r\n sMDX = SubsetMDXGet ( sDim, sSubsetName );\r\n sMDX = UPPER ( sMDX );\r\n If ( sMDX @<> '' );\r\n ## Remove line breaks from MDX string\r\n nMDXLen = Long( sMDX );\r\n nMDXCount = 1;\r\n While( nMDXCount <= nMDXLen );\r\n sCharPoint = Subst( sMDX, nMDXCount, 1 );\r\n IF( sCharPoint @= sCRChar % sCharPoint @= sLFChar );\r\n Delet( sMDX, nMDXCount, 1 );\r\n nMDXLen = Long( sMDX );\r\n ENDIF;\r\n \r\n nMDXCount = nMDXCount + 1;\r\n End;\r\n nMDXLen = Long( sMDX );\r\n sMDXLastChar = Subst( sMDX, nMDXLen, 1 );\r\n While( sMDXLastChar @<> '}' );\r\n sMDX = Subst( sMDX, 1, nMDXLen - 1 );\r\n nMDXLen = Long( sMDX );\r\n sMDXLastChar = Subst( sMDX, nMDXLen, 1 );\r\n End;\r\n sRow = '%pQuote%%sDim%%pQuote%%pFieldDelim%%pQuote%Y%pQuote%%pFieldDelim%%pQuote%%sSubsetName%%pQuote%%pFieldDelim%%pQuote%NO%pQuote%%pFieldDelim%%pQuote%%sMDX%%pQuote%';\r\n IF( pLogoutput = 1 );\r\n sMessage = Expand('Public subset called %sSubsetName% found in dimension %sDim% with MDX %sMDX%');\r\n LogOutput('INFO', Expand( cMsgInfoContent ) );\r\n ENDIF;\r\n # now parse the MDX \r\n nKeywordFlag = 0;\r\n sKeyWordString = '';\r\n sKeywordList = cKeywordList;\r\n nKeywordLength = Long ( sKeywordList );\r\n While ( nKeywordLength > 0 );\r\n nDelimiter = Scan ( cKeywordDelimiter, sKeyWordList );\r\n If ( nDelimiter = 0 );\r\n sKeyword = sKeyWordList;\r\n sKeyWordList = '';\r\n Else;\r\n nEnd = nDelimiter - 1;\r\n sKeyWord = SubSt ( sKeywordList, 1, nEnd );\r\n sKeyWordList = Subst ( sKeywordList, nEnd + 2, nKeywordLength - nEnd);\r\n EndIf; \r\n If ( Scan( sKeyWord, sMDX ) > 0 );\r\n nKeyWordFlag = nKeyWordFlag + 1;\r\n IF( Long( sKeyWordString ) = 0 );\r\n sKeyWordString = sKeyWordString | sKeyWord;\r\n ELSE;\r\n sKeyWordString = sKeyWordString | pDelim | ' ' | sKeyWord;\r\n ENDIF;\r\n IF( pLogoutput = 1 );\r\n sMessage = 'Keyword ' | sKeyWord | ' found in ' | sMDX;\r\n LogOutput('INFO', Expand( cMsgInfoContent ) );\r\n ENDIF;\r\n EndIf; \r\n nKeywordLength = Long ( sKeywordList );\r\n End; \r\n # if keywords found then see if we can match an element in the MDX with one in the dimension\r\n # element will be included within [] but there will be [dimension][hierarchy][subset][attribute] so could be a false positive\r\n If ( nKeyWordFlag > 0 );\r\n sRow = sRow|'%pFieldDelim%%pQuote%%sKeyWordString%%pQuote%';\r\n sUsersString = '';\r\n sElementString = '';\r\n sMDXTemp = sMDX;\r\n sStarter = '[';\r\n sEnder = ']';\r\n nMDXLength = Long ( sMDXTemp );\r\n While ( nMDXLength > 0 );\r\n nStarter = SCAN ( sStarter, sMDXTemp );\r\n If ( nStarter > 0 );\r\n nEnder = SCAN ( sEnder, sMDXTemp );\r\n sElement = SubSt ( sMDXTemp, nStarter + 1, nEnder - nStarter -1);\r\n nToGo = nMDXLength - nEnder + 1;\r\n sMDXTemp = Subst ( sMDXTemp, nEnder + 1, nToGo );\r\n # check if that is actually an element\r\n If ( DimIx ( sDim, sElement ) > 0 );\r\n IF( Scan( sElement, sElementString ) = 0 );\r\n IF( sElementString @= '' );\r\n sElementString = sElementString | sElement;\r\n ELSE;\r\n sElementString = sElementString | pDelim | ' ' | sElement;\r\n ENDIF;\r\n ENDIF;\r\n IF( pLogoutput = 1 );\r\n sMessage = sElement | ' is referenced in the MDX and exists in the dimension';\r\n LogOutput('INFO', Expand( cMsgInfoContent ) );\r\n ENDIF;\r\n #loop thropugh all users\r\n iUser = 1;\r\n nMaxUser = DimSiz ( cUserDim );\r\n While ( iUser <= nMaxUser );\r\n sUser = DimNm ( cUserDim, iUser );\r\n # now need to loop through relevant groups to see access\r\n # loop through all groups to check access to this element\r\n nUserCheck = 0;\r\n iGroup = 1;\r\n nGroupMax = DimSiz ( cGroupDim );\r\n While ( iGroup <= nGroupMax );\r\n sGroup = DimNm ( cGroupDim, iGroup );\r\n #skip the admin groups!\r\n If ( sGroup @<> 'ADMIN' & sGroup @<> 'SecurityAdmin' & sGroup @<> 'DataAdmin' & sGroup @<> 'OperationsAdmin' );\r\n nCheck = 1;\r\n # if we have a user check membership and we don;t need to continue if not in that group\r\n If ( CellGetS ( cSecCube, sUser, sGroup ) @= '' );\r\n nCheck = 0;\r\n EndIf; \r\n If ( nCheck = 1 );\r\n # get the groups security assignment\r\n sAccess = CellGetS ( sSecurityCube, sElement, sGroup );\r\n # if the user has rights to that element then all is good and we can quit the loops\r\n If ( sAccess @<> '' & sAccess @<> 'NONE' );\r\n nUserCheck = 1;\r\n iGroup = nGroupMax + 1;\r\n EndIf;\r\n EndIf;\r\n Else;\r\n # if the user is in an admin group them they will have access\r\n \r\n If ( CellGetS ( cSecCube, sUser, sGroup ) @<> '' );\r\n nUserCheck = 1;\r\n iGroup = nGroupMax + 1;\r\n EndIf; \r\n EndIf; \r\n iGroup = iGroup + 1;\r\n End; \r\n If ( nUserCheck = 0 );\r\n IF( Scan( sUser, sUsersString ) = 0 );\r\n IF( sUsersString @= '' );\r\n sUsersString = sUsersString | sUser;\r\n ELSE;\r\n sUsersString = sUsersString | pDelim | ' ' | sUser;\r\n ENDIF;\r\n ENDIF;\r\n IF( pLogoutput = 1 );\r\n sMessage = Expand('Public subset %sSubsetName% contains a keyword and a specific element %sElement% that the user %sUser% do not have access to');\r\n LogOutput('INFO', Expand( cMsgInfoContent ) );\r\n ENDIF;\r\n EndIf;\r\n iUser = iUser + 1;\r\n End;\r\n EndIf;\r\n nMDXLength = Long ( sMDXTemp );\r\n Else;\r\n nMDXLength = 0;\r\n EndIf; \r\n End; \r\n \r\n sRow = sRow|'%pFieldDelim%%pQuote%%sElementString%%pQuote%%pFieldDelim%%pQuote%%sUsersString%%pQuote%';\r\n sTotalRowString = sTotalRowString | sCRLF | Expand(sRow);\r\n # Output data\r\n #TextOutput( cExportFile, Expand(sRow) );\r\n EndIf; \r\n EndIf; \r\n iSub = iSub + 1;\r\n End; \r\n\r\n ########################################################################################################################################## \r\n EndIf; \r\n iDim = iDim + 1;\r\nEnd;", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n### Write Output data\r\nIf( nErrors = 0 );\r\n TextOutput( cExportFile, sTotalRowString );\r\n TextOutput( cExportFile, sGlobPrivateSubsetsTotalString );\r\nENDIF;\r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully created report file.' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n\r\n\r\n### End Epilog ###\r\n", @@ -10,47 +10,53 @@ "Type": "None" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pNameSpace", - "Prompt": "If CAM ID is used we need to check namespaces enter 1 for CAMID 0 for not (mode 1)", + "Prompt": "OPTIONAL: If CAM ID is used we need to check namespaces (1 = Using CAMID. Default = 0)", "Value": 0, "Type": "Numeric" }, { "Name": "pFilePath", - "Prompt": "OPTIONAL: Export Directory (will default to error file path)", + "Prompt": "OPTIONAL: File directory (Default = GetProcessErrorFileDirectory)", "Value": "", "Type": "String" }, { "Name": "pFileName", - "Prompt": "OPTIONAL: Export Filename (If Left Blank Defaults to processname_export.csv)", + "Prompt": "OPTIONAL: File name (Default = pCube | '_Export.csv')", "Value": "", "Type": "String" }, { "Name": "pDelim", - "Prompt": "OPTIONAL: AsciiOutput delimiter character (Default=comma, exactly 3 digits = ASCII code)", - "Value": ",", + "Prompt": "OPTIONAL: Delimiter for list parameters (Default = '&')", + "Value": "&", "Type": "String" }, { "Name": "pQuote", - "Prompt": "OPTIONAL: AsciiOutput quote character (Accepts empty quote, exactly 3 digits = ASCII code)", + "Prompt": "OPTIONAL: Quote character (2 or 3 digits = ASCII code. Default = '\"')", "Value": "\"", "Type": "String" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [], diff --git a/bedrock_processes_json/}bedrock.security.evaluate.mdx.private.json b/bedrock_processes_json/}bedrock.security.evaluate.mdx.private.json index e41eac2..ec89a96 100644 --- a/bedrock_processes_json/}bedrock.security.evaluate.mdx.private.json +++ b/bedrock_processes_json/}bedrock.security.evaluate.mdx.private.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.security.evaluate.mdx.private", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess('}bedrock.security.evaluate.mdx.private',\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pUser', pUser,\r\n 'pDimension', pDimension,\r\n 'pSubset', pSubset,\r\n 'pSubsetFile', pSubsetFile,\r\n 'pFilePath', pFilePath,\r\n 'pFileName', pFileName,\r\n 'pDelim', pDelim,\r\n 'pQuote', pQuote\r\n );\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will find out PRIVATE dynamic subsets of dimensions having security on them - element security - and evaluate expressions impacted by the latest MDX security changes \r\n\r\n# Use case: Intended for development or production.\r\n\r\n# Note:\r\n# \r\n#EndRegion @DOC\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nStringGlobalVariable('sGlobPrivateSubsetsTotalString');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncUserName = TM1User();\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pUser:%pUser%, pDimension:%pDimension%, pSubset:%pSubset%, pSubsetFile:%pSubsetFile%, pFilePath:%pFilePath%, pFileName:%pFileName%, pDelim:%pDelim%, pQuote:%pQuote%.' ; \r\ncMsgInfoContent = 'User:%cUserName% Process:%cThisProcName% InfoMsg:%sMessage%';\r\ncSecurityPrefix = '}ElementSecurity_';\r\ncDimDim = '}Dimensions';\r\ncUserDim = '}Clients';\r\ncUserAttrDim= '}ElementAttributes_}Clients';\r\ncUserAlias = '}TM1_DefaultDisplayValue';\r\ncSubsetPrefix = '}Subsets_';\r\ncGroupDim = '}Groups';\r\ncSecCube = '}ClientGroups';\r\nnGroupMax = DimSiz ( cGroupDim );\r\nnUserMax = DimSiz ( cUserDim );\r\ncEleSecCube = cSecurityPrefix | pDimension;\r\n\r\npFieldDelim = TRIM(pDelim);\r\nsCRLF = Char( 13 ) | Char( 10 );\r\ncLenASCIICode = 3;\r\nnDataCount = 0;\r\nnErrors = 0;\r\n\r\n#reset flag and string\r\nnMDXFlag = 0;\r\nsMDX = '';\r\nsTotalRowString = '';\r\n\r\n#keywords to look out for in an MDX expression\r\ncKeyWordList = 'DRILLDOWN&.Children&FirstChild&Ancestors&Ascendants&Cousin&DrillUp&FirstSibling&IsAncestor&FirstSibling&LastChild&LastSibling&Descendants';\r\ncKeyWordList = UPPER ( cKeyWordList );\r\ncKeyWordDelimiter = '&';\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\n\r\n# Validate user\r\nIF( DimIx( cUserDim, pUser) = 0 );\r\n sMessage = Expand('Invalid user: %pUser%');\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nENDIF;\r\n\r\n# Validate dimension\r\nIF( DimIx( cDimDim, pDimension) = 0 );\r\n sMessage = Expand('Invalid dimension: %pDimension%');\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nENDIF;\r\n\r\n# Validate subset name\r\nIF( pSubset @= '' % Scan( pSubset, pSubsetFile ) = 0 );\r\n sMessage = Expand('Invalid subset name: %pSubset%');\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nENDIF;\r\n\r\n## check operating system\r\nIf( SubSt( GetProcessErrorFileDirectory, 2, 1 ) @= ':' );\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nElseIf( Scan( '/', GetProcessErrorFileDirectory ) > 0 );\r\n sOS = 'Linux';\r\n sOSDelim = '/';\r\nElse;\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nEndIf;\r\n\r\n# Validate file path\r\nIf(Trim( pFilePath ) @= '' );\r\n pFilePath = GetProcessErrorFileDirectory;\r\nEndIf;\r\nIf( SubSt( pFilePath, Long( pFilePath ), 1 ) @= sOSDelim );\r\n pFilePath = SubSt( pFilePath, 1, Long( pFilePath ) -1 );\r\nEndIf;\r\nIf( FileExists( pFilePath ) = 0 );\r\n sMessage = Expand('Invalid export directory: %pFilePath%');\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\npFilePath = pFilePath | sOSDelim;\r\n\r\n# Validate file name\r\nIf( pFileName @= '' );\r\n sBaseFileName = Expand('%cThisProcName%_%pUser%_%pDimension%_%pSubset%_Export');\r\n sExt = '.csv';\r\n pFileName = sBaseFileName | '.csv';\r\nElse;\r\n # determine file extension. If no file extension entered then use .csv as default\r\n If( Scan( '.', pFileName ) = 0 );\r\n sExt = '.csv';\r\n sBaseFileName = pFileName;\r\n Else;\r\n sExt = SubSt( pFileName, Scan( '.', pFileName ), Long( pFileName ) );\r\n sBaseFileName = SubSt( pFileName, 1, Scan( '.', pFileName ) - 1 );\r\n EndIf;\r\n pFileName = sBaseFileName | sExt;\r\nEndIf;\r\ncExportFile = pFilePath | pFileName;\r\n\r\n# Validate file delimiter & quote character\r\nIf( pFieldDelim @= '' );\r\n pFieldDelim = ',';\r\nElse;\r\n # If length of pFieldDelim is exactly 3 chars and each of them is decimal digit, then the pFieldDelim is entered as ASCII code\r\n nValid = 0;\r\n If ( LONG(pFieldDelim) = cLenASCIICode );\r\n nChar = 1;\r\n While ( nChar <= cLenASCIICode );\r\n If( CODE( pFieldDelim, nChar ) >= CODE( '0', 1 ) & CODE( pFieldDelim, nChar ) <= CODE( '9', 1 ) );\r\n nValid = 1;\r\n Else;\r\n nValid = 0;\r\n EndIf;\r\n nChar = nChar + 1;\r\n End;\r\n EndIf;\r\n If ( nValid<>0 );\r\n pFieldDelim=CHAR(StringToNumber( pFieldDelim ));\r\n Else;\r\n pFieldDelim = SubSt( Trim( pFieldDelim ), 1, 1 );\r\n EndIf;\r\nEndIf;\r\nIf( pQuote @= '' );\r\n ## Use no quote character \r\nElse;\r\n # If length of pQuote is exactly 3 chars and each of them is decimal digit, then the pQuote is entered as ASCII code\r\n nValid = 0;\r\n If ( LONG(pQuote) = cLenASCIICode );\r\n nChar = 1;\r\n While ( nChar <= cLenASCIICode );\r\n If( CODE( pQuote, nChar ) >= CODE( '0', 1 ) & CODE( pQuote, nChar ) <= CODE( '9', 1 ) );\r\n nValid = 1;\r\n Else;\r\n nValid = 0;\r\n EndIf;\r\n nChar = nChar + 1;\r\n End;\r\n EndIf;\r\n If ( nValid<>0 );\r\n pQuote=CHAR(StringToNumber( pQuote ));\r\n Else;\r\n pQuote = SubSt( Trim( pQuote ), 1, 1 );\r\n EndIf;\r\nEndIf;\r\n\r\n# Validate subset file\r\n\r\nIf ( FileExists( pSubsetFile ) = 0 );\r\n sMessage = Expand('Invalid subset file: %pSubsetFile%');\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### Initialize output\r\n\r\nsTotalOutputRowString = '';\r\nIF( pWriteOutput <> 0 );\r\n sTitleRow = '%pQuote%DIMENSION%pQuote%%pFieldDelim%%pQuote%HAS SECURITY%pQuote%%pFieldDelim%%pQuote%SUBSET NAME%pQuote%';\r\n sTitleRow = sTitleRow|'%pFieldDelim%%pQuote%IS PRIVATE%pQuote%%pFieldDelim%%pQuote%MDX EXPRESSION%pQuote%';\r\n sTitleRow = sTitleRow|'%pFieldDelim%%pQuote%KEYWORDS%pQuote%%pFieldDelim%%pQuote%ELEMENTS%pQuote%%pFieldDelim%%pQuote%USERS WITH NO ACCESS%pQuote%';\r\n sTotalOutputRowString = Expand(sTitleRow);\r\nENDIF;\r\nsRow = '';\r\n\r\n### Assign data source\r\nIf( nErrors = 0 );\r\n DataSourceType ='CHARACTERDELIMITED';\r\n DatasourceNameForServer = pSubsetFile;\r\n DatasourceASCIIDelimiter='@@';\r\nEndIF;\r\n", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess('}bedrock.security.evaluate.mdx.private',\r\n 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n 'pUser', pUser,\r\n 'pDimension', pDimension,\r\n 'pSubset', pSubset,\r\n 'pSubsetFile', pSubsetFile,\r\n 'pFilePath', pFilePath,\r\n 'pFileName', pFileName,\r\n 'pDelim', pDelim,\r\n 'pQuote', pQuote\r\n );\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will find out PRIVATE dynamic subsets of dimensions having security on them - element security - and evaluate expressions impacted by the latest MDX security changes \r\n\r\n# Use case: Intended for development or production.\r\n\r\n# Note:\r\n# \r\n#EndRegion @DOC\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nStringGlobalVariable('sGlobPrivateSubsetsTotalString');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncUserName = TM1User();\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pUser:%pUser%, pDimension:%pDimension%, pSubset:%pSubset%, pSubsetFile:%pSubsetFile%, pFilePath:%pFilePath%, pFileName:%pFileName%, pDelim:%pDelim%, pQuote:%pQuote%.' ; \r\ncMsgInfoContent = 'User:%cUserName% Process:%cThisProcName% InfoMsg:%sMessage%';\r\ncSecurityPrefix = '}ElementSecurity_';\r\ncDimDim = '}Dimensions';\r\ncUserDim = '}Clients';\r\ncUserAttrDim= '}ElementAttributes_}Clients';\r\ncUserAlias = '}TM1_DefaultDisplayValue';\r\ncSubsetPrefix = '}Subsets_';\r\ncGroupDim = '}Groups';\r\ncSecCube = '}ClientGroups';\r\nnGroupMax = DimSiz ( cGroupDim );\r\nnUserMax = DimSiz ( cUserDim );\r\ncEleSecCube = cSecurityPrefix | pDimension;\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pDelim\": \"&\",\r\n \"pDimension\": null,\r\n \"pFileName\": \"\",\r\n \"pFilePath\": \"\",\r\n \"pQuote\": \"\"\",\r\n \"pSubset\": null,\r\n \"pSubsetFile\": null,\r\n \"pUser\": null,\r\n \"pLogOutput\": 0,\r\n \"pStrictErrorHandling\": 0,\r\n \"pWriteOutput\": 1\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pDelim\": '|StringToJson ( pDelim )|',\r\n \"pDimension\": '|StringToJson ( pDimension )|',\r\n \"pFileName\": '|StringToJson ( pFileName )|',\r\n \"pFilePath\": '|StringToJson ( pFilePath )|',\r\n \"pQuote\": '|StringToJson ( pQuote )|',\r\n \"pSubset\": '|StringToJson ( pSubset )|',\r\n \"pSubsetFile\": '|StringToJson ( pSubsetFile )|',\r\n \"pUser\": '|StringToJson ( pUser )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|',\r\n \"pWriteOutput\": '|NumberToString( pWriteOutput )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npDelim = JsonToString( JsonGet( pJson, 'pDelim' ) );\r\npDimension = JsonToString( JsonGet( pJson, 'pDimension' ) );\r\npFileName = JsonToString( JsonGet( pJson, 'pFileName' ) );\r\npFilePath = JsonToString( JsonGet( pJson, 'pFilePath' ) );\r\npQuote = JsonToString( JsonGet( pJson, 'pQuote' ) );\r\npSubset = JsonToString( JsonGet( pJson, 'pSubset' ) );\r\npSubsetFile = JsonToString( JsonGet( pJson, 'pSubsetFile' ) );\r\npUser = JsonToString( JsonGet( pJson, 'pUser' ) );\r\n# Numeric Parameters\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\npWriteOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pWriteOutput' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\npFieldDelim = TRIM(pDelim);\r\nsCRLF = Char( 13 ) | Char( 10 );\r\ncLenASCIICode = 3;\r\nnDataCount = 0;\r\nnErrors = 0;\r\n\r\n#reset flag and string\r\nnMDXFlag = 0;\r\nsMDX = '';\r\nsTotalRowString = '';\r\n\r\n#keywords to look out for in an MDX expression\r\ncKeyWordList = 'DRILLDOWN&.Children&FirstChild&Ancestors&Ascendants&Cousin&DrillUp&FirstSibling&IsAncestor&FirstSibling&LastChild&LastSibling&Descendants';\r\ncKeyWordList = UPPER ( cKeyWordList );\r\ncKeyWordDelimiter = '&';\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\n\r\n# Validate user\r\nIF( DimIx( cUserDim, pUser) = 0 );\r\n sMessage = Expand('Invalid user: %pUser%');\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nENDIF;\r\n\r\n# Validate dimension\r\nIF( DimIx( cDimDim, pDimension) = 0 );\r\n sMessage = Expand('Invalid dimension: %pDimension%');\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nENDIF;\r\n\r\n# Validate subset name\r\nIF( pSubset @= '' % Scan( pSubset, pSubsetFile ) = 0 );\r\n sMessage = Expand('Invalid subset name: %pSubset%');\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nENDIF;\r\n\r\n## check operating system\r\nIf( SubSt( GetProcessErrorFileDirectory, 2, 1 ) @= ':' );\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nElseIf( Scan( '/', GetProcessErrorFileDirectory ) > 0 );\r\n sOS = 'Linux';\r\n sOSDelim = '/';\r\nElse;\r\n sOS = 'Windows';\r\n sOSDelim = '\\';\r\nEndIf;\r\n\r\n# Validate file path\r\nIf(Trim( pFilePath ) @= '' );\r\n pFilePath = GetProcessErrorFileDirectory;\r\nEndIf;\r\nIf( SubSt( pFilePath, Long( pFilePath ), 1 ) @= sOSDelim );\r\n pFilePath = SubSt( pFilePath, 1, Long( pFilePath ) -1 );\r\nEndIf;\r\nIf( FileExists( pFilePath ) = 0 );\r\n sMessage = Expand('Invalid export directory: %pFilePath%');\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\npFilePath = pFilePath | sOSDelim;\r\n\r\n# Validate file name\r\nIf( pFileName @= '' );\r\n sBaseFileName = Expand('%cThisProcName%_%pUser%_%pDimension%_%pSubset%_Export');\r\n sExt = '.csv';\r\n pFileName = sBaseFileName | '.csv';\r\nElse;\r\n # determine file extension. If no file extension entered then use .csv as default\r\n If( Scan( '.', pFileName ) = 0 );\r\n sExt = '.csv';\r\n sBaseFileName = pFileName;\r\n Else;\r\n sExt = SubSt( pFileName, Scan( '.', pFileName ), Long( pFileName ) );\r\n sBaseFileName = SubSt( pFileName, 1, Scan( '.', pFileName ) - 1 );\r\n EndIf;\r\n pFileName = sBaseFileName | sExt;\r\nEndIf;\r\ncExportFile = pFilePath | pFileName;\r\n\r\n# Validate file delimiter & quote character\r\nIf( pFieldDelim @= '' );\r\n pFieldDelim = ',';\r\nElse;\r\n # If length of pFieldDelim is exactly 3 chars and each of them is decimal digit, then the pFieldDelim is entered as ASCII code\r\n nValid = 0;\r\n If ( LONG(pFieldDelim) = cLenASCIICode );\r\n nChar = 1;\r\n While ( nChar <= cLenASCIICode );\r\n If( CODE( pFieldDelim, nChar ) >= CODE( '0', 1 ) & CODE( pFieldDelim, nChar ) <= CODE( '9', 1 ) );\r\n nValid = 1;\r\n Else;\r\n nValid = 0;\r\n EndIf;\r\n nChar = nChar + 1;\r\n End;\r\n EndIf;\r\n If ( nValid<>0 );\r\n pFieldDelim=CHAR(StringToNumber( pFieldDelim ));\r\n Else;\r\n pFieldDelim = SubSt( Trim( pFieldDelim ), 1, 1 );\r\n EndIf;\r\nEndIf;\r\nIf( pQuote @= '' );\r\n ## Use no quote character \r\nElse;\r\n # If length of pQuote is exactly 3 chars and each of them is decimal digit, then the pQuote is entered as ASCII code\r\n nValid = 0;\r\n If ( LONG(pQuote) = cLenASCIICode );\r\n nChar = 1;\r\n While ( nChar <= cLenASCIICode );\r\n If( CODE( pQuote, nChar ) >= CODE( '0', 1 ) & CODE( pQuote, nChar ) <= CODE( '9', 1 ) );\r\n nValid = 1;\r\n Else;\r\n nValid = 0;\r\n EndIf;\r\n nChar = nChar + 1;\r\n End;\r\n EndIf;\r\n If ( nValid<>0 );\r\n pQuote=CHAR(StringToNumber( pQuote ));\r\n Else;\r\n pQuote = SubSt( Trim( pQuote ), 1, 1 );\r\n EndIf;\r\nEndIf;\r\n\r\n# Validate subset file\r\n\r\nIf ( FileExists( pSubsetFile ) = 0 );\r\n sMessage = Expand('Invalid subset file: %pSubsetFile%');\r\n nErrors = nErrors + 1;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### Initialize output\r\n\r\nsTotalOutputRowString = '';\r\nIF( pWriteOutput <> 0 );\r\n sTitleRow = '%pQuote%DIMENSION%pQuote%%pFieldDelim%%pQuote%HAS SECURITY%pQuote%%pFieldDelim%%pQuote%SUBSET NAME%pQuote%';\r\n sTitleRow = sTitleRow|'%pFieldDelim%%pQuote%IS PRIVATE%pQuote%%pFieldDelim%%pQuote%MDX EXPRESSION%pQuote%';\r\n sTitleRow = sTitleRow|'%pFieldDelim%%pQuote%KEYWORDS%pQuote%%pFieldDelim%%pQuote%ELEMENTS%pQuote%%pFieldDelim%%pQuote%USERS WITH NO ACCESS%pQuote%';\r\n sTotalOutputRowString = Expand(sTitleRow);\r\nENDIF;\r\nsRow = '';\r\n\r\n### Assign data source\r\nIf( nErrors = 0 );\r\n DataSourceType ='CHARACTERDELIMITED';\r\n DatasourceNameForServer = pSubsetFile;\r\n DatasourceASCIIDelimiter='@@';\r\nEndIF;\r\n", "MetadataProcedure": "#****Begin: Generated Statements***\r\n#****End: Generated Statements****", "DataProcedure": "#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n# MDX statement flag ends on 278\r\n\r\nIf ( Subst ( vLine, 1, 3 ) @= '278' );\r\n # parse this MDX for keywords\r\n sKeyWordString = '';\r\n nKeywordFlag = 0;\r\n sKeywordList = cKeywordList;\r\n nKeywordLength = Long ( sKeywordList );\r\n While ( nKeywordLength > 0 );\r\n nDelimiter = Scan ( cKeywordDelimiter, sKeyWordList );\r\n If ( nDelimiter = 0 );\r\n sKeyword = sKeyWordList;\r\n sKeyWordList = '';\r\n Else;\r\n nEnd = nDelimiter - 1;\r\n sKeyWord = SubSt ( sKeywordList, 1, nEnd );\r\n sKeyWordList = Subst ( sKeywordList, nEnd + 2, nKeywordLength - nEnd);\r\n EndIf; \r\n\r\n If ( Scan( sKeyWord, sMDX ) > 0 );\r\n nKeyWordFlag = nKeyWordFlag + 1;\r\n IF( Long( sKeyWordString ) = 0 );\r\n sKeyWordString = sKeyWordString | sKeyWord;\r\n ELSE;\r\n sKeyWordString = sKeyWordString | pDelim | ' ' | sKeyWord;\r\n ENDIF;\r\n IF( pLogoutput = 1 );\r\n sMessage = 'Keyword ' | sKeyWord | ' found in ' |sMDX;\r\n LogOutput('INFO', Expand( cMsgInfoContent ) );\r\n ENDIF;\r\n EndIf; \r\n nKeywordLength = Long ( sKeywordList );\r\n End;\r\n IF( sKeyWordString @<> '' );\r\n sRow = '%pQuote%%pDimension%%pQuote%%pFieldDelim%%pQuote%Y%pQuote%%pFieldDelim%%pQuote%%pSubset%%pQuote%%pFieldDelim%%pQuote%%pUser%%pQuote%';\r\n sRow = sRow|'%pFieldDelim%%pQuote%%sMDX%%pQuote%';\r\n sRow = sRow|'%pFieldDelim%%pQuote%%sKeyWordString%%pQuote%';\r\n ENDIF;\r\n # end parsing for keywords\r\n # if keywords found then see if we can match an element in the MDX with one in the dimension\r\n # element will be included within [] but there will be [dimension][hierarchy][subset][attribute] so could be a false positive\r\n sElementString = '';\r\n sUsersString = '';\r\n If ( nKeyWordFlag > 0 );\r\n sMDXTemp = sMDX;\r\n sStarter = '[';\r\n sEnder = ']';\r\n nMDXLength = Long ( sMDXTemp );\r\n While ( nMDXLength > 0 );\r\n nStarter = SCAN ( sStarter, sMDXTemp );\r\n If ( nStarter > 0 );\r\n nEnder = SCAN ( sEnder, sMDXTemp );\r\n sElement = SubSt ( sMDXTemp, nStarter + 1, nEnder - nStarter -1);\r\n nToGo = nMDXLength - nEnder + 1;\r\n sMDXTemp = Subst ( sMDXTemp, nEnder + 1, nToGo );\r\n # check if that is actually an element\r\n If ( DimIx ( pDimension, sElement ) > 0 );\r\n IF( Scan( sElement, sElementString ) = 0 );\r\n IF( sElementString @= '' );\r\n sElementString = sElementString | sElement;\r\n ELSE;\r\n sElementString = sElementString | pDelim | ' ' | sElement;\r\n ENDIF;\r\n ENDIF;\r\n IF( pLogoutput = 1 );\r\n sMessage = sElement | ' is referenced in the MDX and exists in the dimension';\r\n LogOutput('INFO', Expand( cMsgInfoContent ) );\r\n ENDIF;\r\n # now need to loop through relevant groups to see access\r\n # loop through all groups to check access to this element\r\n nUserCheck = 0;\r\n iGroup = 1;\r\n While ( iGroup <= nGroupMax );\r\n sGroup = DimNm ( cGroupDim, iGroup );\r\n #skip the admin groups!\r\n If ( sGroup @<> 'ADMIN' & sGroup @<> 'SecurityAdmin' & sGroup @<> 'DataAdmin' & sGroup @<> 'OperationsAdmin' );\r\n nCheck = 1;\r\n # if we have a user check membership and we don;t need to continue if not in that group\r\n If ( CellGetS ( cSecCube, pUser, sGroup ) @= '' );\r\n nCheck = 0;\r\n EndIf; \r\n If ( nCheck = 1 );\r\n # get the groups security assignment\r\n sAccess = CellGetS ( cEleSecCube, sElement, sGroup );\r\n # if the user has rights to that element then all is good and we can quit the loops\r\n If ( sAccess @<> '' & sAccess @<> 'NONE' );\r\n nUserCheck = 1;\r\n iGroup = nGroupMax + 1;\r\n EndIf;\r\n EndIf;\r\n Else;\r\n # if the user is in an admin group them they will have access\r\n If ( CellGetS ( cSecCube, pUser, sGroup ) @<> '' );\r\n nUserCheck = 1;\r\n EndIf; \r\n EndIf; \r\n iGroup = iGroup + 1;\r\n End; \r\n If ( nUserCheck = 0 );\r\n sAlias = AttrS ( cUserDim, pUser, cUserAlias );\r\n If ( sAlias @= '' );\r\n sAlias = pUser;\r\n EndIf;\r\n IF( Scan( sAlias, sUsersString ) = 0 );\r\n IF( sUsersString @= '' );\r\n sUsersString = sUsersString | sAlias;\r\n ELSE;\r\n sUsersString = sUsersString | pDelim | ' ' | sAlias;\r\n ENDIF;\r\n ENDIF;\r\n IF( pLogoutput = 1 );\r\n sMessage = Expand('Private subset %pSubset% contains a keyword and a specific element %sElement% that the user %sAlias% do not have access to');\r\n LogOutput('INFO', Expand( cMsgInfoContent ) );\r\n ENDIF;\r\n EndIf;\r\n EndIf;\r\n nMDXLength = Long ( sMDXTemp );\r\n Else;\r\n nMDXLength = 0;\r\n EndIf; \r\n End; \r\n sRow = sRow|'%pFieldDelim%%pQuote%%sElementString%%pQuote%%pFieldDelim%%pQuote%%sUsersString%%pQuote%';\r\n EndIf;\r\n nMDXFlag = 0;\r\n IF( sTotalOutputRowString @= '' );\r\n sTotalOutputRowString = Expand(sRow);\r\n ELSE;\r\n sTotalOutputRowString = sTotalOutputRowString | sCRLF | Expand(sRow);\r\n ENDIF;\r\nEndIf;\r\n\r\n\r\nIf ( nMDXFlag = 1 );\r\n sMDX = UPPER ( sMDX | vLine ); \r\nEndIf; \r\n\r\n# MDX statement flag starts on 275\r\n\r\nIf ( Subst ( vLine, 1, 3 ) @= '275' );\r\n nMDXFlag = 1;\r\nEndIf;", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n### Write Output data\r\nIf( nErrors = 0 );\r\n IF( pWriteOutput <> 0 );\r\n DatasourceAsciiQuoteCharacter = '';\r\n TextOutput( cExportFile, Expand(sTotalOutputRowString) );\r\n ELSE;\r\n IF( sGlobPrivateSubsetsTotalString @= '' );\r\n sGlobPrivateSubsetsTotalString = sTotalOutputRowString;\r\n ELSE;\r\n IF( sTotalOutputRowString @<> '' );\r\n sGlobPrivateSubsetsTotalString = sGlobPrivateSubsetsTotalString | sCRLF | sTotalOutputRowString;\r\n ENDIF;\r\n ENDIF;\r\n ENDIF;\r\nENDIF;\r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully executed.' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n### End Epilog ###", @@ -18,18 +18,6 @@ "dataSourceNameForServer": "Admin/store}subs/Euros.sub" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pUser", "Prompt": "REQUIRED: User name", @@ -56,33 +44,51 @@ }, { "Name": "pFilePath", - "Prompt": "OPTIONAL: Export Directory (will default to error file path)", + "Prompt": "OPTIONAL: File directory (Default = GetProcessErrorFileDirectory)", "Value": "", "Type": "String" }, { "Name": "pFileName", - "Prompt": "OPTIONAL: Export Filename (If Left Blank Defaults to processname_user_dimension_subset_export.csv)", + "Prompt": "OPTIONAL: File name (Default = pCube | '_Export.csv')", "Value": "", "Type": "String" }, { "Name": "pDelim", - "Prompt": "OPTIONAL: AsciiOutput delimiter character (Default=comma, exactly 3 digits = ASCII code)", - "Value": ",", + "Prompt": "OPTIONAL: Delimiter for list parameters (Default = '&')", + "Value": "&", "Type": "String" }, { "Name": "pQuote", - "Prompt": "OPTIONAL: AsciiOutput quote character (Accepts empty quote, exactly 3 digits = ASCII code)", + "Prompt": "OPTIONAL: Quote character (2 or 3 digits = ASCII code. Default = '\"')", "Value": "\"", "Type": "String" }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, { "Name": "pWriteOutput", - "Prompt": "DO NOT USE: for internal use only", + "Prompt": "DO NOT USE: Internal parameter only, please do not use", "Value": 1, "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [ diff --git a/bedrock_processes_json/}bedrock.security.group.create.json b/bedrock_processes_json/}bedrock.security.group.create.json index d384d83..ff7d1c6 100644 --- a/bedrock_processes_json/}bedrock.security.group.create.json +++ b/bedrock_processes_json/}bedrock.security.group.create.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.security.group.create", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.security.group.create', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n\t 'pGroup', '', 'pAlias', '', 'pDelim', '&'\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will create client groups.\r\n\r\n# Use case: Intended for development or production.\r\n# 1/ Create initial security groups.\r\n# 2/ Add security groups as business needs change.\r\n\r\n# Note:\r\n# Naturally, a group (pGroup) is mandatory otherwise the process will abort.\r\n# - Multiple groups can be specified separated by a delimiter.\r\n# - If group already exists then the process will skip that group.\r\n#EndRegion @DOC\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncUserName = TM1User();\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pGroup:%pGroup%, pDelim:%pDelim%.' ; \r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n# If blank delimiter specified then convert to default\r\nIf( pDelim @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\n# If no groups have been specified then terminate process\r\nIf( Trim( pGroup ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No groups specified';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n# Alias\r\nIf( pAlias @<> '' );\r\n If( DimensionExists( '}ElementAttributes_}Groups' ) = 0 );\r\n AttrInsert( '}Groups', '', '}TM1_DefaultDisplayValue', 'A' );\r\n ElseIf( DimIx( '}ElementAttributes_}Groups', '}TM1_DefaultDisplayValue' ) = 0 );\r\n AttrInsert( '}Groups', '', '}TM1_DefaultDisplayValue', 'A' );\r\n EndIf;\r\nEndIf;\r\n\r\n### Split pGroups into individual groups and add ###\r\nsGroups = pGroup;\r\nnDelimiterIndex = 1;\r\nWhile( nDelimiterIndex <> 0 );\r\n nDelimiterIndex = Scan( pDelim, sGroups );\r\n If( nDelimiterIndex = 0 );\r\n sGroup = sGroups;\r\n Else;\r\n sGroup = Trim( SubSt( sGroups, 1, nDelimiterIndex - 1 ) );\r\n sGroups = Trim( Subst( sGroups, nDelimiterIndex + Long(pDelim), Long( sGroups ) ) );\r\n EndIf;\r\n # Don't attempt to add a blank group\r\n If( sGroup @<> '' );\r\n If( DimIx( '}Groups', sGroup ) = 0 );\r\n AddGroup( sGroup );\r\n Else;\r\n #Skip group\r\n EndIf;\r\n EndIf;\r\nEnd;\r\n\r\nIf( nErrors = 0 );\r\n DimensionSortOrder( '}Groups', 'ByName', 'Ascending', 'ByName' , 'Ascending' );\r\nEndIf;\r\n\r\n### End Prolog ###", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.security.group.create', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n\t 'pGroup', '', 'pAlias', '', 'pDelim', '&'\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will create client groups.\r\n\r\n# Use case: Intended for development or production.\r\n# 1/ Create initial security groups.\r\n# 2/ Add security groups as business needs change.\r\n\r\n# Note:\r\n# Naturally, a group (pGroup) is mandatory otherwise the process will abort.\r\n# - Multiple groups can be specified separated by a delimiter.\r\n# - If group already exists then the process will skip that group.\r\n#EndRegion @DOC\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncUserName = TM1User();\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pGroup:%pGroup%, pDelim:%pDelim%.' ;\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pAlias\": \"\",\r\n \"pDelim\": \"&\",\r\n \"pGroup\": null,\r\n \"pLogOutput\": 0,\r\n \"pStrictErrorHandling\": 0\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pAlias\": '|StringToJson ( pAlias )|',\r\n \"pDelim\": '|StringToJson ( pDelim )|',\r\n \"pGroup\": '|StringToJson ( pGroup )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npAlias = JsonToString( JsonGet( pJson, 'pAlias' ) );\r\npDelim = JsonToString( JsonGet( pJson, 'pDelim' ) );\r\npGroup = JsonToString( JsonGet( pJson, 'pGroup' ) );\r\n# Numeric Parameters\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n# If blank delimiter specified then convert to default\r\nIf( pDelim @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\n# If no groups have been specified then terminate process\r\nIf( Trim( pGroup ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No groups specified';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n# Alias\r\nIf( pAlias @<> '' );\r\n If( DimensionExists( '}ElementAttributes_}Groups' ) = 0 );\r\n AttrInsert( '}Groups', '', '}TM1_DefaultDisplayValue', 'A' );\r\n ElseIf( DimIx( '}ElementAttributes_}Groups', '}TM1_DefaultDisplayValue' ) = 0 );\r\n AttrInsert( '}Groups', '', '}TM1_DefaultDisplayValue', 'A' );\r\n EndIf;\r\nEndIf;\r\n\r\n### Split pGroups into individual groups and add ###\r\nsGroups = pGroup;\r\nnDelimiterIndex = 1;\r\nWhile( nDelimiterIndex <> 0 );\r\n nDelimiterIndex = Scan( pDelim, sGroups );\r\n If( nDelimiterIndex = 0 );\r\n sGroup = sGroups;\r\n Else;\r\n sGroup = Trim( SubSt( sGroups, 1, nDelimiterIndex - 1 ) );\r\n sGroups = Trim( Subst( sGroups, nDelimiterIndex + Long(pDelim), Long( sGroups ) ) );\r\n EndIf;\r\n # Don't attempt to add a blank group\r\n If( sGroup @<> '' );\r\n If( DimIx( '}Groups', sGroup ) = 0 );\r\n AddGroup( sGroup );\r\n Else;\r\n #Skip group\r\n EndIf;\r\n EndIf;\r\nEnd;\r\n\r\nIf( nErrors = 0 );\r\n DimensionSortOrder( '}Groups', 'ByName', 'Ascending', 'ByName' , 'Ascending' );\r\nEndIf;\r\n\r\n### End Prolog ###", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n### Update Alias\r\n\r\nIf( nErrors = 0 );\r\n\r\n sAliases = pAlias;\r\n sGroups = pGroup;\r\n nDelimiterIndex = 1;\r\n\r\n While( nDelimiterIndex > 0 );\r\n nDelimiterIndex = Scan( pDelim, sAliases );\r\n If( nDelimiterIndex = 0 );\r\n sAlias = sAliases;\r\n Else;\r\n sAlias = Trim( SubSt( sAliases, 1, nDelimiterIndex - 1 ) );\r\n sAliases = Trim( Subst( sAliases, nDelimiterIndex + Long(pDelim), Long( sAliases ) ) );\r\n EndIf;\r\n nDelimiterIndex = Scan( pDelim, sGroups );\r\n If( nDelimiterIndex = 0 );\r\n sGroup = sGroups;\r\n Else;\r\n sGroup = Trim( SubSt( sGroups, 1, nDelimiterIndex - 1 ) );\r\n sGroups = Trim( Subst( sGroups, nDelimiterIndex + Long(pDelim), Long( sGroups ) ) );\r\n EndIf;\r\n \r\n If( DimIx( '}Groups', sGroup ) > 0 );\r\n If( sAlias @<> '' );\r\n AttrPutS( sAlias, '}Groups', sGroup, '}TM1_DefaultDisplayValue', 1 );\r\n EndIf;\r\n EndIf;\r\n End;\r\n\r\nEndIf;\r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully created Group %pGroup% .' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n### End Epilog ###", @@ -10,35 +10,41 @@ "Type": "None" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pGroup", - "Prompt": "REQUIRED: Groups separated by delimiter", + "Prompt": "REQUIRED: Delimited list of groups", "Value": "", "Type": "String" }, { "Name": "pAlias", - "Prompt": "OPTIONAL: single or delimited list of }TM1_DefaultDisplayValue alias to assign to group (if list of groups then size of list of aliases must be the same!)", + "Prompt": "OPTIONAL: Set alias for subset", "Value": "", "Type": "String" }, { "Name": "pDelim", - "Prompt": "OPTIONAL: Delimiter character (Defaults to & if left blank)", + "Prompt": "OPTIONAL: Delimiter for list parameters (Default = '&')", "Value": "&", "Type": "String" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [], diff --git a/bedrock_processes_json/}bedrock.security.group.delete.json b/bedrock_processes_json/}bedrock.security.group.delete.json index f66d339..d327ca9 100644 --- a/bedrock_processes_json/}bedrock.security.group.delete.json +++ b/bedrock_processes_json/}bedrock.security.group.delete.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.security.group.delete", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.security.group.delete', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n\t 'pGroup', '', 'pDelim', '&'\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will delete client groups.\r\n\r\n# Use case: Intended for development or production.\r\n# 1/ Clean up security groups after go live.\r\n# 2/ Delete obsolete security groups as business needs change.\r\n\r\n# Note:\r\n# Naturally, a group (pGroup) is mandatory otherwise the process will abort:\r\n# - Multiple groups can be specified separated by a delimiter.\r\n# - If group does not exist then it will be skipped.\r\n# - If multiple groups are specified and some don't exist and some do, then the ones that do exist will still be deleted.\r\n#EndRegion @DOC\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName | '_' | cTimeStamp | '_' | cRandomInt;\r\ncTempFile = GetProcessErrorFileDirectory | cTempSub | '.csv';\r\ncGroupDim = '}Groups';\r\ncGroupHier = cGroupDim;\r\ncUserName = TM1User();\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgInfoLevel = 'INFO';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pGroup:%pGroup%, pDelim:%pDelim%.';\r\ncBuiltInGroups = 'ADMIN&SecurityAdmin&DataAdmin&OperationsAdmin&';\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n# If blank delimiter specified then convert to default\r\nIf( pDelim @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\n# If no groups have been specified then terminate process\r\nIf( Trim( pGroup ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No groups specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n# Check alias exists\r\nIf( DimensionExists('}ElementAttributes_'|cGroupDim) = 0 % DimIx('}ElementAttributes_'|cGroupDim, '}TM1_DefaultDisplayValue') = 0 );\r\n AttrInsert( cGroupDim, '', '}TM1_DefaultDisplayValue', 'A' );\r\nEndIf;\r\n\r\n### Split pGroups into individual groups and delete ###\r\n#sGroups = pGroup;\r\n#nDelimiterIndex = 1;\r\n#While( nDelimiterIndex <> 0 );\r\n# nDelimiterIndex = Scan( pDelim, sGroups );\r\n# If( nDelimiterIndex = 0 );\r\n# sGroup = sGroups;\r\n# Else;\r\n# sGroup = Trim( SubSt( sGroups, 1, nDelimiterIndex - 1 ) );\r\n# sGroups = Trim( Subst( sGroups, nDelimiterIndex + Long(pDelim), Long( sGroups ) ) );\r\n# EndIf;\r\n# \r\n# If( Scan( '*', sGroup ) = 0);\r\n# # Don't attempt to delete a blank group\r\n# If( sGroup @<> '' );\r\n# If( DimIx( '}Groups', sGroup ) > 0 );\r\n# If( nErrors = 0 );\r\n# If( Scan( Upper( sGroup ) |'&', Upper( cBuiltInGroups ) ) = 0 );\r\n# DeleteGroup( sGroup );\r\n# Else;\r\n# nErrors = 1;\r\n# sMessage= Expand('Attempt to delete built-in group %sGroup%.');\r\n# LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n# EndIf;\r\n# EndIf;\r\n# If( nErrors > 0 );\r\n# ItemReject( Expand( cMsgErrorContent ) );\r\n# EndIf;\r\n# EndIf;\r\n# EndIf;\r\n# Else;\r\n# # Wildcard search string\r\n# iCount = 0;\r\n# iCheck = 1;\r\n# sChar = sGroup;\r\n# While (iCheck > 0);\r\n# iCheck = Scan('*',sChar);\r\n# If( iCheck > 0 );\r\n# iCount = iCount + 1;\r\n# sChar = Subst(sChar,iCheck+1,(long(sChar)-iCheck));\r\n# Endif;\r\n# End;\r\n# If(iCount = 1);\r\n# ##If the wilcardsearch is *String, below code will get executed\r\n# if(Subst(sGroup,iCount,1) @= '*');\r\n# sGroup1 = '\"'| Subst(sGroup,iCount+1,(Long(sGroup)- iCount))|'\"';\r\n# sTempCount = NumbertoString(Long(sGroup)-iCount);\r\n# sMdx = '{FILTER({TM1SUBSETALL(['|cGroupDim|'].['|cGroupHier|'])},\r\n# (Right( ['|cGroupDim|'].['|cGroupHier|'].[}TM1_DefaultDisplayValue],'| sTempCount|') ='|sGroup1|'))}+\r\n# {FILTER({TM1SUBSETALL(['|cGroupDim|'].['|cGroupHier|'])},\r\n# (Right( ['|cGroupDim|'].['|cGroupHier|'].CurrentMember.Name,'| sTempCount|') ='|sGroup1|'))}';\r\n# If( SubsetExists( cGroupDim, cTempSub ) = 1 );\r\n# # If a delimited list of Groups includes wildcards then we may have to re-use the subset multiple times\r\n# SubsetMDXSet( cGroupDim, cTempSub, sMDX );\r\n# Else;\r\n# # temp subset, therefore no need to destroy in epilog\r\n# SubsetCreatebyMDX( cTempSub, sMDX, cGroupDim, 1 );\r\n# EndIf;\r\n#\r\n# nHier_Sub_Size = HierarchySubsetGetSize(cGroupDim, cGroupHier, cTempSub);\r\n# nCount = nHier_Sub_Size;\r\n# While (nCount >= 1);\r\n# sTemp = HierarchySubsetElementGetIndex (cGroupDim, cGroupHier, cTempSub, '', 1);\r\n# sElement = HierarchySubsetGetElementName(cGroupDim, cGroupHier, cTempSub, nCount);\r\n# If( Scan( Upper( sElement ) |'&', Upper( cBuiltInGroups ) ) = 0 );\r\n# DeleteGroup( sElement );\r\n# Else;\r\n# sMessage= 'Attempt to delete built-in group %sGroup%.';\r\n# LogOutput( 'WARN', Expand( cMsgErrorContent ) );\r\n# EndIF;\r\n# nCount = nCount -1;\r\n# End;\r\n# ##If the wilcardsearch is String*, below code will get executed\r\n# ElseIf(Subst(sGroup,Long(sGroup),1) @= '*');\r\n# sGroup1 = '\"'| Subst(sGroup,iCount,(Long(sGroup)- iCount))|'\"';\r\n# sMdx = '{FILTER({TM1SUBSETALL(['|cGroupDim|'].['|cGroupHier|'])},\r\n# (INSTR('| NumbertoString(iCount)|', ['|cGroupDim|'].['|cGroupHier|'].[}TM1_DefaultDisplayValue],'|sGroup1|') ='| NumbertoString(iCount)|'))}+\r\n# {FILTER({TM1SUBSETALL(['|cGroupDim|'].['|cGroupHier|'])},\r\n# (INSTR('| NumbertoString(iCount)|', ['|cGroupDim|'].['|cGroupHier|'].CurrentMember.Name,'|sGroup1|') ='| NumbertoString(iCount)|'))}';\r\n# If( SubsetExists( cGroupDim, cTempSub ) = 1 );\r\n# # If a delimited list of Groups includes wildcards then we may have to re-use the subset multiple times\r\n# SubsetMDXSet( cGroupDim, cTempSub, sMDX );\r\n# Else;\r\n# # temp subset, therefore no need to destroy in epilog\r\n# SubsetCreatebyMDX( cTempSub, sMDX, cGroupDim, 1 );\r\n# EndIf;\r\n#\r\n# nHier_Sub_Size = HierarchySubsetGetSize(cGroupDim, cGroupHier, cTempSub);\r\n# nCount = nHier_Sub_Size;\r\n# While (nCount >= 1);\r\n# sTemp = HierarchySubsetElementGetIndex (cGroupDim, cGroupHier, cTempSub, '', 1);\r\n# sElement = HierarchySubsetGetElementName(cGroupDim, cGroupHier, cTempSub, nCount);\r\n# If( Scan( Upper( sElement ) |'&', Upper( cBuiltInGroups ) ) = 0 );\r\n# DeleteGroup( sElement );\r\n# Else;\r\n# sMessage= 'Attempt to delete built-in group %sGroup%.';\r\n# LogOutput( 'WARN', Expand( cMsgErrorContent ) );\r\n# EndIF;\r\n# nCount = nCount -1;\r\n# End;\r\n# Endif;\r\n# Else;\r\n# ##If the wilcardsearch is *String*, below code will get executed\r\n# sGroup1 = '\"'| Subst(sGroup,iCount,(Long(sGroup)- iCount))|'\"';\r\n# sMdx = '{FILTER({TM1SUBSETALL(['|cGroupDim|'].['|cGroupHier|'])},\r\n# (INSTR(1,['|cGroupDim|'].['|cGroupHier|'].[}TM1_DefaultDisplayValue],'|sGroup1|') <> 0))}+\r\n# {FILTER({TM1SUBSETALL(['|cGroupDim|'].['|cGroupHier|'])},\r\n# (INSTR(1,['|cGroupDim|'].['|cGroupHier|'].CurrentMember.Name,'|sGroup1|') <> 0))}';\r\n# If( SubsetExists( cGroupDim, cTempSub ) = 1 );\r\n# # If a delimited list of Groups includes wildcards then we may have to re-use the subset multiple times\r\n# SubsetMDXSet( cGroupDim, cTempSub, sMDX );\r\n# Else;\r\n# # temp subset, therefore no need to destroy in epilog\r\n# SubsetCreatebyMDX( cTempSub, sMDX, cGroupDim, 1 );\r\n# EndIf;\r\n#\r\n# nHier_Sub_Size = HierarchySubsetGetSize(cGroupDim, cGroupHier, cTempSub);\r\n# nCount = nHier_Sub_Size;\r\n# While (nCount >= 1);\r\n# sTemp = HierarchySubsetElementGetIndex (cGroupDim, cGroupHier, cTempSub, '', 1);\r\n# sElement = HierarchySubsetGetElementName(cGroupDim, cGroupHier, cTempSub, nCount);\r\n# If( Scan( Upper( sElement ) |'&', Upper( cBuiltInGroups ) ) = 0 );\r\n# DeleteGroup( sElement );\r\n# Else;\r\n# sMessage= 'Attempt to delete built-in group %sGroup%.';\r\n# LogOutput( 'WARN', Expand( cMsgErrorContent ) );\r\n# EndIF;\r\n# nCount = nCount -1;\r\n# End;\r\n# Endif;\r\n# EndIf;\r\n#End;\r\n\r\nsDim = cGroupDim;\r\nsCurrHierName = cGroupHier;\r\nsEles = pGroup;\r\nnDelimiterIndexB = 1;\r\nWhile( nDelimiterIndexB <> 0 );\r\n \r\n nDelimiterIndexB = Scan( pDelim, sEles );\r\n If( nDelimiterIndexB = 0 );\r\n sEle = sEles;\r\n Else;\r\n sEle = Trim( SubSt( sEles, 1, nDelimiterIndexB - 1 ) );\r\n sEles = Trim( Subst( sEles, nDelimiterIndexB + Long(pDelim), Long( sEles ) ) );\r\n EndIf;\r\n \r\n # Check if a wildcard has been used to specify the Element name.\r\n # If it hasn't then just delete the Element if it exists\r\n If( Scan( '*', sEle ) = 0 & Scan( '?', sEle ) = 0);\r\n If( HierarchyElementExists( sDim,sCurrHierName, sEle ) = 1 );\r\n If( Scan( Upper( sEle ) |'&', Upper( cBuiltInGroups ) ) = 0 );\r\n DeleteGroup( sEle );\r\n Else;\r\n cMsgErrorContent = 'Attempt to delete built-in group %sEle%.';\r\n LogOutput( 'WARN', Expand( cMsgErrorContent ) );\r\n EndIF;\r\n If( pLogOutput = 1 );\r\n cMsgInfoContent = Expand( 'Attempted to delete Element %sEle% from hierarchy %sCurrHierName% in dimension %sDim%.' );\r\n LogOutput( cMsgInfoLevel, Expand( cMsgInfoContent ) );\r\n EndIf;\r\n Else;\r\n If( pLogOutput >= 1 );\r\n cMsgInfoContent = Expand('The Hierarchy %sCurrHierName% does not contain element %sEle%.');\r\n LogOutput( cMsgInfoLevel, Expand( cMsgInfoContent ) );\r\n EndIf;\r\n Endif;\r\n Else;\r\n # Wildcard search string\r\n sEle = '\"'|sEle|'\"';\r\n sMdxEle = '{TM1FILTERBYPATTERN( {TM1SUBSETALL([ ' | sCurrHierName |' ])},'| sEle| ')}';\r\n\r\n If( HierarchySubsetExists( sDim, sCurrHierName, cTempSub ) = 1 );\r\n # If a delimited list of ele names includes wildcards then we may have to re-use the subset multiple times\r\n HierarchySubsetMDXSet( sDim, sCurrHierName, cTempSub, sMDXEle );\r\n Else;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSub, sMDXEle, sCurrHierName, 1 );\r\n EndIf;\r\n\r\n # Loop through subset of hierarchy elements created based on wildcard\r\n nCountElems = HierarchySubsetGetSize(sDim, sCurrHierName, cTempSub);\r\n While( nCountElems >= 1 );\r\n sElement = HierarchySubsetGetElementName(sDim, sCurrHierName, cTempSub, nCountElems);\r\n If( Scan( Upper( sElement ) |'&', Upper( cBuiltInGroups ) ) = 0 );\r\n DeleteGroup( sElement );\r\n Else;\r\n sMessage= 'Attempt to delete built-in group %sElement%.';\r\n LogOutput( 'WARN', Expand( cMsgErrorContent ) );\r\n EndIF;\r\n If( pLogOutput = 1 );\r\n sMessage = Expand( 'Attempted to delete Element %sElement% from hierarchy %sCurrHierName% in dimension %sDim%.' );\r\n LogOutput( cMsgInfoLevel, Expand( cMsgInfoContent ) );\r\n EndIf;\r\n nCountElems = nCountElems - 1;\r\n End;\r\n EndIf;\r\n\r\nEnd;\r\n\r\nIf( nErrors = 0 );\r\n DimensionSortOrder( '}Groups', 'ByName', 'Ascending', 'ByName' , 'Ascending' );\r\nEndIf;\r\n\r\n### End Prolog ###", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.security.group.delete', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n\t 'pGroup', '', 'pDelim', '&'\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will delete client groups.\r\n\r\n# Use case: Intended for development or production.\r\n# 1/ Clean up security groups after go live.\r\n# 2/ Delete obsolete security groups as business needs change.\r\n\r\n# Note:\r\n# Naturally, a group (pGroup) is mandatory otherwise the process will abort:\r\n# - Multiple groups can be specified separated by a delimiter.\r\n# - If group does not exist then it will be skipped.\r\n# - If multiple groups are specified and some don't exist and some do, then the ones that do exist will still be deleted.\r\n#EndRegion @DOC\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName | '_' | cTimeStamp | '_' | cRandomInt;\r\ncTempFile = GetProcessErrorFileDirectory | cTempSub | '.csv';\r\ncGroupDim = '}Groups';\r\ncGroupHier = cGroupDim;\r\ncUserName = TM1User();\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgInfoLevel = 'INFO';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pGroup:%pGroup%, pDelim:%pDelim%.';\r\ncBuiltInGroups = 'ADMIN&SecurityAdmin&DataAdmin&OperationsAdmin&';\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pDelim\": \"&\",\r\n \"pGroup\": null,\r\n \"pLogOutput\": 0,\r\n \"pStrictErrorHandling\": 0\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pDelim\": '|StringToJson ( pDelim )|',\r\n \"pGroup\": '|StringToJson ( pGroup )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npDelim = JsonToString( JsonGet( pJson, 'pDelim' ) );\r\npGroup = JsonToString( JsonGet( pJson, 'pGroup' ) );\r\n# Numeric Parameters\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n# If blank delimiter specified then convert to default\r\nIf( pDelim @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\n# If no groups have been specified then terminate process\r\nIf( Trim( pGroup ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No groups specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n# Check alias exists\r\nIf( DimensionExists('}ElementAttributes_'|cGroupDim) = 0 % DimIx('}ElementAttributes_'|cGroupDim, '}TM1_DefaultDisplayValue') = 0 );\r\n AttrInsert( cGroupDim, '', '}TM1_DefaultDisplayValue', 'A' );\r\nEndIf;\r\n\r\n### Split pGroups into individual groups and delete ###\r\n#sGroups = pGroup;\r\n#nDelimiterIndex = 1;\r\n#While( nDelimiterIndex <> 0 );\r\n# nDelimiterIndex = Scan( pDelim, sGroups );\r\n# If( nDelimiterIndex = 0 );\r\n# sGroup = sGroups;\r\n# Else;\r\n# sGroup = Trim( SubSt( sGroups, 1, nDelimiterIndex - 1 ) );\r\n# sGroups = Trim( Subst( sGroups, nDelimiterIndex + Long(pDelim), Long( sGroups ) ) );\r\n# EndIf;\r\n# \r\n# If( Scan( '*', sGroup ) = 0);\r\n# # Don't attempt to delete a blank group\r\n# If( sGroup @<> '' );\r\n# If( DimIx( '}Groups', sGroup ) > 0 );\r\n# If( nErrors = 0 );\r\n# If( Scan( Upper( sGroup ) |'&', Upper( cBuiltInGroups ) ) = 0 );\r\n# DeleteGroup( sGroup );\r\n# Else;\r\n# nErrors = 1;\r\n# sMessage= Expand('Attempt to delete built-in group %sGroup%.');\r\n# LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n# EndIf;\r\n# EndIf;\r\n# If( nErrors > 0 );\r\n# ItemReject( Expand( cMsgErrorContent ) );\r\n# EndIf;\r\n# EndIf;\r\n# EndIf;\r\n# Else;\r\n# # Wildcard search string\r\n# iCount = 0;\r\n# iCheck = 1;\r\n# sChar = sGroup;\r\n# While (iCheck > 0);\r\n# iCheck = Scan('*',sChar);\r\n# If( iCheck > 0 );\r\n# iCount = iCount + 1;\r\n# sChar = Subst(sChar,iCheck+1,(long(sChar)-iCheck));\r\n# Endif;\r\n# End;\r\n# If(iCount = 1);\r\n# ##If the wilcardsearch is *String, below code will get executed\r\n# if(Subst(sGroup,iCount,1) @= '*');\r\n# sGroup1 = '\"'| Subst(sGroup,iCount+1,(Long(sGroup)- iCount))|'\"';\r\n# sTempCount = NumbertoString(Long(sGroup)-iCount);\r\n# sMdx = '{FILTER({TM1SUBSETALL(['|cGroupDim|'].['|cGroupHier|'])},\r\n# (Right( ['|cGroupDim|'].['|cGroupHier|'].[}TM1_DefaultDisplayValue],'| sTempCount|') ='|sGroup1|'))}+\r\n# {FILTER({TM1SUBSETALL(['|cGroupDim|'].['|cGroupHier|'])},\r\n# (Right( ['|cGroupDim|'].['|cGroupHier|'].CurrentMember.Name,'| sTempCount|') ='|sGroup1|'))}';\r\n# If( SubsetExists( cGroupDim, cTempSub ) = 1 );\r\n# # If a delimited list of Groups includes wildcards then we may have to re-use the subset multiple times\r\n# SubsetMDXSet( cGroupDim, cTempSub, sMDX );\r\n# Else;\r\n# # temp subset, therefore no need to destroy in epilog\r\n# SubsetCreatebyMDX( cTempSub, sMDX, cGroupDim, 1 );\r\n# EndIf;\r\n#\r\n# nHier_Sub_Size = HierarchySubsetGetSize(cGroupDim, cGroupHier, cTempSub);\r\n# nCount = nHier_Sub_Size;\r\n# While (nCount >= 1);\r\n# sTemp = HierarchySubsetElementGetIndex (cGroupDim, cGroupHier, cTempSub, '', 1);\r\n# sElement = HierarchySubsetGetElementName(cGroupDim, cGroupHier, cTempSub, nCount);\r\n# If( Scan( Upper( sElement ) |'&', Upper( cBuiltInGroups ) ) = 0 );\r\n# DeleteGroup( sElement );\r\n# Else;\r\n# sMessage= 'Attempt to delete built-in group %sGroup%.';\r\n# LogOutput( 'WARN', Expand( cMsgErrorContent ) );\r\n# EndIF;\r\n# nCount = nCount -1;\r\n# End;\r\n# ##If the wilcardsearch is String*, below code will get executed\r\n# ElseIf(Subst(sGroup,Long(sGroup),1) @= '*');\r\n# sGroup1 = '\"'| Subst(sGroup,iCount,(Long(sGroup)- iCount))|'\"';\r\n# sMdx = '{FILTER({TM1SUBSETALL(['|cGroupDim|'].['|cGroupHier|'])},\r\n# (INSTR('| NumbertoString(iCount)|', ['|cGroupDim|'].['|cGroupHier|'].[}TM1_DefaultDisplayValue],'|sGroup1|') ='| NumbertoString(iCount)|'))}+\r\n# {FILTER({TM1SUBSETALL(['|cGroupDim|'].['|cGroupHier|'])},\r\n# (INSTR('| NumbertoString(iCount)|', ['|cGroupDim|'].['|cGroupHier|'].CurrentMember.Name,'|sGroup1|') ='| NumbertoString(iCount)|'))}';\r\n# If( SubsetExists( cGroupDim, cTempSub ) = 1 );\r\n# # If a delimited list of Groups includes wildcards then we may have to re-use the subset multiple times\r\n# SubsetMDXSet( cGroupDim, cTempSub, sMDX );\r\n# Else;\r\n# # temp subset, therefore no need to destroy in epilog\r\n# SubsetCreatebyMDX( cTempSub, sMDX, cGroupDim, 1 );\r\n# EndIf;\r\n#\r\n# nHier_Sub_Size = HierarchySubsetGetSize(cGroupDim, cGroupHier, cTempSub);\r\n# nCount = nHier_Sub_Size;\r\n# While (nCount >= 1);\r\n# sTemp = HierarchySubsetElementGetIndex (cGroupDim, cGroupHier, cTempSub, '', 1);\r\n# sElement = HierarchySubsetGetElementName(cGroupDim, cGroupHier, cTempSub, nCount);\r\n# If( Scan( Upper( sElement ) |'&', Upper( cBuiltInGroups ) ) = 0 );\r\n# DeleteGroup( sElement );\r\n# Else;\r\n# sMessage= 'Attempt to delete built-in group %sGroup%.';\r\n# LogOutput( 'WARN', Expand( cMsgErrorContent ) );\r\n# EndIF;\r\n# nCount = nCount -1;\r\n# End;\r\n# Endif;\r\n# Else;\r\n# ##If the wilcardsearch is *String*, below code will get executed\r\n# sGroup1 = '\"'| Subst(sGroup,iCount,(Long(sGroup)- iCount))|'\"';\r\n# sMdx = '{FILTER({TM1SUBSETALL(['|cGroupDim|'].['|cGroupHier|'])},\r\n# (INSTR(1,['|cGroupDim|'].['|cGroupHier|'].[}TM1_DefaultDisplayValue],'|sGroup1|') <> 0))}+\r\n# {FILTER({TM1SUBSETALL(['|cGroupDim|'].['|cGroupHier|'])},\r\n# (INSTR(1,['|cGroupDim|'].['|cGroupHier|'].CurrentMember.Name,'|sGroup1|') <> 0))}';\r\n# If( SubsetExists( cGroupDim, cTempSub ) = 1 );\r\n# # If a delimited list of Groups includes wildcards then we may have to re-use the subset multiple times\r\n# SubsetMDXSet( cGroupDim, cTempSub, sMDX );\r\n# Else;\r\n# # temp subset, therefore no need to destroy in epilog\r\n# SubsetCreatebyMDX( cTempSub, sMDX, cGroupDim, 1 );\r\n# EndIf;\r\n#\r\n# nHier_Sub_Size = HierarchySubsetGetSize(cGroupDim, cGroupHier, cTempSub);\r\n# nCount = nHier_Sub_Size;\r\n# While (nCount >= 1);\r\n# sTemp = HierarchySubsetElementGetIndex (cGroupDim, cGroupHier, cTempSub, '', 1);\r\n# sElement = HierarchySubsetGetElementName(cGroupDim, cGroupHier, cTempSub, nCount);\r\n# If( Scan( Upper( sElement ) |'&', Upper( cBuiltInGroups ) ) = 0 );\r\n# DeleteGroup( sElement );\r\n# Else;\r\n# sMessage= 'Attempt to delete built-in group %sGroup%.';\r\n# LogOutput( 'WARN', Expand( cMsgErrorContent ) );\r\n# EndIF;\r\n# nCount = nCount -1;\r\n# End;\r\n# Endif;\r\n# EndIf;\r\n#End;\r\n\r\nsDim = cGroupDim;\r\nsCurrHierName = cGroupHier;\r\nsEles = pGroup;\r\nnDelimiterIndexB = 1;\r\nWhile( nDelimiterIndexB <> 0 );\r\n \r\n nDelimiterIndexB = Scan( pDelim, sEles );\r\n If( nDelimiterIndexB = 0 );\r\n sEle = sEles;\r\n Else;\r\n sEle = Trim( SubSt( sEles, 1, nDelimiterIndexB - 1 ) );\r\n sEles = Trim( Subst( sEles, nDelimiterIndexB + Long(pDelim), Long( sEles ) ) );\r\n EndIf;\r\n \r\n # Check if a wildcard has been used to specify the Element name.\r\n # If it hasn't then just delete the Element if it exists\r\n If( Scan( '*', sEle ) = 0 & Scan( '?', sEle ) = 0);\r\n If( HierarchyElementExists( sDim,sCurrHierName, sEle ) = 1 );\r\n If( Scan( Upper( sEle ) |'&', Upper( cBuiltInGroups ) ) = 0 );\r\n DeleteGroup( sEle );\r\n Else;\r\n cMsgErrorContent = 'Attempt to delete built-in group %sEle%.';\r\n LogOutput( 'WARN', Expand( cMsgErrorContent ) );\r\n EndIF;\r\n If( pLogOutput = 1 );\r\n cMsgInfoContent = Expand( 'Attempted to delete Element %sEle% from hierarchy %sCurrHierName% in dimension %sDim%.' );\r\n LogOutput( cMsgInfoLevel, Expand( cMsgInfoContent ) );\r\n EndIf;\r\n Else;\r\n If( pLogOutput >= 1 );\r\n cMsgInfoContent = Expand('The Hierarchy %sCurrHierName% does not contain element %sEle%.');\r\n LogOutput( cMsgInfoLevel, Expand( cMsgInfoContent ) );\r\n EndIf;\r\n Endif;\r\n Else;\r\n # Wildcard search string\r\n sEle = '\"'|sEle|'\"';\r\n sMdxEle = '{TM1FILTERBYPATTERN( {TM1SUBSETALL([ ' | sCurrHierName |' ])},'| sEle| ')}';\r\n\r\n If( HierarchySubsetExists( sDim, sCurrHierName, cTempSub ) = 1 );\r\n # If a delimited list of ele names includes wildcards then we may have to re-use the subset multiple times\r\n HierarchySubsetMDXSet( sDim, sCurrHierName, cTempSub, sMDXEle );\r\n Else;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSub, sMDXEle, sCurrHierName, 1 );\r\n EndIf;\r\n\r\n # Loop through subset of hierarchy elements created based on wildcard\r\n nCountElems = HierarchySubsetGetSize(sDim, sCurrHierName, cTempSub);\r\n While( nCountElems >= 1 );\r\n sElement = HierarchySubsetGetElementName(sDim, sCurrHierName, cTempSub, nCountElems);\r\n If( Scan( Upper( sElement ) |'&', Upper( cBuiltInGroups ) ) = 0 );\r\n DeleteGroup( sElement );\r\n Else;\r\n sMessage= 'Attempt to delete built-in group %sElement%.';\r\n LogOutput( 'WARN', Expand( cMsgErrorContent ) );\r\n EndIF;\r\n If( pLogOutput = 1 );\r\n sMessage = Expand( 'Attempted to delete Element %sElement% from hierarchy %sCurrHierName% in dimension %sDim%.' );\r\n LogOutput( cMsgInfoLevel, Expand( cMsgInfoContent ) );\r\n EndIf;\r\n nCountElems = nCountElems - 1;\r\n End;\r\n EndIf;\r\n\r\nEnd;\r\n\r\nIf( nErrors = 0 );\r\n DimensionSortOrder( '}Groups', 'ByName', 'Ascending', 'ByName' , 'Ascending' );\r\nEndIf;\r\n\r\n### End Prolog ###", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully deleted group %pGroup% from dimension %cGroupDim%.' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n### End Epilog ###", @@ -10,28 +10,34 @@ "Type": "None" }, "Parameters": [ + { + "Name": "pGroup", + "Prompt": "REQUIRED: Delimited list of groups", + "Value": "", + "Type": "String" + }, + { + "Name": "pDelim", + "Prompt": "OPTIONAL: Delimiter for list parameters (Default = '&')", + "Value": "&", + "Type": "String" + }, { "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { - "Name": "pGroup", - "Prompt": "REQUIRED: Groups (Separated by Delimiter, Accepts Wild card)", - "Value": "", - "Type": "String" - }, - { - "Name": "pDelim", - "Prompt": "OPTIONAL: Delimiter character (Defaults to & if left blank)", - "Value": "&", + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", "Type": "String" } ], diff --git a/bedrock_processes_json/}bedrock.security.object.assign.json b/bedrock_processes_json/}bedrock.security.object.assign.json index 0197d27..4bc35cd 100644 --- a/bedrock_processes_json/}bedrock.security.object.assign.json +++ b/bedrock_processes_json/}bedrock.security.object.assign.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.security.object.assign", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.security.object.assign', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pGroup', '', 'pObjectType', '', 'pObject', '',\r\n \t'pSecurityLevel', '', 'pSecurityRefresh', 'No', 'pDelim', '&'\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will assign security to specified object(s) for specified group(s). Both pGroup \r\n# and pObject parameters support delimited lists and wildcards.\r\n\r\n# Use case: Intended for develpment or production.\r\n# 1. Set up initial security assignments.\r\n# 2. Update security assignments a business needs change.\r\n\r\n# Note:\r\n# Naturally, group (pGroup), object type (pObjectType) and security level (pSecurityLevel) are mandatory otherwise the process will abort:\r\n# - Multiple groups can be specified separated by delimiter.\r\n# Object names (pObject) can be listed with delimiters but need to be valid as well. \r\n# - Before using this process, you must first initialise object security.\r\n# - For Cubes, in Server Explorer, right click Cubes -> Cube Security and assign an access security for a Cube. \r\n# - For other object types follow a similar process but for that object type.\r\n# - Then from the Server Explorer go to your ServerName -> Security -> Refresh Security.\r\n# - Multiple objects can be specified separated by delimiter.\r\n# - If groups and/or objects that don't exist are specified, then they will be skipped but valid groups and ojects will still be processed.\r\n#EndRegion @DOC\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncSecurityCube = '}' | pObjectType | 'Security';\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncUserName = TM1User();\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pGroup:%pGroup%, pObjectType:%pObjectType%, pObject:%pObject%, pSecurityLevel:%pSecurityLevel%, pSecurityRefresh:%pSecurityRefresh%, pDelim:%pDelim%.' ; \r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n# If no groups have been specified then terminate process\r\nIf( Trim( pGroup ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No groups specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate Object Type\r\nIf(pObjectType @<> 'Cube' & pObjectType @<> 'Dimension' & pObjectType @<> 'Process' & pObjectType @<> 'Chore' );\r\n nErrors = 1;\r\n sMessage = 'Invalid object type specified: ' | pObjectType | '. Valid object types are: Cube, Dimension, Process and Chore';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# If no objects have been specified then terminate process\r\nIf( Trim( pObject ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No objects specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate that object type has object security enabled\r\nIf( CubeExists( cSecurityCube ) = 0 );\r\n sObjectTypePlural = pObjectType;\r\n If( pObjectType @= 'Process');\r\n sObjectTypePlural = sObjectTypePlural | 'es';\r\n Else;\r\n sObjectTypePlural = sObjectTypePlural | 's';\r\n EndIf;\r\n nErrors = 1;\r\n sMessage = 'You must first initialise ' | pObjectType | ' Security. In the Server Explorer go to ' |\r\n sObjectTypePlural | ' -> Security Assignments, and assign an access security to a ' |\r\n pObjectType | '. Then from the Server Explorer go to your ServerName -> Security -> Refresh Security';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Set Object Type Dimension\r\nsObjectTypeDimension = '}' | pObjectType;\r\nIf( pObjectType @= 'Process' );\r\n sObjectTypeDimension = sObjectTypeDimension | 'es';\r\nElse;\r\n sObjectTypeDimension = sObjectTypeDimension | 's';\r\nEndIf;\r\n\r\n# Validate Security Level\r\n# Allowable Security Levels by Object Type (excluding RESERVE and LOCK):\r\n# Cube : NONE, READ, ADMIN, WRITE\r\n# Dimension : NONE, READ, ADMIN, WRITE\r\n# Process : NONE, READ\r\n# Chore : NONE, READ\r\npSecurityLevel = Upper( pSecurityLevel );\r\nIf( pSecurityLevel @= 'NONE' % pSecurityLevel @= 'READ' % \r\n ( pSecurityLevel @= 'ADMIN' & ( pObjectType @= 'Cube' % pObjectType @= 'Dimension' ) ) %\r\n ( pSecurityLevel @= 'WRITE' & ( pObjectType @= 'Cube' % pObjectType @= 'Dimension' ) ) );\r\n # Valid Security Levels\r\nElse;\r\n nErrors = 1;\r\n sMessage = 'Invalid security level parameter: ' | pSecurityLevel | ' for object type: ' | pObjectType;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# If pSecurityRefresh is blank then default to yes\r\nIf( Trim( pSecurityRefresh ) @= '' );\r\n pSecurityRefresh = 'Yes';\r\nEndIf;\r\n\r\n# If pSecurityRefresh has not been specified correctly then terminate process\r\nIf( Upper( pSecurityRefresh ) @<> 'YES' & Upper( pSecurityRefresh ) @<> 'NO' );\r\n nErrors = 1;\r\n sMessage = 'Incorrect value for pSecurityRefresh: ' | pSecurityRefresh | '. Valid values are Yes or No';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# If blank delimiter specified then convert to default\r\nIf( pDelim @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### Assign Application Security ###\r\n# Loop through list of groups\r\nsGroups = pGroup;\r\nnGroupDelimIndex = 1;\r\n\r\nWhile( nGroupDelimIndex <> 0 );\r\n nGroupDelimIndex = Scan( pDelim, sGroups );\r\n If( nGroupDelimIndex = 0 );\r\n sGroup = sGroups;\r\n Else;\r\n sGroup = Trim( SubSt( sGroups, 1, nGroupDelimIndex - 1 ) );\r\n sGroups = Trim( Subst( sGroups, nGroupDelimIndex + Long(pDelim), Long( sGroups ) ) );\r\n EndIf;\r\n \r\n\r\n If(Scan('*',sGroup) = 0);\r\n \r\n \r\n # Don't attempt to process a blank group or ADMIN\r\n If( sGroup @<> '' & sGroup @<> 'ADMIN' );\r\n # Check that Group exists\r\n If( DimIx( '}Groups', sGroup ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Group: ' | sGroup | ' does not exists';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n ELSE;\r\n\r\n # Loop through list of objects\r\n sObjects = pObject;\r\n nObjectDelimIndex = 1;\r\n\r\n While( nObjectDelimIndex <> 0 );\r\n nObjectDelimIndex = Scan( pDelim, sObjects );\r\n If( nObjectDelimIndex = 0 );\r\n sObject = sObjects;\r\n Else;\r\n sObject = Trim( SubSt( sObjects, 1, nObjectDelimIndex - 1 ) );\r\n sObjects = Trim( Subst( sObjects, nObjectDelimIndex + Long(pDelim), Long( sObjects ) ) );\r\n EndIf;\r\n If( Scan( '*', sObject ) = 0);\r\n # Don't attempt to process a blank object\r\n If( sObject @<> '' );\r\n # Check that object exists\r\n If( DimIx( sObjectTypeDimension, sObject ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Object: ' | sObject | ' does not exists';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n ELSE;\r\n # Assign Security\r\n If( CellIsUpdateable( cSecurityCube, sObject, sGroup ) = 1 );\r\n If( nErrors = 0);\r\n CellPutS( pSecurityLevel, cSecurityCube, sObject, sGroup );\r\n EndIf;\r\n EndIf;\r\n EndIf;\r\n EndIf;\r\n ELSE;\r\n # Wildcard search string\r\n sObject = '\"'|sObject|'\"';\r\n sMdx = '{TM1FILTERBYPATTERN( {TM1SUBSETALL([ ' |sObjectTypeDimension| '])},'| sObject| ')}';\r\n If( SubsetExists( sObjectTypeDimension, cTempSub ) = 1 );\r\n # If a delimited list of objects includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( sObjectTypeDimension, cTempSub, sMDX );\r\n Else;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSub, sMDX, sObjectTypeDimension, 1 );\r\n EndIf;\r\n nCountObj = SubsetGetSize( sObjectTypeDimension, cTempSub );\r\n While( nCountObj >= 1 );\r\n sObject = SubsetGetElementName( sObjectTypeDimension, cTempSub, nCountObj );\r\n # Assign Security\r\n If( CellIsUpdateable( cSecurityCube, sObject, sGroup ) = 1 );\r\n If( nErrors = 0);\r\n CellPutS( pSecurityLevel, cSecurityCube, sObject, sGroup );\r\n EndIf;\r\n EndIf;\r\n nCountObj = nCountObj - 1;\r\n End;\r\n EndIf;\r\n End;\r\n EndIf;\r\n EndIf;\r\n ELSE;\r\n# Wildcard search string\r\n sGroupDim = '}Groups';\r\n sGroup = '\"'|sGroup|'\"';\r\n sMdx = '{TM1FILTERBYPATTERN( {TM1SUBSETALL([ ' |sGroupDim| '])},'| sGroup| ')}';\r\n If( SubsetExists( sGroupDim, cTempSub ) = 1 );\r\n # If a delimited list of groups includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( sGroupDim, cTempSub, sMDX );\r\n Else;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSub, sMDX, sGroupDim, 1 );\r\n EndIf;\r\n # Loop through dimensions in groups with wildcard\r\n nCountGroup = SubsetGetSize( '}Groups' , cTempSub );\r\n While( nCountGroup >= 1 );\r\n \r\n sGroup = SubsetGetElementName( '}Groups' , cTempSub, nCountGroup );\r\n # Validate group name\r\n If( Dimix('}Groups', sGroup) = 0 );\r\n nErrors = 1;\r\n sMessage = Expand( 'Group \"%sGroup%\" does not exist.' );\r\n LogOutput( 'ERROR', Expand( cMsgErrorContent ) );\r\n Else;\r\n # Loop through list of objects\r\n sObjects = pObject;\r\n nObjectDelimIndex = 1;\r\n\r\n While( nObjectDelimIndex <> 0 );\r\n nObjectDelimIndex = Scan( pDelim, sObjects );\r\n If( nObjectDelimIndex = 0 );\r\n sObject = sObjects;\r\n Else;\r\n sObject = Trim( SubSt( sObjects, 1, nObjectDelimIndex - 1 ) );\r\n sObjects = Trim( Subst( sObjects, nObjectDelimIndex + Long(pDelim), Long( sObjects ) ) );\r\n EndIf;\r\n If( Scan( '*', sObject ) = 0);\r\n # Don't attempt to process a blank object\r\n If( sObject @<> '' );\r\n # Check that object exists\r\n If( DimIx( sObjectTypeDimension, sObject ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Object: ' | sObject | ' does not exists';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n ELSE;\r\n # Assign Security\r\n If( CellIsUpdateable( cSecurityCube, sObject, sGroup ) = 1 );\r\n If( nErrors = 0);\r\n CellPutS( pSecurityLevel, cSecurityCube, sObject, sGroup );\r\n EndIf;\r\n EndIf;\r\n EndIf;\r\n EndIf;\r\n ELSE;\r\n # Wildcard search string\r\n sObject = '\"'|sObject|'\"';\r\n sMdx = '{TM1FILTERBYPATTERN( {TM1SUBSETALL([ ' |sObjectTypeDimension| '])},'| sObject| ')}';\r\n If( SubsetExists( sObjectTypeDimension, cTempSub ) = 1 );\r\n # If a delimited list of objects includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( sObjectTypeDimension, cTempSub, sMDX );\r\n Else;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSub, sMDX, sObjectTypeDimension, 1 );\r\n EndIf;\r\n nCountObj = SubsetGetSize( sObjectTypeDimension, cTempSub );\r\n While( nCountObj >= 1 );\r\n sObject = SubsetGetElementName( sObjectTypeDimension, cTempSub, nCountObj );\r\n # Assign Security\r\n If( CellIsUpdateable( cSecurityCube, sObject, sGroup ) = 1 );\r\n If( nErrors = 0);\r\n CellPutS( pSecurityLevel, cSecurityCube, sObject, sGroup );\r\n EndIf;\r\n EndIf;\r\n nCountObj = nCountObj - 1;\r\n End;\r\n EndIf;\r\n End;\r\n Endif;\r\n nCountGroup = nCountGroup - 1;\r\n End;\r\n Endif; \r\nEnd;\r\n\r\n\r\n### Refresh Security ###\r\n\r\nIf( Upper( pSecurityRefresh ) @= 'YES' );\r\n SecurityRefresh;\r\nEndIf;\r\n\r\n\r\n### End Prolog ###", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.security.object.assign', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pGroup', '', 'pObjectType', '', 'pObject', '',\r\n \t'pSecurityLevel', '', 'pSecurityRefresh', 'No', 'pDelim', '&'\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will assign security to specified object(s) for specified group(s). Both pGroup \r\n# and pObject parameters support delimited lists and wildcards.\r\n\r\n# Use case: Intended for develpment or production.\r\n# 1. Set up initial security assignments.\r\n# 2. Update security assignments a business needs change.\r\n\r\n# Note:\r\n# Naturally, group (pGroup), object type (pObjectType) and security level (pSecurityLevel) are mandatory otherwise the process will abort:\r\n# - Multiple groups can be specified separated by delimiter.\r\n# Object names (pObject) can be listed with delimiters but need to be valid as well. \r\n# - Before using this process, you must first initialise object security.\r\n# - For Cubes, in Server Explorer, right click Cubes -> Cube Security and assign an access security for a Cube. \r\n# - For other object types follow a similar process but for that object type.\r\n# - Then from the Server Explorer go to your ServerName -> Security -> Refresh Security.\r\n# - Multiple objects can be specified separated by delimiter.\r\n# - If groups and/or objects that don't exist are specified, then they will be skipped but valid groups and ojects will still be processed.\r\n#EndRegion @DOC\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncSecurityCube = '}' | pObjectType | 'Security';\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncUserName = TM1User();\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pGroup:%pGroup%, pObjectType:%pObjectType%, pObject:%pObject%, pSecurityLevel:%pSecurityLevel%, pSecurityRefresh:%pSecurityRefresh%, pDelim:%pDelim%.' ;\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pDelim\": \"&\",\r\n \"pGroup\": null,\r\n \"pObject\": null,\r\n \"pObjectType\": null,\r\n \"pSecurityLevel\": null,\r\n \"pSecurityRefresh\": \"Yes\",\r\n \"pLogOutput\": 0,\r\n \"pStrictErrorHandling\": 0\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pDelim\": '|StringToJson ( pDelim )|',\r\n \"pGroup\": '|StringToJson ( pGroup )|',\r\n \"pObject\": '|StringToJson ( pObject )|',\r\n \"pObjectType\": '|StringToJson ( pObjectType )|',\r\n \"pSecurityLevel\": '|StringToJson ( pSecurityLevel )|',\r\n \"pSecurityRefresh\": '|StringToJson ( pSecurityRefresh )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npDelim = JsonToString( JsonGet( pJson, 'pDelim' ) );\r\npGroup = JsonToString( JsonGet( pJson, 'pGroup' ) );\r\npObject = JsonToString( JsonGet( pJson, 'pObject' ) );\r\npObjectType = JsonToString( JsonGet( pJson, 'pObjectType' ) );\r\npSecurityLevel = JsonToString( JsonGet( pJson, 'pSecurityLevel' ) );\r\npSecurityRefresh = JsonToString( JsonGet( pJson, 'pSecurityRefresh' ) );\r\n# Numeric Parameters\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n# If no groups have been specified then terminate process\r\nIf( Trim( pGroup ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No groups specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate Object Type\r\nIf(pObjectType @<> 'Cube' & pObjectType @<> 'Dimension' & pObjectType @<> 'Process' & pObjectType @<> 'Chore' );\r\n nErrors = 1;\r\n sMessage = 'Invalid object type specified: ' | pObjectType | '. Valid object types are: Cube, Dimension, Process and Chore';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# If no objects have been specified then terminate process\r\nIf( Trim( pObject ) @= '' );\r\n nErrors = 1;\r\n sMessage = 'No objects specified.';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Validate that object type has object security enabled\r\nIf( CubeExists( cSecurityCube ) = 0 );\r\n sObjectTypePlural = pObjectType;\r\n If( pObjectType @= 'Process');\r\n sObjectTypePlural = sObjectTypePlural | 'es';\r\n Else;\r\n sObjectTypePlural = sObjectTypePlural | 's';\r\n EndIf;\r\n nErrors = 1;\r\n sMessage = 'You must first initialise ' | pObjectType | ' Security. In the Server Explorer go to ' |\r\n sObjectTypePlural | ' -> Security Assignments, and assign an access security to a ' |\r\n pObjectType | '. Then from the Server Explorer go to your ServerName -> Security -> Refresh Security';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# Set Object Type Dimension\r\nsObjectTypeDimension = '}' | pObjectType;\r\nIf( pObjectType @= 'Process' );\r\n sObjectTypeDimension = sObjectTypeDimension | 'es';\r\nElse;\r\n sObjectTypeDimension = sObjectTypeDimension | 's';\r\nEndIf;\r\n\r\n# Validate Security Level\r\n# Allowable Security Levels by Object Type (excluding RESERVE and LOCK):\r\n# Cube : NONE, READ, ADMIN, WRITE\r\n# Dimension : NONE, READ, ADMIN, WRITE\r\n# Process : NONE, READ\r\n# Chore : NONE, READ\r\npSecurityLevel = Upper( pSecurityLevel );\r\nIf( pSecurityLevel @= 'NONE' % pSecurityLevel @= 'READ' % \r\n ( pSecurityLevel @= 'ADMIN' & ( pObjectType @= 'Cube' % pObjectType @= 'Dimension' ) ) %\r\n ( pSecurityLevel @= 'WRITE' & ( pObjectType @= 'Cube' % pObjectType @= 'Dimension' ) ) );\r\n # Valid Security Levels\r\nElse;\r\n nErrors = 1;\r\n sMessage = 'Invalid security level parameter: ' | pSecurityLevel | ' for object type: ' | pObjectType;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# If pSecurityRefresh is blank then default to yes\r\nIf( Trim( pSecurityRefresh ) @= '' );\r\n pSecurityRefresh = 'Yes';\r\nEndIf;\r\n\r\n# If pSecurityRefresh has not been specified correctly then terminate process\r\nIf( Upper( pSecurityRefresh ) @<> 'YES' & Upper( pSecurityRefresh ) @<> 'NO' );\r\n nErrors = 1;\r\n sMessage = 'Incorrect value for pSecurityRefresh: ' | pSecurityRefresh | '. Valid values are Yes or No';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n# If blank delimiter specified then convert to default\r\nIf( pDelim @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### Assign Application Security ###\r\n# Loop through list of groups\r\nsGroups = pGroup;\r\nnGroupDelimIndex = 1;\r\n\r\nWhile( nGroupDelimIndex <> 0 );\r\n nGroupDelimIndex = Scan( pDelim, sGroups );\r\n If( nGroupDelimIndex = 0 );\r\n sGroup = sGroups;\r\n Else;\r\n sGroup = Trim( SubSt( sGroups, 1, nGroupDelimIndex - 1 ) );\r\n sGroups = Trim( Subst( sGroups, nGroupDelimIndex + Long(pDelim), Long( sGroups ) ) );\r\n EndIf;\r\n \r\n\r\n If(Scan('*',sGroup) = 0);\r\n \r\n \r\n # Don't attempt to process a blank group or ADMIN\r\n If( sGroup @<> '' & sGroup @<> 'ADMIN' );\r\n # Check that Group exists\r\n If( DimIx( '}Groups', sGroup ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Group: ' | sGroup | ' does not exists';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n ELSE;\r\n\r\n # Loop through list of objects\r\n sObjects = pObject;\r\n nObjectDelimIndex = 1;\r\n\r\n While( nObjectDelimIndex <> 0 );\r\n nObjectDelimIndex = Scan( pDelim, sObjects );\r\n If( nObjectDelimIndex = 0 );\r\n sObject = sObjects;\r\n Else;\r\n sObject = Trim( SubSt( sObjects, 1, nObjectDelimIndex - 1 ) );\r\n sObjects = Trim( Subst( sObjects, nObjectDelimIndex + Long(pDelim), Long( sObjects ) ) );\r\n EndIf;\r\n If( Scan( '*', sObject ) = 0);\r\n # Don't attempt to process a blank object\r\n If( sObject @<> '' );\r\n # Check that object exists\r\n If( DimIx( sObjectTypeDimension, sObject ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Object: ' | sObject | ' does not exists';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n ELSE;\r\n # Assign Security\r\n If( CellIsUpdateable( cSecurityCube, sObject, sGroup ) = 1 );\r\n If( nErrors = 0);\r\n CellPutS( pSecurityLevel, cSecurityCube, sObject, sGroup );\r\n EndIf;\r\n EndIf;\r\n EndIf;\r\n EndIf;\r\n ELSE;\r\n # Wildcard search string\r\n sObject = '\"'|sObject|'\"';\r\n sMdx = '{TM1FILTERBYPATTERN( {TM1SUBSETALL([ ' |sObjectTypeDimension| '])},'| sObject| ')}';\r\n If( SubsetExists( sObjectTypeDimension, cTempSub ) = 1 );\r\n # If a delimited list of objects includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( sObjectTypeDimension, cTempSub, sMDX );\r\n Else;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSub, sMDX, sObjectTypeDimension, 1 );\r\n EndIf;\r\n nCountObj = SubsetGetSize( sObjectTypeDimension, cTempSub );\r\n While( nCountObj >= 1 );\r\n sObject = SubsetGetElementName( sObjectTypeDimension, cTempSub, nCountObj );\r\n # Assign Security\r\n If( CellIsUpdateable( cSecurityCube, sObject, sGroup ) = 1 );\r\n If( nErrors = 0);\r\n CellPutS( pSecurityLevel, cSecurityCube, sObject, sGroup );\r\n EndIf;\r\n EndIf;\r\n nCountObj = nCountObj - 1;\r\n End;\r\n EndIf;\r\n End;\r\n EndIf;\r\n EndIf;\r\n ELSE;\r\n# Wildcard search string\r\n sGroupDim = '}Groups';\r\n sGroup = '\"'|sGroup|'\"';\r\n sMdx = '{TM1FILTERBYPATTERN( {TM1SUBSETALL([ ' |sGroupDim| '])},'| sGroup| ')}';\r\n If( SubsetExists( sGroupDim, cTempSub ) = 1 );\r\n # If a delimited list of groups includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( sGroupDim, cTempSub, sMDX );\r\n Else;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSub, sMDX, sGroupDim, 1 );\r\n EndIf;\r\n # Loop through dimensions in groups with wildcard\r\n nCountGroup = SubsetGetSize( '}Groups' , cTempSub );\r\n While( nCountGroup >= 1 );\r\n \r\n sGroup = SubsetGetElementName( '}Groups' , cTempSub, nCountGroup );\r\n # Validate group name\r\n If( Dimix('}Groups', sGroup) = 0 );\r\n nErrors = 1;\r\n sMessage = Expand( 'Group \"%sGroup%\" does not exist.' );\r\n LogOutput( 'ERROR', Expand( cMsgErrorContent ) );\r\n Else;\r\n # Loop through list of objects\r\n sObjects = pObject;\r\n nObjectDelimIndex = 1;\r\n\r\n While( nObjectDelimIndex <> 0 );\r\n nObjectDelimIndex = Scan( pDelim, sObjects );\r\n If( nObjectDelimIndex = 0 );\r\n sObject = sObjects;\r\n Else;\r\n sObject = Trim( SubSt( sObjects, 1, nObjectDelimIndex - 1 ) );\r\n sObjects = Trim( Subst( sObjects, nObjectDelimIndex + Long(pDelim), Long( sObjects ) ) );\r\n EndIf;\r\n If( Scan( '*', sObject ) = 0);\r\n # Don't attempt to process a blank object\r\n If( sObject @<> '' );\r\n # Check that object exists\r\n If( DimIx( sObjectTypeDimension, sObject ) = 0 );\r\n nErrors = 1;\r\n sMessage = 'Object: ' | sObject | ' does not exists';\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n ELSE;\r\n # Assign Security\r\n If( CellIsUpdateable( cSecurityCube, sObject, sGroup ) = 1 );\r\n If( nErrors = 0);\r\n CellPutS( pSecurityLevel, cSecurityCube, sObject, sGroup );\r\n EndIf;\r\n EndIf;\r\n EndIf;\r\n EndIf;\r\n ELSE;\r\n # Wildcard search string\r\n sObject = '\"'|sObject|'\"';\r\n sMdx = '{TM1FILTERBYPATTERN( {TM1SUBSETALL([ ' |sObjectTypeDimension| '])},'| sObject| ')}';\r\n If( SubsetExists( sObjectTypeDimension, cTempSub ) = 1 );\r\n # If a delimited list of objects includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( sObjectTypeDimension, cTempSub, sMDX );\r\n Else;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSub, sMDX, sObjectTypeDimension, 1 );\r\n EndIf;\r\n nCountObj = SubsetGetSize( sObjectTypeDimension, cTempSub );\r\n While( nCountObj >= 1 );\r\n sObject = SubsetGetElementName( sObjectTypeDimension, cTempSub, nCountObj );\r\n # Assign Security\r\n If( CellIsUpdateable( cSecurityCube, sObject, sGroup ) = 1 );\r\n If( nErrors = 0);\r\n CellPutS( pSecurityLevel, cSecurityCube, sObject, sGroup );\r\n EndIf;\r\n EndIf;\r\n nCountObj = nCountObj - 1;\r\n End;\r\n EndIf;\r\n End;\r\n Endif;\r\n nCountGroup = nCountGroup - 1;\r\n End;\r\n Endif; \r\nEnd;\r\n\r\n\r\n### Refresh Security ###\r\n\r\nIf( Upper( pSecurityRefresh ) @= 'YES' );\r\n SecurityRefresh;\r\nEndIf;\r\n\r\n\r\n### End Prolog ###", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully assigned object %pObject% of type %pObjectType% security level %pSecurityLevel% for group %pGroup%.' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n### End Epilog ###", @@ -10,53 +10,59 @@ "Type": "None" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pGroup", - "Prompt": "REQUIRED: List of Groups Separated by Delimiter", + "Prompt": "REQUIRED: Delimited list of groups", "Value": "", "Type": "String" }, { "Name": "pObjectType", - "Prompt": "REQUIRED: Type of Object to Assign Security To (Cube/Dimension/Process/Chore)", + "Prompt": "REQUIRED: Type of Object to assign security to ('Cube' or 'Dimension' or 'Process' or 'Chore')", "Value": "", "Type": "String" }, { "Name": "pObject", - "Prompt": "REQUIRED: List of Objects Separated by Delimiter", + "Prompt": "REQUIRED: Delimited list of objects", "Value": "", "Type": "String" }, { "Name": "pSecurityLevel", - "Prompt": "REQUIRED: Security Level (Read/Write/Admin/None)", + "Prompt": "REQUIRED: Security level ('Read' or 'Write' or 'Admin' or 'None')", "Value": "", "Type": "String" }, { "Name": "pSecurityRefresh", - "Prompt": "OPTIONAL: Refresh Security? (Default = No)", - "Value": "No", + "Prompt": "OPTIONAL: Refresh security after process execution ('Yes' or 'No'. Default = 'Yes')", + "Value": "Yes", "Type": "String" }, { "Name": "pDelim", - "Prompt": "OPTIONAL: Delimiter (default value if blank = '&')", + "Prompt": "OPTIONAL: Delimiter for list parameters (Default = '&')", "Value": "&", "Type": "String" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [], diff --git a/bedrock_processes_json/}bedrock.security.refresh.json b/bedrock_processes_json/}bedrock.security.refresh.json index 8d66f0a..b62e1c8 100644 --- a/bedrock_processes_json/}bedrock.security.refresh.json +++ b/bedrock_processes_json/}bedrock.security.refresh.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.security.refresh", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.security.refresh', 'pLogOutput', pLogOutput, 'pStrictErrorHandling', pStrictErrorHandling );\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process refreshes TM1 security.\r\n\r\n# Use case: Intended for development or production.\r\n# 1/ Refresh security after new clients or security groups are added.\r\n# 2/ If security cubes have rules and they had to be changed.\r\n\r\n# Note:\r\n# This can be a time consuming process and may need to be run overnight.\r\n#EndRegion @DOC\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncUserName = TM1User();\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters.' ; \r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\nnErrors = 0;\r\n\r\n### Refresh Security ###\r\n\r\nSecurityRefresh;\r\n\r\n### End Prolog ###", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.security.refresh', 'pLogOutput', pLogOutput, 'pStrictErrorHandling', pStrictErrorHandling );\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process refreshes TM1 security.\r\n\r\n# Use case: Intended for development or production.\r\n# 1/ Refresh security after new clients or security groups are added.\r\n# 2/ If security cubes have rules and they had to be changed.\r\n\r\n# Note:\r\n# This can be a time consuming process and may need to be run overnight.\r\n#EndRegion @DOC\r\n\r\n##Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncUserName = TM1User();\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters.' ;\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pLogOutput\": 0,\r\n \"pStrictErrorHandling\": 0\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\n\r\n# Numeric Parameters\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\nnErrors = 0;\r\n\r\n### Refresh Security ###\r\n\r\nSecurityRefresh;\r\n\r\n### End Prolog ###", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully refreshed security.' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n### End Epilog ###", @@ -12,15 +12,21 @@ "Parameters": [ { "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [], diff --git a/bedrock_processes_json/}bedrock.server.deleteallpersistentfeeders.json b/bedrock_processes_json/}bedrock.server.deleteallpersistentfeeders.json index 1890d5b..e229644 100644 --- a/bedrock_processes_json/}bedrock.server.deleteallpersistentfeeders.json +++ b/bedrock_processes_json/}bedrock.server.deleteallpersistentfeeders.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.server.deleteallpersistentfeeders", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.server.deleteallpersistentfeeders', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n\t 'pRun', 'Y'\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will Delete Persistent feeders.\r\n\r\n# Use case: Intended for development or production.\r\n# 1/ Persistent feeders turned off in config file.\r\n# 2/ Want to reprocess feeders.\r\n\r\n# Note:\r\n# Reprocessing feeders could take a long time and it may be better to run this overnight.\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pRun:%pRun% .'; \r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\nnErrors = 0;\r\n\r\n### Delete Feeders ###\r\nIf( pRun @= 'Y' );\r\n DeleteAllPersistentFeeders;\r\nEndIf;", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.server.deleteallpersistentfeeders', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n\t 'pRun', 'Y'\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will Delete Persistent feeders.\r\n\r\n# Use case: Intended for development or production.\r\n# 1/ Persistent feeders turned off in config file.\r\n# 2/ Want to reprocess feeders.\r\n\r\n# Note:\r\n# Reprocessing feeders could take a long time and it may be better to run this overnight.\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pRun:%pRun% .';\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pRun\": \"Y\",\r\n \"pLogOutput\": 0,\r\n \"pStrictErrorHandling\": 0\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pRun\": '|StringToJson ( pRun )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npRun = JsonToString( JsonGet( pJson, 'pRun' ) );\r\n# Numeric Parameters\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\nnErrors = 0;\r\n\r\n### Delete Feeders ###\r\nIf( pRun @= 'Y' );\r\n DeleteAllPersistentFeeders;\r\nEndIf;", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully deleted persistant feeders.' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n### End Epilog ###", @@ -10,22 +10,28 @@ "Type": "None" }, "Parameters": [ + { + "Name": "pRun", + "Prompt": "OPTIONAL: Delete all persistent feeders ('Y' or 'N'. Default = 'Y')", + "Value": "Y", + "Type": "String" + }, { "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { - "Name": "pRun", - "Prompt": "OPTIONAL: Do you want to delete Persistent Feeders? (Y or N)", - "Value": "Y", + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", "Type": "String" } ], diff --git a/bedrock_processes_json/}bedrock.server.dir.backup.json b/bedrock_processes_json/}bedrock.server.dir.backup.json index 5f4be23..972839a 100644 --- a/bedrock_processes_json/}bedrock.server.dir.backup.json +++ b/bedrock_processes_json/}bedrock.server.dir.backup.json @@ -10,53 +10,59 @@ "Type": "None" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pSrcDir", - "Prompt": "REQUIRED: Source Directory to Backup", - "Value": ".", + "Prompt": "OPTIONAL: File directory (Default = GetProcessErrorFileDirectory)", + "Value": "", "Type": "String" }, { "Name": "pTgtDir", - "Prompt": "REQUIRED: Destination Directory for Backup", + "Prompt": "OPTIONAL: Target file directory (Default = GetProcessErrorFileDirectory)", "Value": "", "Type": "String" }, { "Name": "pExcludeFilter", - "Prompt": "OPTIONAL: Exclude filter (To include all files use pFilterExclude = \"\")", + "Prompt": "OPTIONAL: Delimited list of exclusion filters (Default = '.log & .cfg & .csv & .cmal & .txt & .feeders')", "Value": ".log & .cfg & .csv & .cmal & .txt & .feeders", "Type": "String" }, { "Name": "pDelim", - "Prompt": "OPTIONAL: Delimiter", + "Prompt": "OPTIONAL: Delimiter for list parameters (Default = '&')", "Value": "&", "Type": "String" }, { "Name": "pSubDirCopy", - "Prompt": "OPTIONAL: Include subdirectories? (Boolean True = 1)", + "Prompt": "OPTIONAL: Include subdirectories (Boolean. Default = 1)", "Value": 1, "Type": "Numeric" }, { "Name": "pRobocopy", - "Prompt": "OPTIONAL: Use robocopy? (Boolean True = 1), WIN only", + "Prompt": "OPTIONAL: Use Robocopy (WIN Only. Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [], diff --git a/bedrock_processes_json/}bedrock.server.dir.listcontents.json b/bedrock_processes_json/}bedrock.server.dir.listcontents.json index a527626..ae8e167 100644 --- a/bedrock_processes_json/}bedrock.server.dir.listcontents.json +++ b/bedrock_processes_json/}bedrock.server.dir.listcontents.json @@ -10,22 +10,28 @@ "Type": "None" }, "Parameters": [ + { + "Name": "pSrcDir", + "Prompt": "OPTIONAL: File directory (Default = GetProcessErrorFileDirectory)", + "Value": "", + "Type": "String" + }, { "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { - "Name": "pSrcDir", - "Prompt": "OPTIONAL: Data Directory (Leave Blank to use TM1 Settings)", - "Value": "", + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters.", + "Value": "{}", "Type": "String" } ], diff --git a/bedrock_processes_json/}bedrock.server.encrypt.directory.json b/bedrock_processes_json/}bedrock.server.encrypt.directory.json index 98ba995..4cc373e 100644 --- a/bedrock_processes_json/}bedrock.server.encrypt.directory.json +++ b/bedrock_processes_json/}bedrock.server.encrypt.directory.json @@ -10,18 +10,6 @@ "Type": "None" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pType", "Prompt": "REQUIRED: .rux, .dim, .pro, .cub", @@ -36,13 +24,13 @@ }, { "Name": "pDestPath", - "Prompt": "REQUIRED: Directory where to store encrypted files, blank = logging directory", + "Prompt": "OPTIONAL: Directory where to store encrypted files (Default = GetProcessLogFileDirectory)", "Value": "", "Type": "String" }, { "Name": "pConfigLocation", - "Prompt": "REQUIRED: Path to tm1crypt.config file", + "Prompt": "REQUIRED: Path to tm1crypt.config", "Value": "", "Type": "String" }, @@ -54,9 +42,27 @@ }, { "Name": "pAction", - "Prompt": "REQUIRED: 5 = unencrypt, 4 = encrypt", + "Prompt": "OPTIONAL: (5 = unencrypt, 4 = encrypt. Default = 5)", "Value": "5", "Type": "String" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [], diff --git a/bedrock_processes_json/}bedrock.server.encrypt.file.json b/bedrock_processes_json/}bedrock.server.encrypt.file.json index fea30d3..6eacbe0 100644 --- a/bedrock_processes_json/}bedrock.server.encrypt.file.json +++ b/bedrock_processes_json/}bedrock.server.encrypt.file.json @@ -10,18 +10,6 @@ "Type": "None" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pSourcePath", "Prompt": "REQUIRED: Source directory of file to be processed", @@ -36,13 +24,13 @@ }, { "Name": "pDestPath", - "Prompt": "REQUIRED: Directory where to store encrypted files, blank = logging directory", + "Prompt": "OPTIONAL: Directory where to store encrypted files (Default = GetProcessLogFileDirectory)", "Value": "", "Type": "String" }, { "Name": "pConfigLocation", - "Prompt": "REQUIRED: Path to tm1crypt.config file", + "Prompt": "REQUIRED: Path to tm1crypt.config", "Value": "", "Type": "String" }, @@ -54,9 +42,27 @@ }, { "Name": "pAction", - "Prompt": "REQUIRED: 5 = unencrypt, 4 = encrypt", + "Prompt": "OPTIONAL: (5 = unencrypt, 4 = encrypt. Default = 5)", "Value": "5", "Type": "String" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [], diff --git a/bedrock_processes_json/}bedrock.server.executecommand.json b/bedrock_processes_json/}bedrock.server.executecommand.json index ff4ee59..cad6523 100644 --- a/bedrock_processes_json/}bedrock.server.executecommand.json +++ b/bedrock_processes_json/}bedrock.server.executecommand.json @@ -11,34 +11,40 @@ }, "Parameters": [ { - "Name": "pLogOutput", - "Prompt": "Optional: write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" + "Name": "pCommand", + "Prompt": "REQUIRED: The full command line string to execute", + "Value": "", + "Type": "String" }, { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", + "Name": "pWait", + "Prompt": "OPTIONAL: Wait for command to finish executing (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { - "Name": "pCommand", - "Prompt": "The full command line string to execute", - "Value": "", - "Type": "String" + "Name": "pPowerShell", + "Prompt": "OPTIONAL: Execute a PowerShell script (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" }, { - "Name": "pWait", - "Prompt": "Wait for command to finish 0=false 1=true", + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { - "Name": "pPowerShell", - "Prompt": "Execute a PowerShell script 0=false 1=true", + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [ diff --git a/bedrock_processes_json/}bedrock.server.localize.json b/bedrock_processes_json/}bedrock.server.localize.json index f680a3d..09fca63 100644 --- a/bedrock_processes_json/}bedrock.server.localize.json +++ b/bedrock_processes_json/}bedrock.server.localize.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.server.localize", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.server.localize', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n\t 'pDim', '', 'pCube', '', 'pDelim', '&', 'pSub', 0\r\n );\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~ Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock Ver 4.0 ~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process localizes cube & dimension names & optionally localizes:\r\n# * attributes for specified dimension(s)\r\n# * subsets for specified dimension(s)\r\n# * views for specified cube(s)\r\n\r\n# Note:\r\n# If no dimension or cube names are passed, then just cube & dimension names will be localized.\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pDelim:%pDelim%.'; \r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\nIf( Trim( pDelim ) @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\nIf( pSub <> 1 );\r\n pSub = 0;\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\nIF( CubeExists( '}CubeAttributes' ) = 0 );\r\n CubeAttrInsert( '', 'Caption', 'S');\r\nELSEIF( DimIx( '}CubeAttributes', 'Caption' ) = 0 );\r\n CubeAttrInsert( '', 'Caption', 'S');\r\nENDIF;\r\nIF( CubeExists( '}DimensionAttributes' ) = 0 );\r\n DimensionAttrInsert( '', 'Caption', 'S');\r\nELSEIF( DimIx( '}DimensionAttributes', 'Caption' ) = 0 );\r\n DimensionAttrInsert( '', 'Caption', 'S');\r\nENDIF;\r\n\r\nIF( CubeExists( '}LocalizedCubeAttributes' ) = 0 );\r\n CubeAttrPutS( '', '}CubeAttributes', 'Caption', 'en');\r\nENDIF;\r\nIF( CubeExists( '}LocalizedDimensionAttributes' ) = 0 );\r\n DimensionAttrPutS( '', '}Cultures', 'Caption', 'en');\r\nENDIF;\r\n\r\n### Localization of attributes (& subsets) for any dimension passed\r\n# Loop through dimensions in pDim \r\nsDims = Trim( pDim );\r\nnDimDelimiterIndex = 1;\r\n# Get 1st dimension\r\nWhile( pDim @<> '' & nDimDelimiterIndex > 0 );\r\n # Extract 1st dimension > sDim\r\n nDimDelimiterIndex = Scan( pDelim, sDims );\r\n If( nDimDelimiterIndex = 0 );\r\n sDim = sDims;\r\n Else;\r\n sDim = Trim( SubSt( sDims, 1, nDimDelimiterIndex - 1 ) );\r\n sDims = Trim( Subst( sDims, nDimDelimiterIndex + Long(pDelim), Long( sDims ) ) );\r\n EndIf;\r\n \r\n # Check if sDim has wildcard\r\n If( Scan( '*', sDim ) = 0);\r\n If( DimensionExists(sDim) = 0 );\r\n nErrors = 1;\r\n sMessage = Expand( 'Dimension \"%sDim%\" does not exist.' );\r\n LogOutput( 'ERROR', Expand( cMsgErrorContent ) );\r\n Else;\r\n sAttrDim = '}ElementAttributes_' | sDim;\r\n sLocAttrDim = '}LocalizedElementAttributes_' | sDim; \r\n sSubDim = '}Subsets_' | sDim;\r\n sSubAttr = '}SubsetAttributes_' | sDim;\r\n sLocSubAttr = '}LocalizedSubsetAttributes_' | sDim;\r\n IF( CubeExists( sAttrDim ) = 0 );\r\n AttrInsert( sDim, '', 'Caption', 'S' );\r\n ELSEIF( DimIx( sAttrDim, 'Caption' ) = 0 );\r\n AttrInsert( sDim, '', 'Caption', 'S' );\r\n ENDIF;\r\n IF( CubeExists( sLocAttrDim ) = 0 );\r\n sFirstEle = '';\r\n sFirstEle = DimNm( sDim, 1 );\r\n IF( sFirstEle @<> '' );\r\n AttrPutS( '', sDim, sFirstEle, 'Caption', 'en' );\r\n ENDIF;\r\n ENDIF;\r\n If( pSub = 1 & DimSiz( sSubDim ) > 0 );\r\n If( CubeExists( sSubAttr ) = 0 );\r\n SubsetAttrInsert( sDim, '', 'Caption', 'S' );\r\n EndIf;\r\n If( CubeExists( sLocSubAttr ) = 0 );\r\n sSub = DimNm( sSubDim, 1 );\r\n If( Scan( ':', sSub ) > 0 );\r\n sDim = sDim |':'| SubSt( sSub, 1, Scan( ':', sSub ) - 1 );\r\n sSub = SubSt( sSub, Scan( ':', sSub ) + 1, Long( sSub ) );\r\n EndIf;\r\n SubsetAttrPutS( '', sDim, sSub, 'Caption', 'en' );\r\n EndIf;\r\n EndIf;\r\n Endif;\r\n Else;\r\n # Create subset of dimensions using Wildcard to loop through dimensions in pDim with wildcard\r\n sMdx = Expand('{TM1FILTERBYPATTERN( EXCEPT ( EXCEPT ( TM1SUBSETALL( [}Dimensions] ) , TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) , \"*:*\") ), TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) , \"}ElementAttributes_*\") ) , \"%sDim%\" )}');\r\n If( SubsetExists( '}Dimensions' , cTempSub ) = 1 );\r\n # If a delimited list of dim names includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( '}Dimensions' , cTempSub, sMDX );\r\n Else;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSub, sMDX, '}Dimensions' , 1 );\r\n EndIf;\r\n \r\n # Loop through dimensions in subset created based on wildcard\r\n nCountDim = SubsetGetSize( '}Dimensions' , cTempSub );\r\n While( nCountDim >= 1 );\r\n sDim = SubsetGetElementName( '}Dimensions' , cTempSub, nCountDim );\r\n If( DimensionExists(sDim) = 0 );\r\n nErrors = 1;\r\n sMessage = Expand( 'Dimension %sDim% does not exist.' );\r\n LogOutput( 'ERROR', Expand( cMsgErrorContent ) );\r\n Else;\r\n sAttrDim = '}ElementAttributes_' | sDim;\r\n sLocAttrDim = '}LocalizedElementAttributes_' | sDim; \r\n sSubDim = '}Subsets_' | sDim;\r\n sSubAttr = '}SubsetAttributes_' | sDim;\r\n sLocSubAttr = '}LocalizedSubsetAttributes_' | sDim;\r\n IF( CubeExists( sAttrDim ) = 0 );\r\n AttrInsert( sDim, '', 'Caption', 'S' );\r\n ELSEIF( DimIx( sAttrDim, 'Caption' ) = 0 );\r\n AttrInsert( sDim, '', 'Caption', 'S' );\r\n ENDIF;\r\n IF( CubeExists( sLocAttrDim ) = 0 );\r\n sFirstEle = '';\r\n sFirstEle = DimNm( sDim, 1 );\r\n IF( sFirstEle @<> '' );\r\n AttrPutS( '', sDim, sFirstEle, 'Caption', 'en' );\r\n ENDIF;\r\n ENDIF;\r\n If( pSub = 1 );\r\n If( CubeExists( sSubAttr ) = 0 );\r\n SubsetAttrInsert( sDim, '', 'Caption', 'S' );\r\n EndIf;\r\n If( CubeExists( sLocSubAttr ) = 0 & DimSiz( sSubDim ) > 0 );\r\n sSub = DimNm( sSubDim, 1 );\r\n If( Scan( ':', sSub ) > 0 );\r\n sDim = sDim |':'| SubSt( sSub, 1, Scan( ':', sSub ) - 1 );\r\n sSub = SubSt( sSub, Scan( ':', sSub ) + 1, Long( sSub ) );\r\n EndIf;\r\n SubsetAttrPutS( '', sDim, sSub, 'Caption', 'en' );\r\n EndIf;\r\n EndIf;\r\n Endif;\r\n nCountDim = nCountDim - 1;\r\n End;\r\n EndIf;\r\nEnd;\r\n\r\n### Localization of views for any cube passed\r\n# Loop through cubes in pCube \r\nsCubes = Trim( pCube );\r\nnCubDelimiterIndex = 1;\r\n# Get 1st Cube\r\nWhile( pCube @<> '' & nCubDelimiterIndex > 0 );\r\n # Extract 1st cube > sCube\r\n nCubDelimiterIndex = Scan( pDelim, sCubes );\r\n If( nCubDelimiterIndex = 0 );\r\n sCube = sCubes;\r\n Else;\r\n sCube = Trim( SubSt( sCubes, 1, nCubDelimiterIndex - 1 ) );\r\n sCubes = Trim( Subst( sCubes, nCubDelimiterIndex + Long(pDelim), Long( sCubes ) ) );\r\n EndIf;\r\n \r\n # Check if sCube has wildcard\r\n If( Scan( '*', sCube ) = 0);\r\n If( CubeExists(sCube) = 0 );\r\n nErrors = 1;\r\n sMessage = Expand( 'Cube \"%sCube%\" does not exist.' );\r\n LogOutput( 'ERROR', Expand( cMsgErrorContent ) );\r\n Else;\r\n sViewDim = '}Views_' | sCube;\r\n sViewAttr = '}ViewAttributes_' | sCube;\r\n sLocViewAttr = '}LocalizedViewAttributes_' | sCube;\r\n IF( CubeExists( sViewAttr ) = 0 & DimensionExists( sViewDim ) = 1 );\r\n ViewAttrInsert( sCube, '', 'Caption', 'S' );\r\n ENDIF;\r\n IF( CubeExists( sLocViewAttr ) = 0 & DimSiz( sViewDim ) >= 1 );\r\n ViewAttrPutS( '', sCube, DimNm( sViewDim, 1 ), 'Caption', 'en' );\r\n ENDIF;\r\n Endif;\r\n Else;\r\n # Create subset of cubes using Wildcard to loop through cubes in pCube with wildcard\r\n sMdx = Expand('{TM1FILTERBYPATTERN( TM1SUBSETALL( [}Cubes] ), \"%sCube%\" )}');\r\n If( SubsetExists( '}Cubes' , cTempSub ) = 1 );\r\n # If a delimited list of Cub names includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( '}Cubes' , cTempSub, sMDX );\r\n Else;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSub, sMDX, '}Cubes' , 1 );\r\n EndIf;\r\n \r\n # Loop through cubes in subset created based on wildcard\r\n nCountCub = SubsetGetSize( '}Cubes' , cTempSub );\r\n While( nCountCub >= 1 );\r\n sCube = SubsetGetElementName( '}Cubes' , cTempSub, nCountCub );\r\n If( CubeExists(sCube) = 0 );\r\n nErrors = 1;\r\n sMessage = Expand( 'Cube %sCube% does not exist.' );\r\n LogOutput( 'ERROR', Expand( cMsgErrorContent ) );\r\n Else;\r\n sViewDim = '}Views_' | sCube;\r\n sViewAttr = '}ViewAttributes_' | sCube;\r\n sLocViewAttr = '}LocalizedViewAttributes_' | sCube;\r\n IF( CubeExists( sViewAttr ) = 0 & DimensionExists( sViewDim ) = 1 );\r\n ViewAttrInsert( sCube, '', 'Caption', 'S' );\r\n ENDIF;\r\n IF( CubeExists( sLocViewAttr ) = 0 & DimSiz( sViewDim ) >= 1 );\r\n ViewAttrPutS( '', sCube, DimNm( sViewDim, 1 ), 'Caption', 'en' );\r\n ENDIF;\r\n Endif;\r\n nCountCub = nCountCub - 1;\r\n End;\r\n EndIf;\r\nEnd;\r\n\r\n### End Prolog ###", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.server.localize', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n\t 'pDim', '', 'pCube', '', 'pDelim', '&', 'pSub', 0\r\n );\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~ Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock Ver 4.0 ~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process localizes cube & dimension names & optionally localizes:\r\n# * attributes for specified dimension(s)\r\n# * subsets for specified dimension(s)\r\n# * views for specified cube(s)\r\n\r\n# Note:\r\n# If no dimension or cube names are passed, then just cube & dimension names will be localized.\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncTempSub = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pDim:%pDim%, pDelim:%pDelim%.';\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pCube\": null,\r\n \"pDelim\": \"&\",\r\n \"pDim\": null,\r\n \"pLogOutput\": 0,\r\n \"pStrictErrorHandling\": 0,\r\n \"pSub\": 0\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pCube\": '|StringToJson ( pCube )|',\r\n \"pDelim\": '|StringToJson ( pDelim )|',\r\n \"pDim\": '|StringToJson ( pDim )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|',\r\n \"pSub\": '|NumberToString( pSub )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npCube = JsonToString( JsonGet( pJson, 'pCube' ) );\r\npDelim = JsonToString( JsonGet( pJson, 'pDelim' ) );\r\npDim = JsonToString( JsonGet( pJson, 'pDim' ) );\r\n# Numeric Parameters\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\npSub = StringToNumber( JsonToString( JsonGet( pJson, 'pSub' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\n\r\nIf( Trim( pDelim ) @= '' );\r\n pDelim = '&';\r\nEndIf;\r\n\r\nIf( pSub <> 1 );\r\n pSub = 0;\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\nIF( CubeExists( '}CubeAttributes' ) = 0 );\r\n CubeAttrInsert( '', 'Caption', 'S');\r\nELSEIF( DimIx( '}CubeAttributes', 'Caption' ) = 0 );\r\n CubeAttrInsert( '', 'Caption', 'S');\r\nENDIF;\r\nIF( CubeExists( '}DimensionAttributes' ) = 0 );\r\n DimensionAttrInsert( '', 'Caption', 'S');\r\nELSEIF( DimIx( '}DimensionAttributes', 'Caption' ) = 0 );\r\n DimensionAttrInsert( '', 'Caption', 'S');\r\nENDIF;\r\n\r\nIF( CubeExists( '}LocalizedCubeAttributes' ) = 0 );\r\n CubeAttrPutS( '', '}CubeAttributes', 'Caption', 'en');\r\nENDIF;\r\nIF( CubeExists( '}LocalizedDimensionAttributes' ) = 0 );\r\n DimensionAttrPutS( '', '}Cultures', 'Caption', 'en');\r\nENDIF;\r\n\r\n### Localization of attributes (& subsets) for any dimension passed\r\n# Loop through dimensions in pDim \r\nsDims = Trim( pDim );\r\nnDimDelimiterIndex = 1;\r\n# Get 1st dimension\r\nWhile( pDim @<> '' & nDimDelimiterIndex > 0 );\r\n # Extract 1st dimension > sDim\r\n nDimDelimiterIndex = Scan( pDelim, sDims );\r\n If( nDimDelimiterIndex = 0 );\r\n sDim = sDims;\r\n Else;\r\n sDim = Trim( SubSt( sDims, 1, nDimDelimiterIndex - 1 ) );\r\n sDims = Trim( Subst( sDims, nDimDelimiterIndex + Long(pDelim), Long( sDims ) ) );\r\n EndIf;\r\n \r\n # Check if sDim has wildcard\r\n If( Scan( '*', sDim ) = 0);\r\n If( DimensionExists(sDim) = 0 );\r\n nErrors = 1;\r\n sMessage = Expand( 'Dimension \"%sDim%\" does not exist.' );\r\n LogOutput( 'ERROR', Expand( cMsgErrorContent ) );\r\n Else;\r\n sAttrDim = '}ElementAttributes_' | sDim;\r\n sLocAttrDim = '}LocalizedElementAttributes_' | sDim; \r\n sSubDim = '}Subsets_' | sDim;\r\n sSubAttr = '}SubsetAttributes_' | sDim;\r\n sLocSubAttr = '}LocalizedSubsetAttributes_' | sDim;\r\n IF( CubeExists( sAttrDim ) = 0 );\r\n AttrInsert( sDim, '', 'Caption', 'S' );\r\n ELSEIF( DimIx( sAttrDim, 'Caption' ) = 0 );\r\n AttrInsert( sDim, '', 'Caption', 'S' );\r\n ENDIF;\r\n IF( CubeExists( sLocAttrDim ) = 0 );\r\n sFirstEle = '';\r\n sFirstEle = DimNm( sDim, 1 );\r\n IF( sFirstEle @<> '' );\r\n AttrPutS( '', sDim, sFirstEle, 'Caption', 'en' );\r\n ENDIF;\r\n ENDIF;\r\n If( pSub = 1 & DimSiz( sSubDim ) > 0 );\r\n If( CubeExists( sSubAttr ) = 0 );\r\n SubsetAttrInsert( sDim, '', 'Caption', 'S' );\r\n EndIf;\r\n If( CubeExists( sLocSubAttr ) = 0 );\r\n sSub = DimNm( sSubDim, 1 );\r\n If( Scan( ':', sSub ) > 0 );\r\n sDim = sDim |':'| SubSt( sSub, 1, Scan( ':', sSub ) - 1 );\r\n sSub = SubSt( sSub, Scan( ':', sSub ) + 1, Long( sSub ) );\r\n EndIf;\r\n SubsetAttrPutS( '', sDim, sSub, 'Caption', 'en' );\r\n EndIf;\r\n EndIf;\r\n Endif;\r\n Else;\r\n # Create subset of dimensions using Wildcard to loop through dimensions in pDim with wildcard\r\n sMdx = Expand('{TM1FILTERBYPATTERN( EXCEPT ( EXCEPT ( TM1SUBSETALL( [}Dimensions] ) , TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) , \"*:*\") ), TM1FILTERBYPATTERN( TM1SUBSETALL( [}Dimensions] ) , \"}ElementAttributes_*\") ) , \"%sDim%\" )}');\r\n If( SubsetExists( '}Dimensions' , cTempSub ) = 1 );\r\n # If a delimited list of dim names includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( '}Dimensions' , cTempSub, sMDX );\r\n Else;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSub, sMDX, '}Dimensions' , 1 );\r\n EndIf;\r\n \r\n # Loop through dimensions in subset created based on wildcard\r\n nCountDim = SubsetGetSize( '}Dimensions' , cTempSub );\r\n While( nCountDim >= 1 );\r\n sDim = SubsetGetElementName( '}Dimensions' , cTempSub, nCountDim );\r\n If( DimensionExists(sDim) = 0 );\r\n nErrors = 1;\r\n sMessage = Expand( 'Dimension %sDim% does not exist.' );\r\n LogOutput( 'ERROR', Expand( cMsgErrorContent ) );\r\n Else;\r\n sAttrDim = '}ElementAttributes_' | sDim;\r\n sLocAttrDim = '}LocalizedElementAttributes_' | sDim; \r\n sSubDim = '}Subsets_' | sDim;\r\n sSubAttr = '}SubsetAttributes_' | sDim;\r\n sLocSubAttr = '}LocalizedSubsetAttributes_' | sDim;\r\n IF( CubeExists( sAttrDim ) = 0 );\r\n AttrInsert( sDim, '', 'Caption', 'S' );\r\n ELSEIF( DimIx( sAttrDim, 'Caption' ) = 0 );\r\n AttrInsert( sDim, '', 'Caption', 'S' );\r\n ENDIF;\r\n IF( CubeExists( sLocAttrDim ) = 0 );\r\n sFirstEle = '';\r\n sFirstEle = DimNm( sDim, 1 );\r\n IF( sFirstEle @<> '' );\r\n AttrPutS( '', sDim, sFirstEle, 'Caption', 'en' );\r\n ENDIF;\r\n ENDIF;\r\n If( pSub = 1 );\r\n If( CubeExists( sSubAttr ) = 0 );\r\n SubsetAttrInsert( sDim, '', 'Caption', 'S' );\r\n EndIf;\r\n If( CubeExists( sLocSubAttr ) = 0 & DimSiz( sSubDim ) > 0 );\r\n sSub = DimNm( sSubDim, 1 );\r\n If( Scan( ':', sSub ) > 0 );\r\n sDim = sDim |':'| SubSt( sSub, 1, Scan( ':', sSub ) - 1 );\r\n sSub = SubSt( sSub, Scan( ':', sSub ) + 1, Long( sSub ) );\r\n EndIf;\r\n SubsetAttrPutS( '', sDim, sSub, 'Caption', 'en' );\r\n EndIf;\r\n EndIf;\r\n Endif;\r\n nCountDim = nCountDim - 1;\r\n End;\r\n EndIf;\r\nEnd;\r\n\r\n### Localization of views for any cube passed\r\n# Loop through cubes in pCube \r\nsCubes = Trim( pCube );\r\nnCubDelimiterIndex = 1;\r\n# Get 1st Cube\r\nWhile( pCube @<> '' & nCubDelimiterIndex > 0 );\r\n # Extract 1st cube > sCube\r\n nCubDelimiterIndex = Scan( pDelim, sCubes );\r\n If( nCubDelimiterIndex = 0 );\r\n sCube = sCubes;\r\n Else;\r\n sCube = Trim( SubSt( sCubes, 1, nCubDelimiterIndex - 1 ) );\r\n sCubes = Trim( Subst( sCubes, nCubDelimiterIndex + Long(pDelim), Long( sCubes ) ) );\r\n EndIf;\r\n \r\n # Check if sCube has wildcard\r\n If( Scan( '*', sCube ) = 0);\r\n If( CubeExists(sCube) = 0 );\r\n nErrors = 1;\r\n sMessage = Expand( 'Cube \"%sCube%\" does not exist.' );\r\n LogOutput( 'ERROR', Expand( cMsgErrorContent ) );\r\n Else;\r\n sViewDim = '}Views_' | sCube;\r\n sViewAttr = '}ViewAttributes_' | sCube;\r\n sLocViewAttr = '}LocalizedViewAttributes_' | sCube;\r\n IF( CubeExists( sViewAttr ) = 0 & DimensionExists( sViewDim ) = 1 );\r\n ViewAttrInsert( sCube, '', 'Caption', 'S' );\r\n ENDIF;\r\n IF( CubeExists( sLocViewAttr ) = 0 & DimSiz( sViewDim ) >= 1 );\r\n ViewAttrPutS( '', sCube, DimNm( sViewDim, 1 ), 'Caption', 'en' );\r\n ENDIF;\r\n Endif;\r\n Else;\r\n # Create subset of cubes using Wildcard to loop through cubes in pCube with wildcard\r\n sMdx = Expand('{TM1FILTERBYPATTERN( TM1SUBSETALL( [}Cubes] ), \"%sCube%\" )}');\r\n If( SubsetExists( '}Cubes' , cTempSub ) = 1 );\r\n # If a delimited list of Cub names includes wildcards then we may have to re-use the subset multiple times\r\n SubsetMDXSet( '}Cubes' , cTempSub, sMDX );\r\n Else;\r\n # temp subset, therefore no need to destroy in epilog\r\n SubsetCreatebyMDX( cTempSub, sMDX, '}Cubes' , 1 );\r\n EndIf;\r\n \r\n # Loop through cubes in subset created based on wildcard\r\n nCountCub = SubsetGetSize( '}Cubes' , cTempSub );\r\n While( nCountCub >= 1 );\r\n sCube = SubsetGetElementName( '}Cubes' , cTempSub, nCountCub );\r\n If( CubeExists(sCube) = 0 );\r\n nErrors = 1;\r\n sMessage = Expand( 'Cube %sCube% does not exist.' );\r\n LogOutput( 'ERROR', Expand( cMsgErrorContent ) );\r\n Else;\r\n sViewDim = '}Views_' | sCube;\r\n sViewAttr = '}ViewAttributes_' | sCube;\r\n sLocViewAttr = '}LocalizedViewAttributes_' | sCube;\r\n IF( CubeExists( sViewAttr ) = 0 & DimensionExists( sViewDim ) = 1 );\r\n ViewAttrInsert( sCube, '', 'Caption', 'S' );\r\n ENDIF;\r\n IF( CubeExists( sLocViewAttr ) = 0 & DimSiz( sViewDim ) >= 1 );\r\n ViewAttrPutS( '', sCube, DimNm( sViewDim, 1 ), 'Caption', 'en' );\r\n ENDIF;\r\n Endif;\r\n nCountCub = nCountCub - 1;\r\n End;\r\n EndIf;\r\nEnd;\r\n\r\n### End Prolog ###", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% localized cube & dimension names & localized attributes for dimensions %pDim%.' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n### End Epilog ###", @@ -10,41 +10,47 @@ "Type": "None" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pDim", - "Prompt": "OPTIONAL: Dimension (Delimited list & wildcards (*) acceptable)", + "Prompt": "REQUIRED: Delimited list of dimensions", "Value": "", "Type": "String" }, { "Name": "pCube", - "Prompt": "OPTIONAL: Cube( Delimited list & wildcards (*) acceptable)", + "Prompt": "REQUIRED: Cube name", "Value": "", "Type": "String" }, { "Name": "pDelim", - "Prompt": "OPTIONAL: delimiter character for dimension list. (Defaults to & if blank)", + "Prompt": "OPTIONAL: Delimiter for list parameters (Default = '&')", "Value": "&", "Type": "String" }, { "Name": "pSub", - "Prompt": "OPTIONAL: If localizing attributes for a dimension also localize subset names?", + "Prompt": "OPTIONAL: If localizing attributes for a dimension also localize subset names? (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [], diff --git a/bedrock_processes_json/}bedrock.server.logfile.delete.json b/bedrock_processes_json/}bedrock.server.logfile.delete.json index 2884ddc..eebc4d9 100644 --- a/bedrock_processes_json/}bedrock.server.logfile.delete.json +++ b/bedrock_processes_json/}bedrock.server.logfile.delete.json @@ -10,53 +10,59 @@ "Type": "None" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pTgtDir", - "Prompt": "OPTIONAL: Log file directory. (Blank = from TM1 configuration file)", + "Prompt": "OPTIONAL: Target file directory (Default = GetProcessErrorFileDirectory)", "Value": "", "Type": "String" }, { "Name": "pLogDays", - "Prompt": "REQUIRED: The number of days to retain log Files", + "Prompt": "REQUIRED: The number of days to retain log files", "Value": 0, "Type": "Numeric" }, { "Name": "pErrorDays", - "Prompt": "REQUIRED: The number of day to retain TM1 Error Logs", + "Prompt": "REQUIRED: The number of days to retain error files", "Value": 0, "Type": "Numeric" }, { "Name": "pBedrockDays", - "Prompt": "REQUIRED: The number of days to retain Bedrock Debug Files", + "Prompt": "REQUIRED: The number of days to retain bedrock debug files", "Value": 0, "Type": "Numeric" }, { "Name": "pCSVDays", - "Prompt": "REQUIRED: The number of days to retain CSV files", + "Prompt": "REQUIRED: The number of days to retain .csv files", "Value": 0, "Type": "Numeric" }, { "Name": "pFileSize", - "Prompt": "OPTIONAL: The file size of log files (in MB) to exceed before removal (Default=0). Note: for tm1s*.log transaction logs only", + "Prompt": "OPTIONAL: The file size of log files (in MB) to exceed before removal (Default = 0)", "Value": 0, "Type": "Numeric" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [], diff --git a/bedrock_processes_json/}bedrock.server.savedataall.json b/bedrock_processes_json/}bedrock.server.savedataall.json index 69c7d04..2871b11 100644 --- a/bedrock_processes_json/}bedrock.server.savedataall.json +++ b/bedrock_processes_json/}bedrock.server.savedataall.json @@ -12,15 +12,21 @@ "Parameters": [ { "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [], diff --git a/bedrock_processes_json/}bedrock.server.util.string.validate.json b/bedrock_processes_json/}bedrock.server.util.string.validate.json index 53f50ed..f4fc3a9 100644 --- a/bedrock_processes_json/}bedrock.server.util.string.validate.json +++ b/bedrock_processes_json/}bedrock.server.util.string.validate.json @@ -1,27 +1,15 @@ { "Name": "}bedrock.server.util.string.validate", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.server.util.string.validate', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n\t 'pInputString', '', 'pUndesirableFileSystem', '/|\\>\"<:?*', 'pUndesirable1st', Char(39) | '+-[]@!{}%',\r\n\t 'pChanges', '\\,B Slash&/,F Slash&|, &-,Minus&+,Plus&>,greater than&<,less than',\r\n\t 'pReplaceIfNotFound', '_',\r\n\t 'pDelim', '&', 'pSeperator', ',', 'pMode', 3 \r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will validate a string pInputString based on rules in pChanges and change or \r\n# eliminate characters to create a global variable sOutputString that can be used in the source TI.\r\n\r\n# Note:\r\n# - pInputString: This is the input string that needs to be validated based on file system \r\n# limitations or undesirable 1st characters.\r\n\r\n# - pUndesirableFileSystem: These are characters considered undesirable (even forbidden) in \r\n# object/element names due to file system limitations of the operation system. \r\n\r\n# - pUndesirable1st: These are characters considered undesirable as 1st characters in object/element\r\n# names due to TM1 limitations.\r\n\r\n# - pChanges: This string defines the rule of how to change undesirable characters. It can be made up\r\n# of many definitions delimited by pDelim (e.g. `&` which is not considered undesirable\r\n# anywhere). Each definition would contain a character considered undesirable and the desired \r\n# character separatedby pSeperator (e.g. to change a `%` to Percentage and `\"` to inches, it would\r\n# be `%,Percentage&\",inches` if pDelim = `&` and pSeperator = `,`).\r\n\r\n# - pReplaceIfNotFound: This is a catch all for characters listed in pUndesirableFileSystem or \r\n# pUndesirable1st that don't have a rule in pChanges.\r\n\r\n# - pDelim: This is a character that is used to seperate definitions in pChanges.\r\n\r\n# - pSeperator: This is a character used to seperate the current and desired character within each\r\n# definition in pChanges.\r\n\r\n# - pMode: This can be used to limit whether the TI looks at pUndesirableFileSystem or pUndesirable1st \r\n# without having to delete the characters in those parameters.\r\n#EndRegion @DOC\r\n\r\n#Region # Variables & Constants\r\n# Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nStringGlobalVariable('sOutputString');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode = 0;\r\n\r\n# Constants \r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncSubset = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent= '%cThisProcName% : %sMessage% : %cUserName%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pLogOutput=%pLogOutput%, pInputString=%pInputString%, pUndesirableFileSystem=%pUndesirableFileSystem%, pUndesirable1st=%pUndesirable1st%, pChanges=%pChanges%, pReplaceIfNotFound=%pReplaceIfNotFound%, pDelim=%pDelim%, pSeperator=%pSeperator%, pMode=%pMode%';\r\n\r\n# Variables\r\nnErrors = 0;\r\n#EndRegion\r\n\r\n#Region # LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) );\r\nENDIF;\r\n#EndRegion\r\n\r\n#Region # Validate parameters\r\n## Validate pInputString parameter\r\nIF( Trim( pInputString ) @= '' );\r\n nErrors =1;\r\n sMessage = Expand('No element name specified in pInputString.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nELSE;\r\n sElementToUpdate = Trim( pInputString ) ;\r\nENDIF;\r\n\r\n## Validate pMode parameter\r\nIF( pMode <>1 & pMode <>2 & pMode <>3 );\r\n nErrors =1;\r\n sMessage = Expand('pMode parameter must be 1, 2 or 3 not %pMode%.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nENDIF;\r\n\r\n## Validate pDelim parameter\r\nIF( Trim( pChanges ) @<> '' );\r\nIF( Trim( pDelim ) @= '' );\r\n nErrors = 1;\r\n sMessage = Expand('No delimiter specified in pDelim.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nELSE;\r\n sDelim = SUBST( Trim( pDelim ) , 1 , 1 );\r\nENDIF;\r\nENDIF;\r\n\r\n## Validate pSeperator parameter\r\nIF( Trim( pChanges ) @<> '' );\r\nIF( Trim( pSeperator ) @= '' );\r\n nErrors = 1;\r\n sMessage = Expand('No seperator specified in pSeperator.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nELSE;\r\n sSeperator = SUBST( Trim( pSeperator ) , 1 , 1 );\r\nENDIF;\r\nENDIF;\r\n\r\n## Validate pChanges parameter\r\n#pChanges = Trim( pChanges );\r\nIF( pChanges @= '' );\r\n \r\nELSEIF( SUBST( pChanges , LONG( pChanges ) , 1 )@<> sDelim );\r\n pChanges = pChanges | sDelim ;\r\nENDIF;\r\n\r\n#pChanges = Trim( pChanges );\r\nIF( pReplaceIfNotFound @= '' );\r\n sReplaceIfNotFound = '';\r\nELSE;\r\n sReplaceIfNotFound = Trim( pReplaceIfNotFound );\r\nENDIF;\r\n\r\n##### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n#EndRegion \r\n\r\n#Region # Prepare for While loop to validate each character seperately\r\nsEle = TRIM( pInputString );\r\nnEle = LONG( sEle );\r\nsOutputString = '';\r\nnCount = 1;\r\n# Loop through each character to see if valid\r\n# If no script inlcuded in pChanges then the invalid character will be replaced with pReplaceIfNotFound\r\nWHILE( nCount <= nEle );\r\n sChar = SUBST( sEle , nCount , 1 );\r\n sChanges = TRIM( pChanges );\r\n nUndesirableFileSystem = SCAN( sChar , pUndesirableFileSystem );\r\n nUndesirable1st = SCAN( sChar , pUndesirable1st );\r\n ## Test if sChar contains undesirable \r\n IF( nUndesirableFileSystem >0 & ( pMode=1 % pMode=3) );\r\n ## Test if sChar in pChanges\r\n nChange = SCAN( sChar , sChanges );\r\n IF( nChange >0 );\r\n sChanges = SUBST( sChanges , nChange , 999 );\r\n nNewLong = SCAN( sDelim , sChanges ); \r\n sNew = SUBST( sChanges , 3 , nNewLong-3 );\r\n #sOutputString = sOutputString | sNew ;\r\n ELSE;\r\n sNew = sReplaceIfNotFound ;\r\n ENDIF; \r\n ELSEIF( nUndesirable1st >0 & nCount=1 & ( pMode=2 % pMode=3) );\r\n ## Test if sChar in pChanges\r\n nChange = SCAN( sChar , sChanges );\r\n IF( nChange >0 );\r\n sChanges = SUBST( sChanges , nChange , 999 );\r\n nNewLong = SCAN( sDelim , sChanges ); \r\n sNew = SUBST( sChanges , 3 , nNewLong-3 );\r\n #sOutputString = sOutputString | sNew ;\r\n ELSE;\r\n sNew = pReplaceIfNotFound ;\r\n ENDIF; \r\n ELSE;\r\n sNew = sChar;\r\n ENDIF;\r\n sOutputString = sOutputString | sNew ;\r\n # Loop through the rest of the characters\r\n nCount = nCount + 1 ;\r\nEND;", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.server.util.string.validate', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n\t 'pInputString', '', 'pUndesirableFileSystem', '/|\\>\"<:?*', 'pUndesirable1st', Char(39) | '+-[]@!{}%',\r\n\t 'pChanges', '\\,B Slash&/,F Slash&|, &-,Minus&+,Plus&>,greater than&<,less than',\r\n\t 'pReplaceIfNotFound', '_',\r\n\t 'pDelim', '&', 'pSeperator', ',', 'pMode', 3 \r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will validate a string pInputString based on rules in pChanges and change or \r\n# eliminate characters to create a global variable sOutputString that can be used in the source TI.\r\n\r\n# Note:\r\n# - pInputString: This is the input string that needs to be validated based on file system \r\n# limitations or undesirable 1st characters.\r\n\r\n# - pUndesirableFileSystem: These are characters considered undesirable (even forbidden) in \r\n# object/element names due to file system limitations of the operation system. \r\n\r\n# - pUndesirable1st: These are characters considered undesirable as 1st characters in object/element\r\n# names due to TM1 limitations.\r\n\r\n# - pChanges: This string defines the rule of how to change undesirable characters. It can be made up\r\n# of many definitions delimited by pDelim (e.g. `&` which is not considered undesirable\r\n# anywhere). Each definition would contain a character considered undesirable and the desired \r\n# character separatedby pSeperator (e.g. to change a `%` to Percentage and `\"` to inches, it would\r\n# be `%,Percentage&\",inches` if pDelim = `&` and pSeperator = `,`).\r\n\r\n# - pReplaceIfNotFound: This is a catch all for characters listed in pUndesirableFileSystem or \r\n# pUndesirable1st that don't have a rule in pChanges.\r\n\r\n# - pDelim: This is a character that is used to seperate definitions in pChanges.\r\n\r\n# - pSeperator: This is a character used to seperate the current and desired character within each\r\n# definition in pChanges.\r\n\r\n# - pMode: This can be used to limit whether the TI looks at pUndesirableFileSystem or pUndesirable1st \r\n# without having to delete the characters in those parameters.\r\n#EndRegion @DOC\r\n\r\n#Region # Variables & Constants\r\n# Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nStringGlobalVariable('sOutputString');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode = 0;\r\n\r\n# Constants \r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncTimeStamp = TimSt( Now, '\\Y\\m\\d\\h\\i\\s' );\r\ncRandomInt = NumberToString( INT( RAND( ) * 1000 ));\r\ncSubset = cThisProcName |'_'| cTimeStamp |'_'| cRandomInt;\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent= '%cThisProcName% : %sMessage% : %cUserName%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pLogOutput=%pLogOutput%, pInputString=%pInputString%, pUndesirableFileSystem=%pUndesirableFileSystem%, pUndesirable1st=%pUndesirable1st%, pChanges=%pChanges%, pReplaceIfNotFound=%pReplaceIfNotFound%, pDelim=%pDelim%, pSeperator=%pSeperator%, pMode=%pMode%';\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pChanges\": \"''+-[]@!{}% \",\r\n \"pDelim\": \"&\",\r\n \"pInputString\": null,\r\n \"pReplaceIfNotFound\": \"_\",\r\n \"pSeperator\": \",\",\r\n \"pUndesirable1st\": \"''+-[]@!{}% \",\r\n \"pUndesirableFileSystem\": \" /|\\\\>\"<:?*\",\r\n \"pLogOutput\": 0,\r\n \"pMode\": null,\r\n \"pStrictErrorHandling\": 0\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pChanges\": '|StringToJson ( pChanges )|',\r\n \"pDelim\": '|StringToJson ( pDelim )|',\r\n \"pInputString\": '|StringToJson ( pInputString )|',\r\n \"pReplaceIfNotFound\": '|StringToJson ( pReplaceIfNotFound )|',\r\n \"pSeperator\": '|StringToJson ( pSeperator )|',\r\n \"pUndesirable1st\": '|StringToJson ( pUndesirable1st )|',\r\n \"pUndesirableFileSystem\": '|StringToJson ( pUndesirableFileSystem )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pMode\": '|NumberToString( pMode )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npChanges = JsonToString( JsonGet( pJson, 'pChanges' ) );\r\npDelim = JsonToString( JsonGet( pJson, 'pDelim' ) );\r\npInputString = JsonToString( JsonGet( pJson, 'pInputString' ) );\r\npReplaceIfNotFound = JsonToString( JsonGet( pJson, 'pReplaceIfNotFound' ) );\r\npSeperator = JsonToString( JsonGet( pJson, 'pSeperator' ) );\r\npUndesirable1st = JsonToString( JsonGet( pJson, 'pUndesirable1st' ) );\r\npUndesirableFileSystem = JsonToString( JsonGet( pJson, 'pUndesirableFileSystem' ) );\r\n# Numeric Parameters\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npMode = StringToNumber( JsonToString( JsonGet( pJson, 'pMode' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n# Variables\r\nnErrors = 0;\r\n#EndRegion\r\n\r\n#Region # LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) );\r\nENDIF;\r\n#EndRegion\r\n\r\n#Region # Validate parameters\r\n## Validate pInputString parameter\r\nIF( Trim( pInputString ) @= '' );\r\n nErrors =1;\r\n sMessage = Expand('No element name specified in pInputString.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nELSE;\r\n sElementToUpdate = Trim( pInputString ) ;\r\nENDIF;\r\n\r\n## Validate pMode parameter\r\nIF( pMode <>1 & pMode <>2 & pMode <>3 );\r\n nErrors =1;\r\n sMessage = Expand('pMode parameter must be 1, 2 or 3 not %pMode%.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nENDIF;\r\n\r\n## Validate pDelim parameter\r\nIF( Trim( pChanges ) @<> '' );\r\nIF( Trim( pDelim ) @= '' );\r\n nErrors = 1;\r\n sMessage = Expand('No delimiter specified in pDelim.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nELSE;\r\n sDelim = SUBST( Trim( pDelim ) , 1 , 1 );\r\nENDIF;\r\nENDIF;\r\n\r\n## Validate pSeperator parameter\r\nIF( Trim( pChanges ) @<> '' );\r\nIF( Trim( pSeperator ) @= '' );\r\n nErrors = 1;\r\n sMessage = Expand('No seperator specified in pSeperator.');\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nELSE;\r\n sSeperator = SUBST( Trim( pSeperator ) , 1 , 1 );\r\nENDIF;\r\nENDIF;\r\n\r\n## Validate pChanges parameter\r\n#pChanges = Trim( pChanges );\r\nIF( pChanges @= '' );\r\n \r\nELSEIF( SUBST( pChanges , LONG( pChanges ) , 1 )@<> sDelim );\r\n pChanges = pChanges | sDelim ;\r\nENDIF;\r\n\r\n#pChanges = Trim( pChanges );\r\nIF( pReplaceIfNotFound @= '' );\r\n sReplaceIfNotFound = '';\r\nELSE;\r\n sReplaceIfNotFound = Trim( pReplaceIfNotFound );\r\nENDIF;\r\n\r\n##### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n#EndRegion \r\n\r\n#Region # Prepare for While loop to validate each character seperately\r\nsEle = TRIM( pInputString );\r\nnEle = LONG( sEle );\r\nsOutputString = '';\r\nnCount = 1;\r\n# Loop through each character to see if valid\r\n# If no script inlcuded in pChanges then the invalid character will be replaced with pReplaceIfNotFound\r\nWHILE( nCount <= nEle );\r\n sChar = SUBST( sEle , nCount , 1 );\r\n sChanges = TRIM( pChanges );\r\n nUndesirableFileSystem = SCAN( sChar , pUndesirableFileSystem );\r\n nUndesirable1st = SCAN( sChar , pUndesirable1st );\r\n ## Test if sChar contains undesirable \r\n IF( nUndesirableFileSystem >0 & ( pMode=1 % pMode=3) );\r\n ## Test if sChar in pChanges\r\n nChange = SCAN( sChar , sChanges );\r\n IF( nChange >0 );\r\n sChanges = SUBST( sChanges , nChange , 999 );\r\n nNewLong = SCAN( sDelim , sChanges ); \r\n sNew = SUBST( sChanges , 3 , nNewLong-3 );\r\n #sOutputString = sOutputString | sNew ;\r\n ELSE;\r\n sNew = sReplaceIfNotFound ;\r\n ENDIF; \r\n ELSEIF( nUndesirable1st >0 & nCount=1 & ( pMode=2 % pMode=3) );\r\n ## Test if sChar in pChanges\r\n nChange = SCAN( sChar , sChanges );\r\n IF( nChange >0 );\r\n sChanges = SUBST( sChanges , nChange , 999 );\r\n nNewLong = SCAN( sDelim , sChanges ); \r\n sNew = SUBST( sChanges , 3 , nNewLong-3 );\r\n #sOutputString = sOutputString | sNew ;\r\n ELSE;\r\n sNew = pReplaceIfNotFound ;\r\n ENDIF; \r\n ELSE;\r\n sNew = sChar;\r\n ENDIF;\r\n sOutputString = sOutputString | sNew ;\r\n # Loop through the rest of the characters\r\n nCount = nCount + 1 ;\r\nEND;", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock Ver 4.0.0~~##\r\n################################################################################################# \r\n\r\nIF( nCount <> 1000000 );\r\n #AttrPutS( NumberToString( StringToNumber( sUpdatesNew ) ) , sDim2 , sUpdatesNew , 'Number');\r\nENDIF;\r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% has validated the string the element \"%pInputString%\" and returned \"%sOutputString%\".' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n### End Epilog ###", "HasSecurityAccess": true, - "UIData": "_ParameterConstraints=e30=\f", + "UIData": "", "DataSource": { "Type": "None" }, "Parameters": [ - { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", - "Value": 1, - "Type": "Numeric" - }, - { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", - "Value": 0, - "Type": "Numeric" - }, { "Name": "pInputString", "Prompt": "REQUIRED: Element name to validate and update if necessary", @@ -30,45 +18,63 @@ }, { "Name": "pUndesirableFileSystem", - "Prompt": "OPTIONAL: Undesirable characters for file system (e.g. /|\\>\"<:?* )", - "Value": "/|\\>\"<:?*", + "Prompt": "OPTIONAL: Undesirable characters for file system (Default = ' /|\\\\>\"<:?*')", + "Value": " /|\\\\>\"<:?*", "Type": "String" }, { "Name": "pUndesirable1st", - "Prompt": "OPTIONAL: Undesirable 1st characters (e.g. '+-[]@!{}% )", - "Value": "'+-[]@!{}%", + "Prompt": "OPTIONAL: Undesirable 1st characters (Default = ''+-[]@!{}% ')", + "Value": "'+-[]@!{}% ", "Type": "String" }, { "Name": "pChanges", - "Prompt": "OPTIONAL: String showing what to change. Replaces with pReplaceIfNotFound if blank.", - "Value": "\\,B Slash&/,F Slash&|, &-,Minus&+,Plus&>,greater than&<,less than", + "Prompt": "OPTIONAL: String showing what to change (Default = pReplaceIfNotFound)", + "Value": "'+-[]@!{}% ", "Type": "String" }, { "Name": "pReplaceIfNotFound", - "Prompt": "OPTIONAL: Replace ndesirable character with this if not specified in pChanges above (blank will delete)", + "Prompt": "OPTIONAL: Replace undesirable characters with this if not specified in pChanges (Default = '_')", "Value": "_", "Type": "String" }, { "Name": "pDelim", - "Prompt": "REQUIRED: Delimiter between definitions", + "Prompt": "OPTIONAL: Delimiter for list parameters (Default = '&')", "Value": "&", "Type": "String" }, { "Name": "pSeperator", - "Prompt": "REQUIRED: Seperator between current & desired", + "Prompt": "OPTIONAL: Seperator between current & desired (Default = ',')", "Value": ",", "Type": "String" }, { "Name": "pMode", - "Prompt": "REQUIRED: 1=Validate for File System only, 2=Validate for 1st only, 3=Validate Fully", + "Prompt": "REQUIRED: 1=Validate for File System only, 2=Validate for 1st only, 3=Validate Fully (Default = 3)", "Value": 3, "Type": "Numeric" + }, + { + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", + "Value": 0, + "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [], diff --git a/bedrock_processes_json/}bedrock.server.wait.json b/bedrock_processes_json/}bedrock.server.wait.json index 0a6ac82..4e01435 100644 --- a/bedrock_processes_json/}bedrock.server.wait.json +++ b/bedrock_processes_json/}bedrock.server.wait.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.server.wait", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.server.wait', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n\t 'pWaitSec', 0\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This Bedrock TM1 TI will put a process in a wait state for time specified in seconds.\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\nsWaitSec = NumberToString( pWaitSec );\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pWaitSec:%sWaitSec%.'; \r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\nnErrors = 0;\r\n\r\n### SLEEP ##\r\nnWaitTime = pWaitSec * 1000;\r\nSleep ( nWaitTime );", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.server.wait', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n\t 'pWaitSec', 0\r\n\t);\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This Bedrock TM1 TI will put a process in a wait state for time specified in seconds.\r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\nsWaitSec = NumberToString( pWaitSec );\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pWaitSec:%sWaitSec%.';\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pLogOutput\": 0,\r\n \"pStrictErrorHandling\": 0,\r\n \"pWaitSec\": null\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|',\r\n \"pWaitSec\": '|NumberToString( pWaitSec )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\n\r\n# Numeric Parameters\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\npWaitSec = StringToNumber( JsonToString( JsonGet( pJson, 'pWaitSec' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\nnErrors = 0;\r\n\r\n### SLEEP ##\r\nnWaitTime = pWaitSec * 1000;\r\nSleep ( nWaitTime );", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully waited for %sWaitSec% .' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n### End Epilog ###", @@ -11,22 +11,28 @@ }, "Parameters": [ { - "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", + "Name": "pWaitSec", + "Prompt": "REQUIRED: Wait time in seconds", "Value": 0, "Type": "Numeric" }, { - "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", + "Name": "pLogOutput", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { - "Name": "pWaitSec", - "Prompt": "REQUIRED: Wait time in seconds", + "Name": "pStrictErrorHandling", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" + }, + { + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", + "Type": "String" } ], "Variables": [], diff --git a/bedrock_processes_json/}bedrock.server.writetomessagelog.json b/bedrock_processes_json/}bedrock.server.writetomessagelog.json index fcb0ca6..9643b6c 100644 --- a/bedrock_processes_json/}bedrock.server.writetomessagelog.json +++ b/bedrock_processes_json/}bedrock.server.writetomessagelog.json @@ -1,6 +1,6 @@ { "Name": "}bedrock.server.writetomessagelog", - "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.server.writetomessagelog', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pLevel', '', 'pMessage', ''\r\n );\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will write a Message into the TM1 server Message Log. \r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pLevel:%pLevel%, pMessage:%pMessage%.' ; \r\ncLF = Char ( 10 );\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\nsErrors = '';\r\n\r\n# ValidateType\r\nsType = Upper ( pLevel );\r\nIf( sType @<> 'ERROR' & sType @<> 'WARN' & sType @<> 'DEBUG' & sType @<> 'INFO' );\r\n nErrors = nErrors + 1;\r\n sMessage = 'Invalid Type: ' | pLevel | cLF;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\nIf( Long ( pMessage ) = 0 );\r\n nErrors = nErrors + 1;\r\n sMessage = sErrors | 'pMessage can not be empty.' | cLF;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### Action ###\r\nLogOutput ( sType , pMessage );\r\n", + "PrologProcedure": "#Region CallThisProcess\r\n# A snippet of code provided as an example how to call this process should the developer be working on a system without access to an editor with auto-complete.\r\nIf( 1 = 0 );\r\n ExecuteProcess( '}bedrock.server.writetomessagelog', 'pLogOutput', pLogOutput,\r\n 'pStrictErrorHandling', pStrictErrorHandling,\r\n \t'pLevel', '', 'pMessage', ''\r\n );\r\nEndIf;\r\n#EndRegion CallThisProcess\r\n\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n#Region @DOC\r\n# Description:\r\n# This process will write a Message into the TM1 server Message Log. \r\n#EndRegion @DOC\r\n\r\n### Global Variables\r\nStringGlobalVariable('sProcessReturnCode');\r\nNumericGlobalVariable('nProcessReturnCode');\r\nnProcessReturnCode= 0;\r\n\r\n### Constants ###\r\ncThisProcName = GetProcessName();\r\ncUserName = TM1User();\r\ncMsgErrorLevel = 'ERROR';\r\ncMsgErrorContent = 'User:%cUserName% Process:%cThisProcName% ErrorMsg:%sMessage%';\r\ncLogInfo = 'Process:%cThisProcName% run with parameters pLevel:%pLevel%, pMessage:%pMessage%.' ; \r\ncLF = Char ( 10 );\r\n\r\n#################################################################################################\r\n#Region - Process Parameters\r\n\r\npJson = IF( JsonType( pJson ) @<> 'object', '{}', pJson );\r\nsMessages = '{\"Process\": \"'|GetProcessName()|'\", \"User\": \"'|TM1User()|'\", \"Info\": [\"Process: '''|GetProcessName()|''' run by User: '''|TM1User()|'''.\"], \"Error\": []}';\r\npDefaultParameters = '{\r\n \"pLevel\": \",\",\r\n \"pMessage\": null,\r\n \"pLogOutput\": 0,\r\n \"pStrictErrorHandling\": 0\r\n}';\r\n\r\npPassedParameters = '{\r\n \"pLevel\": '|StringToJson ( pLevel )|',\r\n \"pMessage\": '|StringToJson ( pMessage )|',\r\n \"pLogOutput\": '|NumberToString( pLogOutput )|',\r\n \"pStrictErrorHandling\": '|NumberToString( pStrictErrorHandling )|'\r\n}';\r\n\r\npJson = JsonMergePatch( pPassedParameters, pJson );\r\n# String Parameters\r\npLevel = JsonToString( JsonGet( pJson, 'pLevel' ) );\r\npMessage = JsonToString( JsonGet( pJson, 'pMessage' ) );\r\n# Numeric Parameters\r\npLogOutput = StringToNumber( JsonToString( JsonGet( pJson, 'pLogOutput' ) ) );\r\npStrictErrorHandling = StringToNumber( JsonToString( JsonGet( pJson, 'pStrictErrorHandling' ) ) );\r\n\r\n### Get the parameters that differ from the default\r\npDiffer = JsonDiff( pDefaultParameters, pJson );\r\nnSize = JsonSize( pDiffer );\r\nWHILE( nSize > 0 );\r\n nSize = nSize - 1;\r\n pDiffer = JsonReplace( pDiffer, '/'|NumberToString( nSize )|'/op', '\"add\"' );\r\nEND;\r\npJson = JsonPatch( '{}', pDiffer );\r\n\r\n### LogOutput parameters\r\nsMessages = JsonAdd( sMessages, '/Info/-', pJson );\r\nIF( pLogOutput = 1 );\r\n LogOutput('INFO', JsonToString( sMessages, '/Info/0', 0, ' ' ) );\r\nENDIF;\r\n\r\n#EndRegion - Process Parameters\r\n#################################################################################################\r\n\r\n## LogOutput parameters\r\nIF( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( cLogInfo ) ); \r\nENDIF;\r\n\r\n### Validate Parameters ###\r\nnErrors = 0;\r\nsErrors = '';\r\n\r\n# ValidateType\r\nsType = Upper ( pLevel );\r\nIf( sType @<> 'ERROR' & sType @<> 'WARN' & sType @<> 'DEBUG' & sType @<> 'INFO' );\r\n nErrors = nErrors + 1;\r\n sMessage = 'Invalid Type: ' | pLevel | cLF;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\nIf( Long ( pMessage ) = 0 );\r\n nErrors = nErrors + 1;\r\n sMessage = sErrors | 'pMessage can not be empty.' | cLF;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\nEndIf;\r\n\r\n### Check for errors before continuing\r\nIf( nErrors <> 0 );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n Else;\r\n ProcessBreak;\r\n EndIf;\r\nEndIf;\r\n\r\n### Action ###\r\nLogOutput ( sType , pMessage );\r\n", "MetadataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****", "DataProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n", "EpilogProcedure": "\r\n#****Begin: Generated Statements***\r\n#****End: Generated Statements****\r\n\r\n################################################################################################# \r\n##~~Join the bedrock TM1 community on GitHub https://github.com/cubewise-code/bedrock-5 Ver 5.0~~##\r\n################################################################################################# \r\n\r\n### Return code & final error message handling\r\nIf( nErrors > 0 );\r\n sMessage = 'the process incurred at least 1 error. Please see above lines in this file for more details.';\r\n nProcessReturnCode = 0;\r\n LogOutput( cMsgErrorLevel, Expand( cMsgErrorContent ) );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% Process:%cThisProcName% completed with errors. Check tm1server.log for details.' );\r\n If( pStrictErrorHandling = 1 ); \r\n ProcessQuit; \r\n EndIf;\r\nElse;\r\n sProcessAction = Expand( 'Process:%cThisProcName% successfully wrote message type %pLevel% with message %pMessage%.' );\r\n sProcessReturnCode = Expand( '%sProcessReturnCode% %sProcessAction%' );\r\n nProcessReturnCode = 1;\r\n If( pLogoutput = 1 );\r\n LogOutput('INFO', Expand( sProcessAction ) ); \r\n EndIf;\r\nEndIf;\r\n\r\n### End Epilog ###\r\n", @@ -10,28 +10,34 @@ "Type": "None" }, "Parameters": [ + { + "Name": "pLevel", + "Prompt": "OPTIONAL: REQUIRED: Severity of the message ('INFO', 'DEBUG', 'ERROR')", + "Value": ",", + "Type": "String" + }, + { + "Name": "pMessage", + "Prompt": "REQUIRED: Message to display in TM1 Server Message Log", + "Value": "", + "Type": "String" + }, { "Name": "pLogOutput", - "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean True = 1)", + "Prompt": "OPTIONAL: Write parameters and action summary to server message log (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { "Name": "pStrictErrorHandling", - "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean True = 1)", + "Prompt": "OPTIONAL: On encountering any error, exit with major error status by ProcessQuit after writing to the server message log (Boolean. Default = 0)", "Value": 0, "Type": "Numeric" }, { - "Name": "pLevel", - "Prompt": "REQUIRED: Severity of the message - INFO, DEBUG or ERROR", - "Value": "", - "Type": "String" - }, - { - "Name": "pMessage", - "Prompt": "REQUIRED: Message to display in TM1 server Message Log", - "Value": "", + "Name": "pJson", + "Prompt": "OPTIONAL: JSON Object with process parameter values. This will overwrite user passed parameters for all included parameters.", + "Value": "{}", "Type": "String" } ],