Navigation on a child of a MDX+ Category hierarchy does not seem to work - iccube

the issue
When I define navigation on a child of a Category member I get the following MDX error when I click on a member:
[Stats].[Top X].[Total].[subtotal].[<child of subtotal category]' is not a known MDX entity
this is the set-up
I have simplified the MDX and transferred it to run on the default Sales cube:
set [level] as [Customers].[Geography].[City]
set [selection] as
filter([level],mid([level].currentmember.name,1,1) = 'A')
+ filter([level],mid([level].currentmember.name,1,1) = 'B')
+ filter([level],mid([level].currentmember.name,1,1) = 'C')
/* MDX + function to create a dynamic hierarchy */
CATEGORY HIERARCHY [Stats].[ABC], DEFAULT_MEMBER_NAME = "Total",LEVEL_NAME_PATTERN="L - TOP X - ${levelDepth}"
CATEGORY MEMBER [Stats].[ABC].[Total].[subtotal] as [selection] , ADD_CHILDREN=true
CATEGORY MEMBER [Stats].[ABC].[Total].[remainder] as except([level],[selection]),ADD_CHILDREN=false
SELECT
{[Measures].[amount]} on 0,
{[Stats].[ABC].[total].[subtotal].children
,[Stats].[ABC].[total].[subtotal]
,[Stats].[ABC].[total].[remainder]
,[Stats].[ABC].[total]} on 1
FROM [sales]
In the table widget, I have defined the navigation as:
click behavior: Drilldown
Drilldown Strategy: mdxExpression
Drilldown axis: Rows
MDX Expression:
when $member.name = 'subtotal' then ic3drilldownStop()
when $member.name = 'total' then ic3drilldownStop()
when $member.level is [Time].[Calendar].[Month] then ic3drilldownStop()
else nonempty([Time].[Calendar].[Month],[measures].[amount])
end
Result is
Now clicking on, for example, Bogota gives:
Error:
[Stats].[Top X].[Total].[subtotal].[Bogotá]' is not a known MDX entity
the question
How to solve this error?

The issue is because you're trying to use a category member defined in the SELECT statement itself. As a workaround you could modify your drilldown MDX expression as following:
non empty
case
when $member.name = 'subtotal' then ic3drilldownStop()
when $member.name = 'total' then ic3drilldownStop()
when $member.level is [Time].[Calendar].[Month] then ic3drilldownStop()
else nonempty([Time].[Calendar].[Month],[measures].[amount])
end
axis 0 ([Measures].[Amount], $member)
As you can see the expression is not only redefining the axis 1 but the axis 0 as well to mimic the "Filter by" option (i.e., filtering by the Bogota member in your example).

Related

How to use MDX constants/functions in icCube Reporting?

I have several functions/constants defined in the schema. An example is:
_latestPeriodWithData() which returns a date.
Goal: I want to use this value in the Reporting to set a Guide in a chart, using the demo example 'On Widget Options':
This is what I tried so far:
I have assigned this function as 'MDX / Value' for a Report Constant _lastDate and obtained the value for this constant using the java script function: context.eventValue('_lastDate'); but that just gives me the caption. The function context.eventObject("_lastDate").options.asMdx gives me _latestPeriodWithData(), but not its value.
On Widget Options
/**
* Result will be used while rendering.
*/
function(context, options, $box) {
// for debugging purpose
console.log(context.eventObject("_lastDate").options.asMdx);
options.guides[0].value = context.eventObject("_lastDate").options.asMdx; // <-- gives me _latestPeriodeWith data
// but not its value
options.guides[0].toValue = context.eventObject("_lastDate").options.asMdx;
options.guides[0].lineAlpha = 1;
options.guides[0].lineColor = "#c44";
return options;
}

X++ assign Enum Value to a table column

