@luquimbo/bi-superpowers 5.0.0 → 5.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +5 -3
- package/.claude-plugin/plugin.json +1 -1
- package/.claude-plugin/skill-manifest.json +23 -7
- package/.plugin/plugin.json +1 -1
- package/AGENTS.md +124 -26
- package/CHANGELOG.md +494 -16
- package/README.md +33 -117
- package/bin/cli.js +1 -1
- package/bin/commands/diff.js +2 -2
- package/bin/commands/install.js +58 -45
- package/bin/commands/lint.js +2 -2
- package/bin/commands/validate-projects.js +1 -1
- package/bin/lib/generators/claude-plugin.js +14 -5
- package/bin/lib/generators/shared.js +9 -5
- package/bin/lib/mcp-config.js +22 -2
- package/bin/lib/skills.js +8 -8
- package/bin/mcp/powerbi-modeling-launcher.js +8 -4
- package/bin/postinstall.js +14 -12
- package/bin/utils/mcp-detect.js +11 -11
- package/commands/bi-connect.md +34 -17
- package/commands/bi-dax.md +385 -0
- package/commands/bi-kickoff.md +75 -44
- package/commands/bi-modeling.md +395 -0
- package/commands/bi-performance.md +455 -0
- package/commands/bi-start.md +30 -18
- package/desktop-extension/manifest.json +2 -2
- package/package.json +6 -3
- package/skills/bi-connect/SKILL.md +34 -17
- package/skills/bi-connect/scripts/update-check.js +1 -1
- package/skills/bi-dax/SKILL.md +387 -0
- package/skills/{bi-report → bi-dax}/scripts/update-check.js +1 -1
- package/skills/bi-kickoff/SKILL.md +75 -44
- package/skills/bi-kickoff/scripts/update-check.js +1 -1
- package/skills/bi-modeling/SKILL.md +397 -0
- package/skills/bi-modeling/scripts/update-check.js +403 -0
- package/skills/bi-performance/SKILL.md +457 -0
- package/skills/bi-performance/scripts/install-tabular-editor.ps1 +90 -0
- package/skills/bi-performance/scripts/run-bpa.ps1 +161 -0
- package/skills/bi-performance/scripts/update-check.js +403 -0
- package/skills/bi-start/SKILL.md +31 -19
- package/skills/bi-start/scripts/update-check.js +1 -1
- package/src/content/base.md +13 -8
- package/src/content/routing.md +1 -5
- package/src/content/skills/bi-connect.md +32 -15
- package/src/content/skills/bi-dax.md +358 -0
- package/src/content/skills/bi-kickoff.md +73 -42
- package/src/content/skills/bi-modeling.md +368 -0
- package/src/content/skills/bi-performance/SKILL.md +428 -0
- package/src/content/skills/bi-performance/scripts/install-tabular-editor.ps1 +90 -0
- package/src/content/skills/bi-performance/scripts/run-bpa.ps1 +161 -0
- package/src/content/skills/bi-start.md +30 -18
- package/templates/sales/AGENTS.md +33 -0
- package/templates/sales/sales-template.Report/.platform +11 -0
- package/templates/sales/sales-template.Report/StaticResources/RegisteredResources/BISuperpowers.json +3888 -0
- package/templates/sales/sales-template.Report/StaticResources/SharedResources/BaseThemes/Fluent2-CY26SU03.json +4104 -0
- package/templates/sales/sales-template.Report/definition/pages/017e2c84c7dc89f26e57/page.json +123 -0
- package/templates/sales/sales-template.Report/definition/pages/017e2c84c7dc89f26e57/visuals/10420560e5b8c5235857/visual.json +16 -0
- package/templates/sales/sales-template.Report/definition/pages/017e2c84c7dc89f26e57/visuals/2181c54a94f0c67abb2d/visual.json +283 -0
- package/templates/sales/sales-template.Report/definition/pages/017e2c84c7dc89f26e57/visuals/24eba6a7af0b59974ef5/visual.json +703 -0
- package/templates/sales/sales-template.Report/definition/pages/017e2c84c7dc89f26e57/visuals/26db24c91e5b615a5c29/mobile.json +11 -0
- package/templates/sales/sales-template.Report/definition/pages/017e2c84c7dc89f26e57/visuals/26db24c91e5b615a5c29/visual.json +528 -0
- package/templates/sales/sales-template.Report/definition/pages/017e2c84c7dc89f26e57/visuals/2ec652d0956901dd2afd/mobile.json +11 -0
- package/templates/sales/sales-template.Report/definition/pages/017e2c84c7dc89f26e57/visuals/2ec652d0956901dd2afd/visual.json +324 -0
- package/templates/sales/sales-template.Report/definition/pages/017e2c84c7dc89f26e57/visuals/45dda4e0b159becf2dcd/mobile.json +11 -0
- package/templates/sales/sales-template.Report/definition/pages/017e2c84c7dc89f26e57/visuals/45dda4e0b159becf2dcd/visual.json +359 -0
- package/templates/sales/sales-template.Report/definition/pages/017e2c84c7dc89f26e57/visuals/4ca8800cf1539ad423f2/visual.json +468 -0
- package/templates/sales/sales-template.Report/definition/pages/017e2c84c7dc89f26e57/visuals/4f5704218eb88f7cdff6/mobile.json +29 -0
- package/templates/sales/sales-template.Report/definition/pages/017e2c84c7dc89f26e57/visuals/4f5704218eb88f7cdff6/visual.json +241 -0
- package/templates/sales/sales-template.Report/definition/pages/017e2c84c7dc89f26e57/visuals/54d3fdbedbbb863a9d7a/visual.json +575 -0
- package/templates/sales/sales-template.Report/definition/pages/017e2c84c7dc89f26e57/visuals/68043403e96ca8ed23e8/visual.json +575 -0
- package/templates/sales/sales-template.Report/definition/pages/017e2c84c7dc89f26e57/visuals/80b54a678ef36a250994/visual.json +351 -0
- package/templates/sales/sales-template.Report/definition/pages/017e2c84c7dc89f26e57/visuals/814f624b6056dc4c8de5/mobile.json +11 -0
- package/templates/sales/sales-template.Report/definition/pages/017e2c84c7dc89f26e57/visuals/814f624b6056dc4c8de5/visual.json +421 -0
- package/templates/sales/sales-template.Report/definition/pages/017e2c84c7dc89f26e57/visuals/85e1cc13559f4e107ede/visual.json +681 -0
- package/templates/sales/sales-template.Report/definition/pages/017e2c84c7dc89f26e57/visuals/8686961b837e855963fe/mobile.json +11 -0
- package/templates/sales/sales-template.Report/definition/pages/017e2c84c7dc89f26e57/visuals/8686961b837e855963fe/visual.json +720 -0
- package/templates/sales/sales-template.Report/definition/pages/017e2c84c7dc89f26e57/visuals/8d302c5b7e87e8cb57bb/visual.json +590 -0
- package/templates/sales/sales-template.Report/definition/pages/017e2c84c7dc89f26e57/visuals/a02c5b30f2e757637d78/mobile.json +11 -0
- package/templates/sales/sales-template.Report/definition/pages/017e2c84c7dc89f26e57/visuals/a02c5b30f2e757637d78/visual.json +102 -0
- package/templates/sales/sales-template.Report/definition/pages/017e2c84c7dc89f26e57/visuals/a405d29e7744c770d445/visual.json +575 -0
- package/templates/sales/sales-template.Report/definition/pages/017e2c84c7dc89f26e57/visuals/b0dc2036d3cf2baafb35/mobile.json +11 -0
- package/templates/sales/sales-template.Report/definition/pages/017e2c84c7dc89f26e57/visuals/b0dc2036d3cf2baafb35/visual.json +333 -0
- package/templates/sales/sales-template.Report/definition/pages/017e2c84c7dc89f26e57/visuals/cdd696baaf3b80b326f8/mobile.json +11 -0
- package/templates/sales/sales-template.Report/definition/pages/017e2c84c7dc89f26e57/visuals/cdd696baaf3b80b326f8/visual.json +468 -0
- package/templates/sales/sales-template.Report/definition/pages/017e2c84c7dc89f26e57/visuals/ff77ca1bafff5bfe5044/mobile.json +11 -0
- package/templates/sales/sales-template.Report/definition/pages/017e2c84c7dc89f26e57/visuals/ff77ca1bafff5bfe5044/visual.json +523 -0
- package/templates/sales/sales-template.Report/definition/pages/6a4808bb8bb9166f49ff/page.json +130 -0
- package/templates/sales/sales-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/0352fd80d074693a65db/visual.json +681 -0
- package/templates/sales/sales-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/1c5a14bf493697344b68/visual.json +351 -0
- package/templates/sales/sales-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/3486cf7624c5b109b4e5/mobile.json +11 -0
- package/templates/sales/sales-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/3486cf7624c5b109b4e5/visual.json +333 -0
- package/templates/sales/sales-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/4d8b989008edc0db28d1/mobile.json +11 -0
- package/templates/sales/sales-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/4d8b989008edc0db28d1/visual.json +102 -0
- package/templates/sales/sales-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/5f4d76bbc870118e9840/mobile.json +11 -0
- package/templates/sales/sales-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/5f4d76bbc870118e9840/visual.json +468 -0
- package/templates/sales/sales-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/73629e1abebb7a444b59/mobile.json +11 -0
- package/templates/sales/sales-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/73629e1abebb7a444b59/visual.json +359 -0
- package/templates/sales/sales-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/749cb1388c7e0a88161c/visual.json +685 -0
- package/templates/sales/sales-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/85090dcdf75ac2487d1e/visual.json +283 -0
- package/templates/sales/sales-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/92cf92e3da10493adb78/visual.json +468 -0
- package/templates/sales/sales-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/a30bd0950630ed94e8a3/visual.json +590 -0
- package/templates/sales/sales-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/a56e91d9400a835e4814/mobile.json +11 -0
- package/templates/sales/sales-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/a56e91d9400a835e4814/visual.json +528 -0
- package/templates/sales/sales-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/a90aaa3e3117494f18f8/mobile.json +11 -0
- package/templates/sales/sales-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/a90aaa3e3117494f18f8/visual.json +523 -0
- package/templates/sales/sales-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/aded24cd205c0b528642/mobile.json +11 -0
- package/templates/sales/sales-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/aded24cd205c0b528642/visual.json +720 -0
- package/templates/sales/sales-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/af34b26f14a8a724c9a9/mobile.json +37 -0
- package/templates/sales/sales-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/af34b26f14a8a724c9a9/visual.json +1230 -0
- package/templates/sales/sales-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/b06ef80aa78cabcef8a6/mobile.json +11 -0
- package/templates/sales/sales-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/b06ef80aa78cabcef8a6/visual.json +324 -0
- package/templates/sales/sales-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/d97979633a91e041107e/mobile.json +11 -0
- package/templates/sales/sales-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/d97979633a91e041107e/visual.json +421 -0
- package/templates/sales/sales-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/fa81f184e2cb0e8b087c/mobile.json +29 -0
- package/templates/sales/sales-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/fa81f184e2cb0e8b087c/visual.json +241 -0
- package/templates/sales/sales-template.Report/definition/pages/pages.json +8 -0
- package/templates/sales/sales-template.Report/definition/report.json +89 -0
- package/templates/sales/sales-template.Report/definition/version.json +4 -0
- package/templates/sales/sales-template.Report/definition.pbir +9 -0
- package/templates/sales/sales-template.SemanticModel/.pbi/editorSettings.json +8 -0
- package/templates/sales/sales-template.SemanticModel/.platform +11 -0
- package/templates/sales/sales-template.SemanticModel/DAXQueries/.pbi/daxQueries.json +9 -0
- package/templates/sales/sales-template.SemanticModel/DAXQueries/Calendar445MonthNr.dax +0 -0
- package/templates/sales/sales-template.SemanticModel/DAXQueries/Consulta 1.dax +6 -0
- package/templates/sales/sales-template.SemanticModel/DAXQueries/Consulta 2.dax +32 -0
- package/templates/sales/sales-template.SemanticModel/definition/cultures/es-AR.tmdl +7324 -0
- package/templates/sales/sales-template.SemanticModel/definition/database.tmdl +3 -0
- package/templates/sales/sales-template.SemanticModel/definition/expressions.tmdl +233 -0
- package/templates/sales/sales-template.SemanticModel/definition/functions.tmdl +247 -0
- package/templates/sales/sales-template.SemanticModel/definition/model.tmdl +46 -0
- package/templates/sales/sales-template.SemanticModel/definition/relationships.tmdl +16 -0
- package/templates/sales/sales-template.SemanticModel/definition/tables/Aux Comparaciones.tmdl +194 -0
- package/templates/sales/sales-template.SemanticModel/definition/tables/Aux Dimensiones ventas.tmdl +71 -0
- package/templates/sales/sales-template.SemanticModel/definition/tables/Aux Ejes temporales.tmdl +67 -0
- package/templates/sales/sales-template.SemanticModel/definition/tables/Aux Per/303/255odos.tmdl" +318 -0
- package/templates/sales/sales-template.SemanticModel/definition/tables/Aux Vista de calendario.tmdl +36 -0
- package/templates/sales/sales-template.SemanticModel/definition/tables/Aux Vista del valor.tmdl +87 -0
- package/templates/sales/sales-template.SemanticModel/definition/tables/Aux Vista temporal.tmdl +62 -0
- package/templates/sales/sales-template.SemanticModel/definition/tables/Calendario.tmdl +198 -0
- package/templates/sales/sales-template.SemanticModel/definition/tables/Canales.tmdl +59 -0
- package/templates/sales/sales-template.SemanticModel/definition/tables/Clientes.tmdl +120 -0
- package/templates/sales/sales-template.SemanticModel/definition/tables/Modelo Configuraci/303/263n.tmdl" +48 -0
- package/templates/sales/sales-template.SemanticModel/definition/tables/Monedas.tmdl +43 -0
- package/templates/sales/sales-template.SemanticModel/definition/tables/M/303/251tricas.tmdl +553 -0
- package/templates/sales/sales-template.SemanticModel/definition/tables/Productos.tmdl +73 -0
- package/templates/sales/sales-template.SemanticModel/definition/tables/Tipo de cambio.tmdl +66 -0
- package/templates/sales/sales-template.SemanticModel/definition/tables/Ventas.tmdl +133 -0
- package/templates/sales/sales-template.SemanticModel/definition.pbism +5 -0
- package/templates/sales/sales-template.SemanticModel/diagramLayout.json +239 -0
- package/templates/sales/sales-template.pbip +14 -0
- package/theme/BISuperpowers.json +3888 -0
- package/commands/bi-report.md +0 -403
- package/skills/bi-report/SKILL.md +0 -405
- package/skills/bi-report/references/cli-commands.md +0 -184
- package/skills/bi-report/references/cli-setup.md +0 -101
- package/skills/bi-report/references/close-write-open-pattern.md +0 -80
- package/skills/bi-report/references/layouts/finance.md +0 -65
- package/skills/bi-report/references/layouts/generic.md +0 -46
- package/skills/bi-report/references/layouts/hr.md +0 -48
- package/skills/bi-report/references/layouts/marketing.md +0 -45
- package/skills/bi-report/references/layouts/operations.md +0 -44
- package/skills/bi-report/references/layouts/sales.md +0 -50
- package/skills/bi-report/references/native-visuals.md +0 -341
- package/skills/bi-report/references/pbi-desktop-installation.md +0 -87
- package/skills/bi-report/references/pbir-preview-activation.md +0 -40
- package/skills/bi-report/references/slicer.md +0 -89
- package/skills/bi-report/references/textbox.md +0 -101
- package/skills/bi-report/references/themes/BISuperpowers.json +0 -915
- package/skills/bi-report/references/troubleshooting.md +0 -135
- package/skills/bi-report/references/visual-types.md +0 -78
- package/skills/bi-report/scripts/apply-theme.js +0 -243
- package/skills/bi-report/scripts/create-visual.js +0 -942
- package/skills/bi-report/scripts/ensure-pbi-cli.sh +0 -41
- package/skills/bi-report/scripts/validate-pbir.js +0 -351
- package/src/content/skills/bi-report/SKILL.md +0 -376
- package/src/content/skills/bi-report/references/cli-commands.md +0 -184
- package/src/content/skills/bi-report/references/cli-setup.md +0 -101
- package/src/content/skills/bi-report/references/close-write-open-pattern.md +0 -80
- package/src/content/skills/bi-report/references/layouts/finance.md +0 -65
- package/src/content/skills/bi-report/references/layouts/generic.md +0 -46
- package/src/content/skills/bi-report/references/layouts/hr.md +0 -48
- package/src/content/skills/bi-report/references/layouts/marketing.md +0 -45
- package/src/content/skills/bi-report/references/layouts/operations.md +0 -44
- package/src/content/skills/bi-report/references/layouts/sales.md +0 -50
- package/src/content/skills/bi-report/references/native-visuals.md +0 -341
- package/src/content/skills/bi-report/references/pbi-desktop-installation.md +0 -87
- package/src/content/skills/bi-report/references/pbir-preview-activation.md +0 -40
- package/src/content/skills/bi-report/references/slicer.md +0 -89
- package/src/content/skills/bi-report/references/textbox.md +0 -101
- package/src/content/skills/bi-report/references/themes/BISuperpowers.json +0 -915
- package/src/content/skills/bi-report/references/troubleshooting.md +0 -135
- package/src/content/skills/bi-report/references/visual-types.md +0 -78
- package/src/content/skills/bi-report/scripts/apply-theme.js +0 -243
- package/src/content/skills/bi-report/scripts/create-visual.js +0 -942
- package/src/content/skills/bi-report/scripts/ensure-pbi-cli.sh +0 -41
- package/src/content/skills/bi-report/scripts/validate-pbir.js +0 -351
|
@@ -0,0 +1,553 @@
|
|
|
1
|
+
/// Tabla desconectada del template para enrutar medidas seleccionables de ventas.
|
|
2
|
+
table Métricas
|
|
3
|
+
lineageTag: f1c7296b-4b19-4310-8f46-a654a261f537
|
|
4
|
+
|
|
5
|
+
/// Moneda destino seleccionada para mostrar importes convertidos. Si no hay selección, usa la moneda base definida por el parámetro MonedaBase.
|
|
6
|
+
measure 'Moneda seleccionada' =
|
|
7
|
+
// Lee la moneda elegida en el slicer de Monedas.
|
|
8
|
+
// Si el usuario no elige una moneda, usa la misma moneda base definida para el modelo.
|
|
9
|
+
SELECTEDVALUE ( Monedas[Moneda], [Moneda base] )
|
|
10
|
+
displayFolder: Auxiliar
|
|
11
|
+
lineageTag: 5bf2e0fa-5bf2-43bc-be26-590f8e1b0aff
|
|
12
|
+
|
|
13
|
+
/// Ventas convertidas a la moneda seleccionada usando la UDF ConvertCurrency.
|
|
14
|
+
measure Ventas =
|
|
15
|
+
// Lee la moneda destino seleccionada por el usuario en el slicer Monedas.
|
|
16
|
+
VAR __MonedaDestino = [Moneda seleccionada]
|
|
17
|
+
// Recorre cada fila de ventas para convertirla desde su moneda origen a la moneda destino.
|
|
18
|
+
RETURN
|
|
19
|
+
SUMX (
|
|
20
|
+
Ventas,
|
|
21
|
+
// ConvertCurrency usa la moneda de la fila, la moneda seleccionada y la fecha de venta.
|
|
22
|
+
ConvertCurrency ( Ventas[Venta Bruta], Ventas[Moneda], __MonedaDestino, Ventas[Fecha] )
|
|
23
|
+
)
|
|
24
|
+
formatString: #,0
|
|
25
|
+
displayFolder: Ventas
|
|
26
|
+
lineageTag: 3ec2726a-08d9-438c-98fe-5cf700866b37
|
|
27
|
+
|
|
28
|
+
/// Costo convertido a la moneda seleccionada usando la UDF ConvertCurrency.
|
|
29
|
+
measure Costo =
|
|
30
|
+
// Lee la moneda destino seleccionada por el usuario en el slicer Monedas.
|
|
31
|
+
VAR __MonedaDestino = [Moneda seleccionada]
|
|
32
|
+
// Recorre cada fila de ventas para convertir el costo desde su moneda origen a la moneda destino.
|
|
33
|
+
RETURN
|
|
34
|
+
SUMX (
|
|
35
|
+
Ventas,
|
|
36
|
+
// ConvertCurrency usa la moneda de la fila, la moneda seleccionada y la fecha de venta.
|
|
37
|
+
ConvertCurrency ( Ventas[Costo Total], Ventas[Moneda], __MonedaDestino, Ventas[Fecha] )
|
|
38
|
+
)
|
|
39
|
+
formatString: #,0
|
|
40
|
+
displayFolder: Ventas
|
|
41
|
+
lineageTag: bdf3cf39-b975-490d-a90a-4a07f07f8921
|
|
42
|
+
|
|
43
|
+
/// Ventas menos costo en la moneda seleccionada.
|
|
44
|
+
measure 'Margen bruto' =
|
|
45
|
+
// Calcula cuánto queda después de restar el costo a las ventas.
|
|
46
|
+
// Ventas y Costo ya están convertidos a la moneda seleccionada.
|
|
47
|
+
[Ventas] - [Costo]
|
|
48
|
+
formatString: #,0
|
|
49
|
+
displayFolder: Ventas
|
|
50
|
+
lineageTag: fb554d55-eae7-4308-8744-fa8d60fef44d
|
|
51
|
+
|
|
52
|
+
/// Margen bruto dividido por ventas.
|
|
53
|
+
measure 'Margen %' =
|
|
54
|
+
// Divide el margen bruto por las ventas para obtener rentabilidad porcentual.
|
|
55
|
+
// DIVIDE evita errores cuando las ventas son cero o están en blanco.
|
|
56
|
+
DIVIDE ( [Margen bruto], [Ventas] )
|
|
57
|
+
formatString: 0.0%
|
|
58
|
+
displayFolder: Ratios
|
|
59
|
+
lineageTag: 286165a6-4e9e-4264-9418-e794ef369916
|
|
60
|
+
|
|
61
|
+
/// Cantidad total de unidades vendidas.
|
|
62
|
+
measure 'Unidades vendidas' =
|
|
63
|
+
// Suma la cantidad de unidades de todas las ventas visibles en el contexto actual.
|
|
64
|
+
SUM ( Ventas[Cantidad] )
|
|
65
|
+
formatString: #,0
|
|
66
|
+
displayFolder: Ventas
|
|
67
|
+
lineageTag: e7f830b2-df93-4991-83ff-03ce6358ec1e
|
|
68
|
+
|
|
69
|
+
/// Cantidad de líneas/pedidos sintéticos visibles.
|
|
70
|
+
measure Pedidos =
|
|
71
|
+
// Cuenta ventas distintas usando VentaId como identificador de pedido/línea.
|
|
72
|
+
DISTINCTCOUNT ( Ventas[VentaId] )
|
|
73
|
+
formatString: #,0
|
|
74
|
+
displayFolder: Ventas
|
|
75
|
+
lineageTag: a804b7f2-306f-46db-a712-d1f1459c9bf6
|
|
76
|
+
|
|
77
|
+
/// Ventas divididas por pedidos en la moneda seleccionada.
|
|
78
|
+
measure 'Ticket promedio' =
|
|
79
|
+
// Divide las ventas convertidas por la cantidad de pedidos.
|
|
80
|
+
// DIVIDE evita errores si no hay pedidos en el contexto actual.
|
|
81
|
+
DIVIDE ( [Ventas], [Pedidos] )
|
|
82
|
+
formatString: #,0
|
|
83
|
+
displayFolder: Ratios
|
|
84
|
+
lineageTag: 61c8a07a-62ca-49e1-a2d6-3db9587ca795
|
|
85
|
+
|
|
86
|
+
/// Valor de la métrica seleccionada para el período actual. Requiere una única métrica en contexto.
|
|
87
|
+
measure 'Periodo Actual' =
|
|
88
|
+
// Lee qué métrica eligió el usuario. Sin selección única, el cálculo queda en blanco.
|
|
89
|
+
VAR __MetricName = SELECTEDVALUE ( 'Métricas'[Métrica] )
|
|
90
|
+
// Pide a la UDF CalendarContext la definición del período actual y previo.
|
|
91
|
+
VAR __CalendarContext = CalendarContext ()
|
|
92
|
+
// Extrae la primera fecha del período actual.
|
|
93
|
+
VAR __Start = MAXX ( __CalendarContext, [Current Start] )
|
|
94
|
+
// Extrae la última fecha del período actual.
|
|
95
|
+
VAR __End = MAXX ( __CalendarContext, [Current End] )
|
|
96
|
+
// Detecta si el visual tiene un eje temporal (UDF central, un solo punto de cambio).
|
|
97
|
+
VAR __HasCalendarAxis = EjeCalendarioEnContexto ()
|
|
98
|
+
RETURN
|
|
99
|
+
IF (
|
|
100
|
+
NOT ISBLANK ( __MetricName )
|
|
101
|
+
&& NOT ISBLANK ( __Start )
|
|
102
|
+
&& NOT ISBLANK ( __End ),
|
|
103
|
+
IF (
|
|
104
|
+
__HasCalendarAxis,
|
|
105
|
+
// En gráficos con eje temporal respetamos el eje y solo limitamos el rango.
|
|
106
|
+
CALCULATE (
|
|
107
|
+
[Selector métrica],
|
|
108
|
+
TREATAS ( { __MetricName }, 'Métricas'[Métrica] ),
|
|
109
|
+
KEEPFILTERS ( DATESBETWEEN ( 'Calendario'[Fecha], __Start, __End ) )
|
|
110
|
+
),
|
|
111
|
+
// En tarjetas quitamos el filtro de fecha previo y aplicamos el rango completo.
|
|
112
|
+
CALCULATE (
|
|
113
|
+
[Selector métrica],
|
|
114
|
+
TREATAS ( { __MetricName }, 'Métricas'[Métrica] ),
|
|
115
|
+
REMOVEFILTERS ( 'Calendario' ),
|
|
116
|
+
DATESBETWEEN ( 'Calendario'[Fecha], __Start, __End )
|
|
117
|
+
)
|
|
118
|
+
)
|
|
119
|
+
)
|
|
120
|
+
displayFolder: Auxiliar
|
|
121
|
+
lineageTag: 7d83954c-90a1-4b67-b326-826100ef6038
|
|
122
|
+
|
|
123
|
+
formatStringDefinition = FormatoMetricaSeleccionada ()
|
|
124
|
+
|
|
125
|
+
/// Valor de la métrica seleccionada para el período anterior comparable. Requiere una única métrica en contexto.
|
|
126
|
+
measure 'Periodo Previo' =
|
|
127
|
+
// Lee qué métrica eligió el usuario. Sin selección única, el cálculo queda en blanco.
|
|
128
|
+
VAR __MetricName = SELECTEDVALUE ( 'Métricas'[Métrica] )
|
|
129
|
+
// Pide a la UDF CalendarContext la definición del período actual y previo.
|
|
130
|
+
VAR __CalendarContext = CalendarContext ()
|
|
131
|
+
// Extrae la primera fecha del período actual.
|
|
132
|
+
VAR __CurrentStart = MAXX ( __CalendarContext, [Current Start] )
|
|
133
|
+
// Extrae la última fecha del período actual.
|
|
134
|
+
VAR __CurrentEnd = MAXX ( __CalendarContext, [Current End] )
|
|
135
|
+
// Extrae la primera fecha del período previo comparable.
|
|
136
|
+
VAR __PreviousStart = MAXX ( __CalendarContext, [Previous Start] )
|
|
137
|
+
// Extrae la última fecha del período previo comparable.
|
|
138
|
+
VAR __PreviousEnd = MAXX ( __CalendarContext, [Previous End] )
|
|
139
|
+
// Calcula cuántos días separan el inicio actual del inicio previo.
|
|
140
|
+
VAR __DateOffset = __CurrentStart - __PreviousStart
|
|
141
|
+
// Detecta si el visual tiene un eje temporal (UDF central, un solo punto de cambio).
|
|
142
|
+
VAR __HasCalendarAxis = EjeCalendarioEnContexto ()
|
|
143
|
+
RETURN
|
|
144
|
+
IF (
|
|
145
|
+
NOT ISBLANK ( __MetricName )
|
|
146
|
+
&& NOT ISBLANK ( __PreviousStart )
|
|
147
|
+
&& NOT ISBLANK ( __PreviousEnd ),
|
|
148
|
+
IF (
|
|
149
|
+
__HasCalendarAxis,
|
|
150
|
+
// Captura las fechas visibles del período actual para desplazar punto a punto.
|
|
151
|
+
VAR __VisibleCurrentDates =
|
|
152
|
+
CALCULATETABLE (
|
|
153
|
+
VALUES ( 'Calendario'[Fecha] ),
|
|
154
|
+
KEEPFILTERS ( DATESBETWEEN ( 'Calendario'[Fecha], __CurrentStart, __CurrentEnd ) )
|
|
155
|
+
)
|
|
156
|
+
// Desplaza esas fechas hacia el período previo manteniendo el mismo patrón temporal.
|
|
157
|
+
VAR __ShiftedPreviousDates =
|
|
158
|
+
SELECTCOLUMNS (
|
|
159
|
+
FILTER (
|
|
160
|
+
ADDCOLUMNS ( __VisibleCurrentDates, "__PreviousDate", 'Calendario'[Fecha] - __DateOffset ),
|
|
161
|
+
[__PreviousDate] >= __PreviousStart
|
|
162
|
+
&& [__PreviousDate] <= __PreviousEnd
|
|
163
|
+
),
|
|
164
|
+
"Fecha", [__PreviousDate]
|
|
165
|
+
)
|
|
166
|
+
RETURN
|
|
167
|
+
IF (
|
|
168
|
+
NOT ISEMPTY ( __ShiftedPreviousDates ),
|
|
169
|
+
CALCULATE (
|
|
170
|
+
[Selector métrica],
|
|
171
|
+
TREATAS ( { __MetricName }, 'Métricas'[Métrica] ),
|
|
172
|
+
REMOVEFILTERS ( 'Calendario' ),
|
|
173
|
+
TREATAS ( __ShiftedPreviousDates, 'Calendario'[Fecha] )
|
|
174
|
+
)
|
|
175
|
+
),
|
|
176
|
+
// En tarjetas usamos directamente todo el rango previo comparable.
|
|
177
|
+
CALCULATE (
|
|
178
|
+
[Selector métrica],
|
|
179
|
+
TREATAS ( { __MetricName }, 'Métricas'[Métrica] ),
|
|
180
|
+
REMOVEFILTERS ( 'Calendario' ),
|
|
181
|
+
DATESBETWEEN ( 'Calendario'[Fecha], __PreviousStart, __PreviousEnd )
|
|
182
|
+
)
|
|
183
|
+
)
|
|
184
|
+
)
|
|
185
|
+
displayFolder: Auxiliar
|
|
186
|
+
lineageTag: 11e4fee6-6079-4522-91c4-f4f653ccc2b2
|
|
187
|
+
|
|
188
|
+
formatStringDefinition = FormatoMetricaSeleccionada ()
|
|
189
|
+
|
|
190
|
+
/// Diferencia entre el período actual y el período anterior para la métrica seleccionada.
|
|
191
|
+
measure Variación =
|
|
192
|
+
// Guarda el valor del período actual.
|
|
193
|
+
VAR __Actual = [Periodo Actual]
|
|
194
|
+
// Guarda el valor del período anterior comparable.
|
|
195
|
+
VAR __Anterior = [Periodo Previo]
|
|
196
|
+
// Resta anterior a actual solo cuando ambos valores existen.
|
|
197
|
+
RETURN
|
|
198
|
+
IF ( NOT ISBLANK ( __Actual ) && NOT ISBLANK ( __Anterior ), __Actual - __Anterior )
|
|
199
|
+
displayFolder: Auxiliar
|
|
200
|
+
lineageTag: 5c881ac9-8f88-4fcb-914b-cdf064840418
|
|
201
|
+
|
|
202
|
+
formatStringDefinition = FormatoMetricaSeleccionada ()
|
|
203
|
+
|
|
204
|
+
/// Variación porcentual del período actual contra el período anterior.
|
|
205
|
+
measure 'Variación %' =
|
|
206
|
+
// Divide la variación absoluta por el valor anterior para obtener variación porcentual.
|
|
207
|
+
// DIVIDE evita errores si el valor anterior es cero o está en blanco.
|
|
208
|
+
DIVIDE ( [Variación], [Periodo Previo] )
|
|
209
|
+
formatString: 0.0%;-0.0%;0.0%
|
|
210
|
+
displayFolder: Ratios
|
|
211
|
+
lineageTag: 66146073-d9e7-41ee-8a34-563faeab1afb
|
|
212
|
+
|
|
213
|
+
/// Router interno que devuelve la medida real cuando hay exactamente una métrica seleccionada.
|
|
214
|
+
measure 'Selector métrica' =
|
|
215
|
+
// Lee el nombre de la métrica elegida. En producción no usamos default:
|
|
216
|
+
// si no hay exactamente una métrica en contexto, devolvemos BLANK().
|
|
217
|
+
VAR __MetricName = SELECTEDVALUE ( 'Métricas'[Métrica] )
|
|
218
|
+
RETURN
|
|
219
|
+
SWITCH (
|
|
220
|
+
TRUE (),
|
|
221
|
+
ISBLANK ( __MetricName ), BLANK (),
|
|
222
|
+
__MetricName = "Ventas", [Ventas],
|
|
223
|
+
__MetricName = "Margen bruto", [Margen bruto],
|
|
224
|
+
__MetricName = "Margen %", [Margen %],
|
|
225
|
+
__MetricName = "Unidades vendidas", [Unidades vendidas],
|
|
226
|
+
__MetricName = "Pedidos", [Pedidos],
|
|
227
|
+
__MetricName = "Ticket promedio", [Ticket promedio],
|
|
228
|
+
__MetricName = "Ventas nuevos clientes", [Ventas nuevos clientes],
|
|
229
|
+
__MetricName = "Ventas nuevos clientes %", [Ventas nuevos clientes %],
|
|
230
|
+
BLANK ()
|
|
231
|
+
)
|
|
232
|
+
formatString: #,0
|
|
233
|
+
isHidden
|
|
234
|
+
displayFolder: Auxiliar
|
|
235
|
+
lineageTag: f8cb8072-fffe-4f9d-ab14-15b87910158f
|
|
236
|
+
|
|
237
|
+
/// Primera fecha del período actual seleccionado.
|
|
238
|
+
measure 'Fecha inicial actual' =
|
|
239
|
+
// Pide a CalendarContext la fila con los rangos de comparación.
|
|
240
|
+
// Devuelve la primera fecha del rango actual.
|
|
241
|
+
MAXX ( CalendarContext (), [Current Start] )
|
|
242
|
+
formatString: dd/mm/yyyy
|
|
243
|
+
isHidden
|
|
244
|
+
displayFolder: Auxiliar
|
|
245
|
+
lineageTag: 9512b74d-b5f8-4c16-a523-9d859f85bf41
|
|
246
|
+
|
|
247
|
+
/// Última fecha del período actual seleccionado.
|
|
248
|
+
measure 'Fecha final actual' =
|
|
249
|
+
// Pide a CalendarContext la fila con los rangos de comparación.
|
|
250
|
+
// Devuelve la última fecha del rango actual.
|
|
251
|
+
MAXX ( CalendarContext (), [Current End] )
|
|
252
|
+
formatString: dd/mm/yyyy
|
|
253
|
+
isHidden
|
|
254
|
+
displayFolder: Auxiliar
|
|
255
|
+
lineageTag: 9491d15a-a1a7-4ded-8161-21474fdaffb6
|
|
256
|
+
|
|
257
|
+
/// Primera fecha del período previo seleccionado.
|
|
258
|
+
measure 'Fecha inicial anterior' =
|
|
259
|
+
// Pide a CalendarContext la fila con los rangos de comparación.
|
|
260
|
+
// Devuelve la primera fecha del rango previo.
|
|
261
|
+
MAXX ( CalendarContext (), [Previous Start] )
|
|
262
|
+
formatString: dd/mm/yyyy
|
|
263
|
+
isHidden
|
|
264
|
+
displayFolder: Auxiliar
|
|
265
|
+
lineageTag: ef4de0c9-0fd3-4de8-a970-89642c59064e
|
|
266
|
+
|
|
267
|
+
/// Última fecha del período previo seleccionado.
|
|
268
|
+
measure 'Fecha final anterior' =
|
|
269
|
+
// Pide a CalendarContext la fila con los rangos de comparación.
|
|
270
|
+
// Devuelve la última fecha del rango previo.
|
|
271
|
+
MAXX ( CalendarContext (), [Previous End] )
|
|
272
|
+
formatString: dd/mm/yyyy
|
|
273
|
+
isHidden
|
|
274
|
+
displayFolder: Auxiliar
|
|
275
|
+
lineageTag: be892c13-b21d-442e-b210-1a53e47debc2
|
|
276
|
+
|
|
277
|
+
/// Título de comparación que muestra el rango actual y el rango previo en una sola línea.
|
|
278
|
+
measure 'Título comparación' =
|
|
279
|
+
// Devuelve en una sola medida el rango actual y su rango comparable.
|
|
280
|
+
VAR __CurrentStart = [Fecha inicial actual]
|
|
281
|
+
VAR __CurrentEnd = [Fecha final actual]
|
|
282
|
+
VAR __PreviousStart = [Fecha inicial anterior]
|
|
283
|
+
VAR __PreviousEnd = [Fecha final anterior]
|
|
284
|
+
VAR __CurrentStartText = SUBSTITUTE ( LOWER ( FORMAT ( __CurrentStart, "ddd d/m/yy", "es-AR" ) ), ".", "" )
|
|
285
|
+
VAR __CurrentEndText = SUBSTITUTE ( LOWER ( FORMAT ( __CurrentEnd, "ddd d/m/yy", "es-AR" ) ), ".", "" )
|
|
286
|
+
VAR __PreviousStartText = SUBSTITUTE ( LOWER ( FORMAT ( __PreviousStart, "ddd d/m/yy", "es-AR" ) ), ".", "" )
|
|
287
|
+
VAR __PreviousEndText = SUBSTITUTE ( LOWER ( FORMAT ( __PreviousEnd, "ddd d/m/yy", "es-AR" ) ), ".", "" )
|
|
288
|
+
RETURN
|
|
289
|
+
IF (
|
|
290
|
+
NOT ISBLANK ( __CurrentStart )
|
|
291
|
+
&& NOT ISBLANK ( __CurrentEnd )
|
|
292
|
+
&& NOT ISBLANK ( __PreviousStart )
|
|
293
|
+
&& NOT ISBLANK ( __PreviousEnd ),
|
|
294
|
+
"Del " & __CurrentStartText & " al " & __CurrentEndText
|
|
295
|
+
& " (vs. " & __PreviousStartText & " al " & __PreviousEndText & ")"
|
|
296
|
+
)
|
|
297
|
+
isHidden
|
|
298
|
+
displayFolder: Auxiliar
|
|
299
|
+
lineageTag: 62eb5630-a405-4a36-adf1-48f07b3345fd
|
|
300
|
+
|
|
301
|
+
/// Etiqueta textual de variación porcentual con icono Unicode de dirección e incluye el valor del periodo anterior en formato compacto como `Prev.`.
|
|
302
|
+
measure 'Etiqueta variación %' =
|
|
303
|
+
// Muestra la direccion de la variacion porcentual con un icono Unicode.
|
|
304
|
+
// Tambien muestra el valor del periodo anterior en formato compacto de etiqueta.
|
|
305
|
+
VAR __ChangePct = [Variación %]
|
|
306
|
+
VAR __Previous = [Periodo Previo]
|
|
307
|
+
VAR __Icon =
|
|
308
|
+
SWITCH (
|
|
309
|
+
TRUE (),
|
|
310
|
+
ISBLANK ( __ChangePct ), BLANK (),
|
|
311
|
+
__ChangePct > 0, UNICHAR ( 9650 ),
|
|
312
|
+
__ChangePct < 0, UNICHAR ( 9660 ),
|
|
313
|
+
BLANK ()
|
|
314
|
+
)
|
|
315
|
+
VAR __ChangeText = FORMAT ( ABS ( __ChangePct ), "0.0%" )
|
|
316
|
+
VAR __PreviousText = FormatoValorEtiqueta ( __Previous )
|
|
317
|
+
VAR __Label =
|
|
318
|
+
IF (
|
|
319
|
+
ISBLANK ( __Icon ),
|
|
320
|
+
__ChangeText,
|
|
321
|
+
__Icon & " " & __ChangeText
|
|
322
|
+
)
|
|
323
|
+
RETURN
|
|
324
|
+
IF (
|
|
325
|
+
ISBLANK ( __ChangePct ),
|
|
326
|
+
"-",
|
|
327
|
+
__Label & " (Prev. " & __PreviousText & ")"
|
|
328
|
+
)
|
|
329
|
+
displayFolder: Auxiliar
|
|
330
|
+
lineageTag: 3065df96-b375-4d44-9b89-730a0f864b92
|
|
331
|
+
|
|
332
|
+
/// Ventas de clientes cuya primera venta histórica cae dentro del contexto de fechas visible. Devuelve 0 cuando no hay clientes nuevos para que los visuals no queden en blanco.
|
|
333
|
+
measure 'Ventas nuevos clientes' =
|
|
334
|
+
// Identifica los clientes cuya primera venta historica cae dentro del contexto de fechas visible.
|
|
335
|
+
// REMOVEFILTERS ( Calendario ) evita que la primera venta quede recortada por el periodo actual.
|
|
336
|
+
VAR __FechasVisibles = VALUES ( 'Calendario'[Fecha] )
|
|
337
|
+
VAR __ClientesNuevos =
|
|
338
|
+
FILTER (
|
|
339
|
+
VALUES ( Clientes[ClienteId] ),
|
|
340
|
+
VAR __PrimeraVentaCliente =
|
|
341
|
+
CALCULATE (
|
|
342
|
+
MIN ( Ventas[Fecha] ),
|
|
343
|
+
REMOVEFILTERS ( 'Calendario' )
|
|
344
|
+
)
|
|
345
|
+
RETURN
|
|
346
|
+
CONTAINSROW ( __FechasVisibles, __PrimeraVentaCliente )
|
|
347
|
+
)
|
|
348
|
+
VAR __VentasNuevos = CALCULATE ( [Ventas], __ClientesNuevos )
|
|
349
|
+
RETURN
|
|
350
|
+
COALESCE ( __VentasNuevos, 0 )
|
|
351
|
+
formatString: #,0
|
|
352
|
+
displayFolder: Ventas
|
|
353
|
+
lineageTag: eca6420b-769a-4a38-8cf3-67d9056f74f4
|
|
354
|
+
|
|
355
|
+
/// Porcentaje de ventas visibles explicado por clientes nuevos. Devuelve 0 cuando no hay ventas o no hay clientes nuevos.
|
|
356
|
+
measure 'Ventas nuevos clientes %' =
|
|
357
|
+
// Participacion de las ventas generadas por clientes nuevos sobre las ventas totales visibles.
|
|
358
|
+
// El tercer argumento devuelve 0 cuando no hay ventas en el contexto.
|
|
359
|
+
DIVIDE ( [Ventas nuevos clientes], [Ventas], 0 )
|
|
360
|
+
formatString: 0.0%
|
|
361
|
+
displayFolder: Ratios
|
|
362
|
+
lineageTag: 44abd84b-93fd-4691-9595-5dd70d5c1ec0
|
|
363
|
+
|
|
364
|
+
/// Color para formato condicional de bullet charts: Tremor Green #22C55E cuando la variación es favorable, Tremor Red #EF4444 cuando es desfavorable y Tremor Gray #6B7280 cuando es neutra o no evaluable.
|
|
365
|
+
measure 'Color bullet variación' =
|
|
366
|
+
// Color para aplicar con fx sobre bullet charts.
|
|
367
|
+
// Interpreta el signo de [Variación %] contra la Tendencia configurada en Métricas.
|
|
368
|
+
VAR __ChangePct = [Variación %]
|
|
369
|
+
VAR __Trend = SELECTEDVALUE ( 'Métricas'[Tendencia] )
|
|
370
|
+
VAR __Direction =
|
|
371
|
+
SWITCH (
|
|
372
|
+
TRUE (),
|
|
373
|
+
ISBLANK ( __ChangePct ), 0,
|
|
374
|
+
__ChangePct > 0, 1,
|
|
375
|
+
__ChangePct < 0, -1,
|
|
376
|
+
0
|
|
377
|
+
)
|
|
378
|
+
VAR __Score =
|
|
379
|
+
SWITCH (
|
|
380
|
+
TRUE (),
|
|
381
|
+
__Direction = 0 || ISBLANK ( __Trend ), 0,
|
|
382
|
+
__Trend IN { "Baja es positivo", "Negativo", "Negativa" } && __Direction < 0, 1,
|
|
383
|
+
__Trend IN { "Baja es positivo", "Negativo", "Negativa" } && __Direction > 0, -1,
|
|
384
|
+
__Trend IN { "Sube es positivo", "Positivo", "Positiva" } && __Direction > 0, 1,
|
|
385
|
+
__Trend IN { "Sube es positivo", "Positivo", "Positiva" } && __Direction < 0, -1,
|
|
386
|
+
0
|
|
387
|
+
)
|
|
388
|
+
RETURN
|
|
389
|
+
SWITCH (
|
|
390
|
+
TRUE (),
|
|
391
|
+
__Score > 0, "#22C55E",
|
|
392
|
+
__Score < 0, "#EF4444",
|
|
393
|
+
"#6B7280"
|
|
394
|
+
)
|
|
395
|
+
displayFolder: Auxiliar
|
|
396
|
+
lineageTag: 96ee8802-7a64-4454-991f-08c8a08daef1
|
|
397
|
+
|
|
398
|
+
/// Color para formato condicional de etiquetas de variación: Tremor Green #22C55E cuando la variación es favorable, Tremor Red #EF4444 cuando es desfavorable y Tremor Gray #6B7280 cuando es neutra o no evaluable.
|
|
399
|
+
measure 'Color etiqueta variación' =
|
|
400
|
+
// Color para aplicar con fx sobre etiquetas de variacion.
|
|
401
|
+
// Interpreta el signo de [Variación %] contra la Tendencia configurada en Métricas.
|
|
402
|
+
VAR __ChangePct = [Variación %]
|
|
403
|
+
VAR __Trend = SELECTEDVALUE ( 'Métricas'[Tendencia] )
|
|
404
|
+
VAR __Direction =
|
|
405
|
+
SWITCH (
|
|
406
|
+
TRUE (),
|
|
407
|
+
ISBLANK ( __ChangePct ), 0,
|
|
408
|
+
__ChangePct > 0, 1,
|
|
409
|
+
__ChangePct < 0, -1,
|
|
410
|
+
0
|
|
411
|
+
)
|
|
412
|
+
VAR __Score =
|
|
413
|
+
SWITCH (
|
|
414
|
+
TRUE (),
|
|
415
|
+
__Direction = 0 || ISBLANK ( __Trend ), 0,
|
|
416
|
+
__Trend IN { "Baja es positivo", "Negativo", "Negativa" } && __Direction < 0, 1,
|
|
417
|
+
__Trend IN { "Baja es positivo", "Negativo", "Negativa" } && __Direction > 0, -1,
|
|
418
|
+
__Trend IN { "Sube es positivo", "Positivo", "Positiva" } && __Direction > 0, 1,
|
|
419
|
+
__Trend IN { "Sube es positivo", "Positivo", "Positiva" } && __Direction < 0, -1,
|
|
420
|
+
0
|
|
421
|
+
)
|
|
422
|
+
RETURN
|
|
423
|
+
SWITCH (
|
|
424
|
+
TRUE (),
|
|
425
|
+
__Score > 0, "#22C55E",
|
|
426
|
+
__Score < 0, "#EF4444",
|
|
427
|
+
"#6B7280"
|
|
428
|
+
)
|
|
429
|
+
displayFolder: Auxiliar
|
|
430
|
+
lineageTag: 0d772674-7987-48b4-812a-1eea6d3b63da
|
|
431
|
+
|
|
432
|
+
/// Etiqueta para bullet charts: icono Unicode de subida/bajada y variación porcentual. El color se aplica con la medida de color del bullet.
|
|
433
|
+
measure 'Etiqueta bullet chart' =
|
|
434
|
+
// Etiqueta compacta para bullet charts: icono de variacion y porcentaje.
|
|
435
|
+
VAR __ChangePct = [Variación %]
|
|
436
|
+
VAR __Icon =
|
|
437
|
+
SWITCH (
|
|
438
|
+
TRUE (),
|
|
439
|
+
ISBLANK ( __ChangePct ), BLANK (),
|
|
440
|
+
__ChangePct > 0, UNICHAR ( 9650 ),
|
|
441
|
+
__ChangePct < 0, UNICHAR ( 9660 ),
|
|
442
|
+
BLANK ()
|
|
443
|
+
)
|
|
444
|
+
VAR __ChangeText = FORMAT ( ABS ( __ChangePct ), "0.0%" )
|
|
445
|
+
RETURN
|
|
446
|
+
IF (
|
|
447
|
+
ISBLANK ( __ChangePct ),
|
|
448
|
+
BLANK (),
|
|
449
|
+
IF ( ISBLANK ( __Icon ), __ChangeText, __Icon & " " & __ChangeText )
|
|
450
|
+
)
|
|
451
|
+
displayFolder: Auxiliar
|
|
452
|
+
lineageTag: 4ca5174b-6818-4632-a87c-825364b498a3
|
|
453
|
+
|
|
454
|
+
/// Título textual para visuals: devuelve el nombre de la métrica seleccionada desde Métricas[Métrica].
|
|
455
|
+
measure 'Título métrica' =
|
|
456
|
+
// Titulo de visual basado en la metrica seleccionada.
|
|
457
|
+
SELECTEDVALUE ( 'Métricas'[Métrica] )
|
|
458
|
+
displayFolder: Auxiliar
|
|
459
|
+
lineageTag: ab43c6f2-0fee-4d37-96fe-ca978cf66ea2
|
|
460
|
+
|
|
461
|
+
/// Subtítulo textual para visuals: devuelve la definición de la métrica seleccionada desde Métricas[Descripción].
|
|
462
|
+
measure 'Subtítulo métrica' =
|
|
463
|
+
// Subtitulo de visual basado en la definicion de la metrica seleccionada.
|
|
464
|
+
SELECTEDVALUE ( 'Métricas'[Descripción] )
|
|
465
|
+
displayFolder: Auxiliar
|
|
466
|
+
lineageTag: eab62d0c-d40b-4b8a-b79c-cec58830ea57
|
|
467
|
+
|
|
468
|
+
/// Moneda base definida por el parámetro Power Query MonedaBase. También es el default de visualización cuando no hay una selección única en Monedas.
|
|
469
|
+
measure 'Moneda base' =
|
|
470
|
+
VAR __ConfiguredCurrency =
|
|
471
|
+
MAXX (
|
|
472
|
+
FILTER (
|
|
473
|
+
ALL ( 'Modelo Configuración' ),
|
|
474
|
+
'Modelo Configuración'[Configuración] = "Moneda Base"
|
|
475
|
+
),
|
|
476
|
+
'Modelo Configuración'[ValorTexto]
|
|
477
|
+
)
|
|
478
|
+
RETURN
|
|
479
|
+
COALESCE ( __ConfiguredCurrency, "USD" )
|
|
480
|
+
isHidden
|
|
481
|
+
displayFolder: Auxiliar
|
|
482
|
+
lineageTag: b65ba356-1fcd-4f55-b408-68e69b6bc77b
|
|
483
|
+
|
|
484
|
+
column Métrica
|
|
485
|
+
lineageTag: 748cb7e2-0803-4f55-a9e0-eb44ea479875
|
|
486
|
+
summarizeBy: none
|
|
487
|
+
isNameInferred
|
|
488
|
+
sourceColumn: [Métrica]
|
|
489
|
+
sortByColumn: Índice
|
|
490
|
+
|
|
491
|
+
column Índice
|
|
492
|
+
isHidden
|
|
493
|
+
formatString: 0
|
|
494
|
+
lineageTag: cda91f1e-e9df-4a43-a7e0-93b753a3aa2f
|
|
495
|
+
summarizeBy: none
|
|
496
|
+
isNameInferred
|
|
497
|
+
sourceColumn: [Índice]
|
|
498
|
+
|
|
499
|
+
column Formato
|
|
500
|
+
isHidden
|
|
501
|
+
lineageTag: 42b9b96a-0e2a-4101-8948-c109fb8060e2
|
|
502
|
+
summarizeBy: none
|
|
503
|
+
isNameInferred
|
|
504
|
+
sourceColumn: [Formato]
|
|
505
|
+
|
|
506
|
+
column Tendencia
|
|
507
|
+
isHidden
|
|
508
|
+
lineageTag: 2c23d1b2-5d16-4816-9950-7b808c986195
|
|
509
|
+
summarizeBy: none
|
|
510
|
+
isNameInferred
|
|
511
|
+
sourceColumn: [Tendencia]
|
|
512
|
+
|
|
513
|
+
column Acumulado
|
|
514
|
+
isHidden
|
|
515
|
+
lineageTag: 02dbb720-4ccb-4bf5-8dcb-d968fb47cef0
|
|
516
|
+
summarizeBy: none
|
|
517
|
+
isNameInferred
|
|
518
|
+
sourceColumn: [Acumulado]
|
|
519
|
+
|
|
520
|
+
column Descripción
|
|
521
|
+
lineageTag: 44a61e89-9050-4664-b8f0-cb86c9afb703
|
|
522
|
+
summarizeBy: none
|
|
523
|
+
isNameInferred
|
|
524
|
+
sourceColumn: [Descripción]
|
|
525
|
+
|
|
526
|
+
column Monetaria
|
|
527
|
+
lineageTag: 01fbb1bb-8876-49bb-aaa1-6a956dac8ff0
|
|
528
|
+
isNameInferred
|
|
529
|
+
sourceColumn: [Monetaria]
|
|
530
|
+
|
|
531
|
+
partition Métricas = calculated
|
|
532
|
+
mode: import
|
|
533
|
+
source =
|
|
534
|
+
DATATABLE (
|
|
535
|
+
"Métrica", STRING,
|
|
536
|
+
"Índice", INTEGER,
|
|
537
|
+
"Formato", STRING,
|
|
538
|
+
"Tendencia", STRING,
|
|
539
|
+
"Monetaria", BOOLEAN,
|
|
540
|
+
"Acumulado", BOOLEAN,
|
|
541
|
+
"Descripción", STRING,
|
|
542
|
+
{
|
|
543
|
+
{ "Ventas", 1, "#,0", "Sube es positivo", TRUE, TRUE, "Ventas convertidas a la moneda seleccionada." },
|
|
544
|
+
{ "Margen bruto", 2, "#,0", "Sube es positivo", TRUE, TRUE, "Ventas menos costo en la moneda seleccionada." },
|
|
545
|
+
{ "Margen %", 3, "0.0%", "Sube es positivo", FALSE, FALSE, "Margen bruto dividido por ventas." },
|
|
546
|
+
{ "Unidades vendidas", 4, "#,0", "Sube es positivo", FALSE, TRUE, "Cantidad de unidades vendidas." },
|
|
547
|
+
{ "Pedidos", 5, "#,0", "Sube es positivo", FALSE, TRUE, "Cantidad de pedidos o líneas de venta." },
|
|
548
|
+
{ "Ticket promedio", 6, "#,0", "Sube es positivo", TRUE, FALSE, "Ventas divididas por pedidos en la moneda seleccionada." },
|
|
549
|
+
{ "Ventas nuevos clientes", 7, "#,0", "Sube es positivo", TRUE, TRUE, "Ventas de clientes cuya primera venta histórica cae dentro del contexto de fechas visible." },
|
|
550
|
+
{ "Ventas nuevos clientes %", 8, "0.0%", "Sube es positivo", FALSE, FALSE, "Porcentaje de ventas visibles explicado por clientes nuevos." }
|
|
551
|
+
}
|
|
552
|
+
)
|
|
553
|
+
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/// Dimension de productos sintética para ventas, cargada desde Power Query para que el sample dataset no dependa de DAX calculated tables.
|
|
2
|
+
table Productos
|
|
3
|
+
lineageTag: 129abf05-1906-4a84-b7ce-0f26b4b60083
|
|
4
|
+
|
|
5
|
+
column ProductoId
|
|
6
|
+
dataType: string
|
|
7
|
+
isHidden
|
|
8
|
+
lineageTag: ca5f9070-95c1-4d7f-bb7f-dcd5caf63e86
|
|
9
|
+
summarizeBy: none
|
|
10
|
+
sourceColumn: ProductoId
|
|
11
|
+
|
|
12
|
+
annotation SummarizationSetBy = Automatic
|
|
13
|
+
|
|
14
|
+
column Producto
|
|
15
|
+
dataType: string
|
|
16
|
+
lineageTag: 7251821c-c2b3-4e71-a4f7-a492793acf44
|
|
17
|
+
summarizeBy: none
|
|
18
|
+
sourceColumn: Producto
|
|
19
|
+
|
|
20
|
+
column Categoría
|
|
21
|
+
dataType: string
|
|
22
|
+
lineageTag: f0b5325a-2564-4f0e-9a33-f59b72a49a41
|
|
23
|
+
summarizeBy: none
|
|
24
|
+
sourceColumn: Categoria
|
|
25
|
+
|
|
26
|
+
column Subcategoría
|
|
27
|
+
dataType: string
|
|
28
|
+
lineageTag: 79b4bb01-8955-4f4d-8021-485d2c0b0869
|
|
29
|
+
summarizeBy: none
|
|
30
|
+
sourceColumn: Subcategoria
|
|
31
|
+
|
|
32
|
+
/// Drill-down estándar de Productos: Categoría -> Subcategoría -> Producto.
|
|
33
|
+
hierarchy 'Jerarquía de productos'
|
|
34
|
+
lineageTag: 4c61c740-5ac8-4a33-ae38-cc46369099dd
|
|
35
|
+
|
|
36
|
+
level Categoría
|
|
37
|
+
lineageTag: 4f5c233f-66ae-46d0-bc3a-cc19daca8161
|
|
38
|
+
column: Categoría
|
|
39
|
+
|
|
40
|
+
level Subcategoría
|
|
41
|
+
lineageTag: d82a4e44-77c3-4792-a764-a4610c6794f4
|
|
42
|
+
column: Subcategoría
|
|
43
|
+
|
|
44
|
+
level Producto
|
|
45
|
+
lineageTag: f439e85f-0346-4b49-8467-2e639f07364b
|
|
46
|
+
column: Producto
|
|
47
|
+
|
|
48
|
+
partition Productos = m
|
|
49
|
+
mode: import
|
|
50
|
+
queryGroup: 'Sample Dataset'
|
|
51
|
+
source =
|
|
52
|
+
let
|
|
53
|
+
Source = #table(
|
|
54
|
+
type table [ProductoId = Int64.Type, Producto = text, Categoria = text, Subcategoria = text],
|
|
55
|
+
{
|
|
56
|
+
{ 1, "Notebook Pro", "Hardware", "Computadoras" },
|
|
57
|
+
{ 2, "Monitor 27", "Hardware", "Perifericos" },
|
|
58
|
+
{ 3, "Dock USB-C", "Hardware", "Accesorios" },
|
|
59
|
+
{ 4, "Licencia BI", "Software", "Analytics" },
|
|
60
|
+
{ 5, "Soporte Premium", "Servicios", "Soporte" },
|
|
61
|
+
{ 6, "Implementacion", "Servicios", "Consultoria" },
|
|
62
|
+
{ 7, "Capacitacion", "Servicios", "Training" },
|
|
63
|
+
{ 8, "Integracion API", "Software", "Integraciones" }
|
|
64
|
+
}
|
|
65
|
+
),
|
|
66
|
+
#"Tipo cambiado" = Table.TransformColumnTypes(Source,{{"ProductoId", type text}, {"Producto", type text}, {"Categoria", type text}, {"Subcategoria", type text}})
|
|
67
|
+
in
|
|
68
|
+
#"Tipo cambiado"
|
|
69
|
+
|
|
70
|
+
annotation PBI_NavigationStepName = Navegación
|
|
71
|
+
|
|
72
|
+
annotation PBI_ResultType = Table
|
|
73
|
+
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/// Tabla helper sintética de tipos de cambio por fecha y moneda, cargada desde Power Query para validar patrones de conversión de moneda.
|
|
2
|
+
table 'Tipo de cambio'
|
|
3
|
+
isHidden
|
|
4
|
+
lineageTag: 876182f9-6e8d-495e-bf52-13fc9db4ffef
|
|
5
|
+
|
|
6
|
+
column Fecha
|
|
7
|
+
dataType: dateTime
|
|
8
|
+
isHidden
|
|
9
|
+
formatString: Long Date
|
|
10
|
+
lineageTag: a3b5f7ba-ec6d-40f8-a78e-49f5b2f89ec6
|
|
11
|
+
summarizeBy: none
|
|
12
|
+
sourceColumn: Fecha
|
|
13
|
+
|
|
14
|
+
annotation UnderlyingDateTimeDataType = Date
|
|
15
|
+
|
|
16
|
+
column Moneda
|
|
17
|
+
dataType: string
|
|
18
|
+
isHidden
|
|
19
|
+
lineageTag: 6c8a29b7-41d3-4f41-97b8-db3f5f3b1cdc
|
|
20
|
+
summarizeBy: none
|
|
21
|
+
sourceColumn: Moneda
|
|
22
|
+
|
|
23
|
+
column TipoCambioBase
|
|
24
|
+
dataType: double
|
|
25
|
+
formatString: #,0.00
|
|
26
|
+
lineageTag: f7a93c19-5278-4d38-ae49-fef3b8a53173
|
|
27
|
+
summarizeBy: none
|
|
28
|
+
sourceColumn: TipoCambioBase
|
|
29
|
+
|
|
30
|
+
partition TipoCambio = m
|
|
31
|
+
mode: import
|
|
32
|
+
queryGroup: 'Sample Dataset'
|
|
33
|
+
source =
|
|
34
|
+
let
|
|
35
|
+
BaseCurrency = Text.From(MonedaBase),
|
|
36
|
+
RatesUsd = #table(
|
|
37
|
+
type table [Moneda = text, TipoCambioUSD = number, VariacionDiaria = number],
|
|
38
|
+
{
|
|
39
|
+
{ "USD", 1.00, 0.00 },
|
|
40
|
+
{ "ARS", 1200.00, 0.15 },
|
|
41
|
+
{ "EUR", 0.92, 0.00005 }
|
|
42
|
+
}
|
|
43
|
+
),
|
|
44
|
+
Dates = Table.SelectColumns(Calendario, {"Fecha"}),
|
|
45
|
+
AddRates = Table.AddColumn(Dates, "Rates", each RatesUsd),
|
|
46
|
+
ExpandRates = Table.ExpandTableColumn(AddRates, "Rates", {"Moneda", "TipoCambioUSD", "VariacionDiaria"}, {"Moneda", "TipoCambioUSD", "VariacionDiaria"}),
|
|
47
|
+
AddRateUsd = Table.AddColumn(
|
|
48
|
+
ExpandRates,
|
|
49
|
+
"RateUsd",
|
|
50
|
+
each if [Moneda] = "USD" then 1.0 else [TipoCambioUSD] + (Duration.Days(Date.From([Fecha]) - #date(2025, 1, 1)) * [VariacionDiaria]),
|
|
51
|
+
type number
|
|
52
|
+
),
|
|
53
|
+
BaseRows = Table.SelectRows(AddRateUsd, each [Moneda] = BaseCurrency),
|
|
54
|
+
BaseRates = Table.RenameColumns(Table.SelectColumns(BaseRows, {"Fecha", "RateUsd"}), {{"RateUsd", "BaseRateUsd"}}),
|
|
55
|
+
JoinBase = Table.NestedJoin(AddRateUsd, {"Fecha"}, BaseRates, {"Fecha"}, "Base", JoinKind.LeftOuter),
|
|
56
|
+
ExpandBase = Table.ExpandTableColumn(JoinBase, "Base", {"BaseRateUsd"}, {"BaseRateUsd"}),
|
|
57
|
+
AddTipoCambioBase = Table.AddColumn(ExpandBase, "TipoCambioBase", each if [BaseRateUsd] = null or [BaseRateUsd] = 0 then [RateUsd] else [RateUsd] / [BaseRateUsd], type number),
|
|
58
|
+
Result = Table.SelectColumns(AddTipoCambioBase, {"Fecha", "Moneda", "TipoCambioBase"}),
|
|
59
|
+
#"Tipo cambiado" = Table.TransformColumnTypes(Result,{{"Moneda", type text}})
|
|
60
|
+
in
|
|
61
|
+
#"Tipo cambiado"
|
|
62
|
+
|
|
63
|
+
annotation PBI_NavigationStepName = Navegación
|
|
64
|
+
|
|
65
|
+
annotation PBI_ResultType = Table
|
|
66
|
+
|