Product Analytics provides insights to manufacturer about their products, based on the parts that ends up on user's Bill of Materials (BOM, i.e. from the Calculation Dialog) when they are using CET. This is a way for manufacturers to get an early read on what are the most popular products and what may be the most common combinations and configurations.
The CET statistics system drives this feature by taking snapshot of the drawing's parts on regular intervals and some events (like user save) and send the parts list to the Analytics backend.
Most of the implementation should happen automatically. However, on thing to take note if you have implemented custom Part classes is to verify that the manufacturer association of each part is correct.
Data structure
The structure of the BOM data captured is illustrated below:
"PartSnapshot", "PartEntry", and "PartEntryOption" are specific classes in CM that are used to describe parts-related data for Analytics purpose.
Debugging
To observe the data captured in the BOM snapshots, you may use the "Dump BOM" on the trace settings in the Statistics Test extension toolbox (cm.statistics.reporter.test).
With this trace turned on, anytime you save the drawing, it will trigger the snapshot and you will see the below dump in your CM console.
The dump above shows the Parts Snapshot, i.e. details of the list of parts generated from your active drawing. The example shows parts from a drawing that contains a couple of symbols from FIKA Office and you can observe that manufacturer associated with those parts is identified by the Catalogue id 643. You can also observe infor
For your own parts, ensure that G3ManufacturerId captures either the Catalogue Id of the appropriate catalogue (that's owned by your manufacturer) or the main package of the extension.
Implementation
If we refer to the implementation in Part class below, the manufacturer can be either determined by the Part object itself (via the "statsManufacturer" method in Part) or from the owner Snapper (via the "statsManufacturer" in Snapper).
/*********************************************************************** * Statistics ***********************************************************************/ /** * Convert to statistics part entry. No recursion into child parts here * please, that will be handled by the system. */ extend public void toStatsPartEntry(Space space, PartEntry entry) { entry.pkg = class.pkg; G3ManufacturerId man = statsManufacturer(); if (!man and owner) man = owner.statsManufacturer(); entry.manufacturer = man; entry.category = category; entry.articleCode = articleCode; entry.quantity = quantity; entry.sellPrice = sellPrice(space=space); entry.listPrice = listPrice(space=space); entry.description = description(space); appendStatsPartTags(entry); entry.specOptions = statsPartEntryOptions(); currencyId c = mainCurrency(); if (c.id > 0) entry.sellCurrency = internationalCurrencySymbol(c); } /** * Get stats manufacturer id. */ extend public G3ManufacturerId statsManufacturer() { return null; } /** * Get stats part options. * Returns a sequence of (PartEntryOption[]) * where each element represents a top-level option branch. */ extend public (PartEntryOption[])[] statsPartEntryOptions() { return null; }
Overriding stats manufacturer value
In any case, the captured Manufacturer is incorrect, or if you want to change the value, you can choose to override the method in Part or Snapper to do so (Note: the method in Snapper would also be used for Extension Analytics data).
Specifying options in PartEntry
PartEntry options are automatically populated using specOptions for Part classes that extends from ProdPart class (cm.abstract.part).
//cm.abstract.part.ProdPart /** * Get stats part options. * Returns a sequence of (PartEntryOption[]) * where each element represents a top-level option branch. */ public (PartEntryOption[])[] statsPartEntryOptions() { (PartEntryOption[])[] options(); PartEntryOption[] branch; for (o in specOptions) { if (o.level == 0) { if (branch) options << branch; branch = null; } init? branch(); branch << PartEntryOption(o.code, o.description, o.groupDescription, o.level); } if (branch) options << branch; return options; }
For any implementations that do not use specOptions, it is expected that developers populate the options for PartEntry using the method above.
Comments
0 comments
Please sign in to leave a comment.