{% extends "layouts/base.twig" %} {% block title %}{{ translations.benchmark_my_products_analysis ?? 'My products price analysis' }}{% endblock %} {% block head %} {% endblock %} {% block page_heading %}

{{ translations.benchmark_my_products_analysis ?? 'My products price analysis' }}

{{ translations.period ?? 'Period' }}: {{ date_from }}{{ date_to }} {% if analyse and analyse.getKpi and analyse.getKpi().getLastObservationDate %} • {{ translations.last_observation ?? 'Last observation' }}: {{ analyse.getKpi().getLastObservationDate() }} {% endif %}

{% endblock %} {% block content %} {% set kpi = analyse.getKpi() %} {% set products = analyse.getProducts() %} {% set breakdown = breakdown %} {# --- helpers: formatowanie --- #} {% macro money(v) %} {% if v is null %}{% else %}€ {{ v|number_format(2, '.', ' ') }}{% endif %} {% endmacro %} {% macro perc(v) %} {% if v is null %}{% else %}{{ v|number_format(2, '.', ' ') }}%{% endif %} {% endmacro %} {% macro gapClass(v) %} {% if v is null %}gap-zero{% elseif v > 0 %}gap-up{% elseif v < 0 %}gap-down{% else %}gap-zero{% endif %} {% endmacro %} {% import _self as fmt %} {# --- INSIGHTS + INFO CARDS OBOK --- #}
{{ translations.insights ?? 'Insights' }}
{{ translations.insights_hint ?? 'Quick overview: biggest overpricing / underpricing vs competitor minimum.' }}
{{ translations.products ?? 'Products' }}: {{ products|length }} {{ translations.breakdown_rows ?? 'Breakdown rows' }}: {{ breakdown|length }}
{% set topOver = [] %} {% set topUnder = [] %} {% for p in products %} {% if p.getGapVsMinPercent() is not null %} {% if p.getGapVsMinPercent() < 0 %} {% set topOver = topOver|merge([p]) %} {% elseif p.getGapVsMinPercent() > 0 %} {% set topUnder = topUnder|merge([p]) %} {% endif %} {% endif %} {% endfor %}
{{ translations.top_overpriced ?? 'Top overpriced vs competitor minimum' }}
{{ translations.top_overpriced_hint ?? 'Most negative gap_vs_min_percent.' }}
{% if topOver|length == 0 %}
{{ translations.no_data ?? 'No data' }}
{% else %}
{% for p in topOver|slice(0,5) %}
{{ p.getMyProductName() }}
#{{ p.getMyProductId() }} • {{ translations.last_seen ?? 'Last seen' }}: {{ p.getLastSeen() }}
{{ fmt.perc(p.getGapVsMinPercent()) }}
{{ fmt.money(p.getGapVsMinAmount()) }}
{% endfor %}
{% endif %}
{{ translations.top_underpriced ?? 'Top underpriced vs competitor minimum' }}
{{ translations.top_underpriced_hint ?? 'Most positive gap_vs_min_percent.' }}
{% if topUnder|length == 0 %}
{{ translations.no_data ?? 'No data' }}
{% else %}
{% for p in topUnder|slice(0,5) %}
{{ p.getMyProductName() }}
#{{ p.getMyProductId() }} • {{ translations.last_seen ?? 'Last seen' }}: {{ p.getLastSeen() }}
{{ fmt.perc(p.getGapVsMinPercent()) }}
{{ fmt.money(p.getGapVsMinAmount()) }}
{% endfor %}
{% endif %}
{{ translations.how_to_read ?? 'How to read' }}: {{ translations.how_to_read_text ?? 'gap_vs_min is computed against the minimum competitor price observed for this product in the period. Breakdown below shows competitor-by-competitor gaps.' }}
{# ✅ Cards z pojedynczymi informacjami obok Insights — wersja PRO (Mazer vibe) #}
{# Products #}
{{ translations.products ?? 'Products' }}
{{ translations.products_hint_short ?? 'Products in analysis.' }}
{{ translations.tracked ?? 'Tracked' }}
{{ products|length }}
{{ translations.tracked_products ?? 'Tracked products' }}: {{ kpi.getTrackedProducts() }}
{{ translations.comparisons ?? 'Comparisons' }}: {{ kpi.getComparisonsCount() }} {{ translations.competitors ?? 'Competitors' }}: {{ kpi.getCoveredCompetitors() }}
{# Breakdown rows #}
{{ translations.breakdown_rows ?? 'Breakdown rows' }}
{{ translations.breakdown_rows_hint ?? 'Rows used for competitor comparisons.' }}
{{ translations.rows ?? 'Rows' }}
{{ breakdown|length }}
{{ translations.avg_gap_percent ?? 'Avg gap %' }}: {{ fmt.perc(kpi.getAvgGapPercent()) }}
{{ translations.used ?? 'Used' }}: {{ kpi.getComparisonsCount() }} {{ translations.coverage ?? 'Coverage' }}: {{ kpi.getCoveredCompetitors() }}
{# Freshness #}
{{ translations.freshness ?? 'Freshness' }}
{{ translations.freshness_hint ?? 'Days since last observation.' }}
{{ translations.days ?? 'days' }}
{{ kpi.getFreshnessDays() }}
{{ translations.last_observation ?? 'Last observation' }}
{{ kpi.getLastObservationDate() }} {{ translations.period ?? 'Period' }}: {{ date_from }}{{ date_to }}
{# Last observation (date focus) #}
{{ translations.last_observation ?? 'Last observation' }}
{{ translations.last_observation_hint ?? 'Last usable observation date.' }}
{{ translations.source ?? 'Source' }}
{{ kpi.getLastObservationDate() }}
{{ translations.covered_competitors ?? 'Covered competitors' }}: {{ kpi.getCoveredCompetitors() }}
{{ translations.freshness ?? 'Freshness' }}: {{ kpi.getFreshnessDays() }} {{ translations.days ?? 'days' }} {{ translations.comparisons ?? 'Comparisons' }}: {{ kpi.getComparisonsCount() }}
{# ✅ FILTERS przeniesione między Insights a tabelę Products (poziomo, szerokość jak tabela) #}
{{ translations.filters ?? 'Filters' }}
{{ translations.gap_explained ?? 'Gap is computed as (competitor - my). Negative means you are more expensive.' }}
{# --- Products table --- #}
{{ translations.products ?? 'Products' }}
{{ translations.products_hint ?? 'Complete product list with competitor min/avg/max and gap vs min. Click a row to view competitor breakdown.' }}
{# ✅ colgroup + table-layout: fixed = stabilne szerokości #} {% for p in products %} {% set gapPerc = p.getGapVsMinPercent() %} {% set gapAmt = p.getGapVsMinAmount() %} {% set gapCls = fmt.gapClass(gapAmt) %} {# --- Breakdown collapse for this product --- #} {% endfor %}
{{ translations.product ?? 'Product' }} {{ translations.my_price ?? 'My price' }} {{ translations.comp_min ?? 'Comp. min' }} {{ translations.comp_avg ?? 'Comp. avg' }} {{ translations.comp_max ?? 'Comp. max' }} {{ translations.competitors ?? 'Competitors' }} {{ translations.comparisons ?? 'Comparisons' }} {{ translations.promo_hits ?? 'Promo hits' }} {{ translations.last_seen ?? 'Last seen' }} {{ translations.gap_vs_min ?? 'Gap vs min' }}
{{ p.getMyProductName() }}
#{{ p.getMyProductId() }} {% if p.getMissingProductRow() %} • {{ translations.missing_product_row ?? 'Missing product row' }} {% endif %} {% if p.getMissingMyPriceSource() %} • {{ translations.missing_my_price_source ?? 'Missing my price source' }} {% endif %}
{{ fmt.money(p.getMyPrice()) }} {{ fmt.money(p.getCompetitorMinPrice()) }} {{ fmt.money(p.getCompetitorAvgPrice()) }} {{ fmt.money(p.getCompetitorMaxPrice()) }} {{ p.getCompetitorsCount() }} {{ p.getComparisonsCount() }} {% if p.getPromoHits() > 0 %} {{ p.getPromoHits() }} {% else %} 0 {% endif %} {{ p.getLastSeen() }}
{{ fmt.perc(gapPerc) }}
{{ fmt.money(gapAmt) }}
{{ translations.competitor_breakdown ?? 'Competitor breakdown' }} — {{ p.getMyProductName() }}
{{ translations.breakdown_hint ?? 'Gap = (competitor - my). Positive means competitor is more expensive. Negative means you are more expensive.' }}
{{ translations.my_price ?? 'My price' }}: {{ fmt.money(p.getMyPrice()) }}
{% set hasRows = false %} {% for b in breakdown %} {% if b.getMyProductId() == p.getMyProductId() %} {% set hasRows = true %} {% set cls = fmt.gapClass(b.getGapAmount()) %} {% endif %} {% endfor %} {% if not hasRows %} {% endif %}
{{ translations.competitor ?? 'Competitor' }} {{ translations.last_seen ?? 'Last seen' }} {{ translations.competitor_price_used ?? 'Competitor price' }} {{ translations.my_price ?? 'My price' }} {{ translations.gap ?? 'Gap' }}
{{ b.getCompetitorName() }}
#{{ b.getCompetitorId() }}
{{ b.getLastSeen() }} {{ fmt.money(b.getCompetitorPriceUsed()) }} {{ fmt.money(b.getMyPrice()) }}
{{ fmt.perc(b.getGapPercent()) }}
{{ fmt.money(b.getGapAmount()) }}
{{ translations.no_breakdown_for_product ?? 'No breakdown rows found for this product.' }}
{% endblock %} {% block scripts %} {% endblock %}