I am trying to pull the Enum chosen from a dialog and assign the label to a table's column.
For example: Dialog opens and allows you to choose from:
Surface
OutOfSpec
Other
These are 0,1,2 respectively.
The user chooses OutOfSpec (the label for this is Out Of Spec), I want to put this enum's Name, or the label, into a table. The column I'm inserting into is set to be a str.
Here's the code I've tried, without success:
SysDictEnum dictEnum = new SysDictEnum(enumNum(SDILF_ScrapReasons));
reason = dialog.addField(enumStr(SDILF_ScrapReasons),"Scrap Reason");
dialog.run();
if (!dialog.closedOk())
{
info(reason.value());
return;
}
ttsBegin;
// For now, this will strip off the order ID from the summary fields.
// No longer removing the Order ID
batchAttr = PdsBatchAttributes::find(itemId, invDim.inventBatchId, "OrderId");
orders = SDILF_BreakdownOrders::find(batchAttr.PdsBatchAttribValue, true);
if (orders)
{
orders.BoxProduced -= 1;
orders.update();
}
// Adding a batch attribute that will include the reason for scrapping
select forUpdate batchAttr;
batchAttr.PdsBatchAttribId = "ScrapReason";
//batchAttr.PdsBatchAttribValue = any2str(dictEnum.index2Value(reason.value()));
batchAttr.PdsBatchAttribValue = enum2str(reason.value());
batchAttr.InventBatchId = invDim.inventBatchId;
batchAttr.ItemId = itemId;
batchAttr.insert();
Obviously this is not the whole code, but it should be enough to give the issue that I'm trying to solve.
I'm sure there is a way to get the int value and use that to assign the label, I've just not been able to figure it out yet.
EDIT
To add some more information about what I am trying to accomplish. We make our finished goods, sometimes they are out of spec or damaged when this happens we then have to scrap that finished good. When we do this we want to keep track of why it is being scrapped, but we don't want just a bunch of random reasons. I used an enum to limit the reasons. When the operator clicks the button to scrap something they will get a dialog screen pop-up that allows them to select a reason for scrapping. The code will then, eventually, put that assigned reason on that finished items batch attributes so that we can track it later in a report and have a list of all the finished goods that were scrapped and why they were scrapped.
I'm not entirely sure of your question, but I think you're just missing one of the index2[...] calls or you're not getting the return value from your dialog correctly. Just create the below as a new job, run it, make a selection of Open Order and click ok.
I don't know the difference between index2Label and index2Name.
static void Job67(Args _args)
{
Dialog dialog = new dialog();
SysDictEnum dictEnum = new SysDictEnum(enumNum(SalesStatus));
DialogField reason;
SalesStatus salesStatusUserSelection;
str label, name, symbol;
int value;
reason = dialog.addField(enumStr(SalesStatus), "SalesStatus");
dialog.run();
if (dialog.closedOk())
{
salesStatusUserSelection = reason.value();
// Label
label = dictEnum.index2Label(salesStatusUserSelection);
// Name
name = dictEnum.index2Name(salesStatusUserSelection);
// Symbol
symbol = dictEnum.index2Symbol(salesStatusUserSelection);
// Value
value = dictEnum.index2Value(salesStatusUserSelection);
info(strFmt("Label: %1; Name: %2; Symbol: %3; Value: %4", label, name, symbol, value));
}
}

How to get total number of rows in a drupal view alter hook?

I've to avoid duplicate search result in a view, so what I am trying to alter the view using pre render hook. and removing the duplicates it's working fine but the problem is in the count of result. it shows the count from the query executed and this include the duplicated item too. also, I enabled the pagination with limit of 5 in a page. then the count seems to be strange it's taking the count of the elements showing in each page
function search_helper_views_pre_render(\Drupal\views\ViewExecutable $view) {
if ($view->id() == "all_news" || $view->id() == "all_publications" || $view->id() == "all_events" || $view->id() == "global_search") {
$unique_nids = $d_nids = $new_results = array();
// Loop through results and filter out duplicate results.
foreach($view->result as $key => $result) {
if(!in_array($result->nid, $unique_nids)) {
$unique_nids[] = $result->nid;
}
else {
unset($view->result[$key]);
}
}
$view->total_rows = count($view->result);
//$view->pager->total_items = count($view->result);
$view->pager->updatePageInfo();
}
}
the expected output of the $view->total_rows must be the total count of result instead of count of elements shown in the page.
You totaly done it in wrong way. as you see ( and it's clear from its name ), it's hook__views_pre_render it runs before the rendering. So its really hard to manipulate the views results and counter, pagination there.
As I see in your query you just remove duplicate Nids , so you can easily do it by Distinct drupal views feature.
Under Advanced, query settings, click on settings.
You will get this popup, now checkmark Distinct
Could do
$difference = count($view->result) - count($new_result);
$view->total_rows = $view->total_rows - $difference;
BTW Distinct setting doesn't always work, see https://www.drupal.org/project/drupal/issues/2993688

One item per line (row) in timeline? - Vis.js

Is there a way to always have one item per line in the timeline? I don't want two or more items to share the same line, whatever the dates are.
Thanks.
You have to use groups, or if you're already using those for another purpose, you have to use subgroups.
Here's the official documentation for items, groups and subgroups (I'm assuming the website isn't gonna expire anytime soon... again...).
If you can use groups
Specify a different group for every item. You can set the group's content as an empty string, if you don't want to have a label for it on the left side of the Timeline.
If you want to arrange the groups in a specific way, specify an ordering function as the Timeline's options' groupOrder property. Example:
var options = {
// other properties...
groupOrder: function (a, b) {
if(a.content > b.content)// alphabetic order
return 1;
else if(a.content < b.content)
return -1;
return 0;
}
};
If you have to use subgroups
When you create an item, put it in the group it belongs to but also specify for it the subgroup property so that it's unique, like the item's id. For example, you can use the id itself, or add a prefix or suffix to it.
In the Timeline's options, set the stack and stackSubgroups properties to true.
In each group, set the subgroupStack property to true and specify an ordering function as the group's subgroupOrder property. Example:
var group = {
id: 1,
content: 'example group',
subgroupStack: true,
subgroupOrder: function(a, b) {
var tmp = a.start.getTime() - b.start.getTime();
return tmp === 0 ? parseInt(a.id) - parseInt(b.id) : tmp;
// if the start dates are the same, I compare the items' ids.
// this is because due to a bug (I guess) the ordering of items
// that return 0 in the ordering function might "flicker" in certain
// situations. if you want to order the items alphabetically in that
// case, compare their "content" property, or whatever other
// property you want.
}
};

Adobe Catalyst - 'Attribute Price' adding on to 'Sell Price' Issue

I have set a products sell price at £100. I have also created a 'Size' attribute at 'Large' £120.
But when I view the product and select 'Large' it prices up at £220 (adding the attribute and sell price together) when I'm wanting it at just the £120.
Any thoughts on why I'm getting this issue?
I believe Daut maybe talking about something else but I could be wrong.
When using attributes that you talk about, the price is calculated by default price plus the attribute price. This is why you see £220 as your total, as you have figured out.
In other words, your default price is £100. For your total to be £120, then your Large attribute would actually be £20. When it adds together, your total price will be £120.
When I use attributes with varying cost, I typically write my attribute as:
Large + [then BC inserts the price.]
On the BC App Store, there are a couple plugins (here and here) that assist with using Attributes. Their main purpose, from my understanding, is controling how the information is displayed to customers. I have no experience using either of these but it may help you.
Hi have created my own way around this issue in BC I also shared it on Business Catalyst Forum too. for select dropdown or radio buttons use the code bellow, you need to have a certain code ability to mend it together, it was quite done some time ago but if somebody interested on improving it to a cleaner way be welcome to share.
$(document).ready(function(){
StartDynamicPrice();
DoPriceChange();
});
var el_totalprice='#totalprice';
var el_totalprice_gst='#totalprice_gst';
//var el_attrselect='.catProdAttributeItem select';
// uncomment if you want radio as well
var el_attrselect='.catProdAttributeItem select, .catProdAttributeItem input';
var currencysymbol='£';
Number.prototype.toMoney=function(decimals, decimal_sep, thousands_sep){
var n = this,
c = isNaN(decimals) ? 2 : Math.abs(decimals),
d = decimal_sep || '.',
t = (typeof thousands_sep === 'undefined') ? ',' : thousands_sep,
sign = (n < 0) ? '-' : '',
i = parseInt(n = Math.abs(n).toFixed(c)) + '',
j = ((j = i.length) > 3) ? j % 3 : 0;
return sign + (j ? i.substr(0, j) + t : '') + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + t) + (c ? d + Math.abs(n - i).toFixed(c).slice(2) : '');
}
DoPriceChange=function(){
var selected='';
var newsubtotal=0;
$.each($(el_attrselect), function(i,e){
selected=$(e).children(':selected').text();
if (selected.indexOf(currencysymbol) != -1){
newsubtotal+=parseFloat(selected.substring(selected.indexOf(currencysymbol)+1));
};
});
newtotal=parseFloat($(el_totalprice).attr('base'))+parseFloat(newsubtotal);
newtotal_gst=newtotal+(newtotal*.10);
$(el_totalprice).html(currencysymbol+newtotal.toMoney());
$(el_totalprice_gst).html(currencysymbol+newtotal_gst.toMoney());
}
StartDynamicPrice=function(){
$(el_totalprice).attr('base',$(el_totalprice).html().replace(currencysymbol,'').replace(' ,','')); // set base price
$(el_attrselect).on('change',function(){
DoPriceChange();
})
}
/// END
Attributes in BC are add-ons. You cannot just get the attribute.
What you need is product grouping.
Group products together
You can create multiple products of the same type and group them together. A customer viewing one product can also see the available variations by selecting another product from the group.
Check how Grouping works in Business Catalyst
From the Actions menu, select Group Products Together.
Move the products from the left panel to the right, select a default product, and click Save.
Note: The default product is the only product that displays in a catalog. All other grouped products are available through the grouped product drop-down menu.

Resources