This commit is contained in:
2026-04-25 17:31:15 +02:00
parent 25fb0364ac
commit 973c98723f
8 changed files with 780 additions and 164 deletions

View File

@@ -487,6 +487,39 @@ class Products
$sql .= ' AND ag.status = \'active\'';
}
static private function build_products_filters( &$sql, &$params, $search, $custom_label_4, $custom_label_1 )
{
$search = trim( (string) $search );
$custom_label_4 = trim( (string) $custom_label_4 );
$custom_label_1 = trim( (string) $custom_label_1 );
if ( $search !== '' )
{
$sql .= ' AND (
p.name LIKE :search
OR p.title LIKE :search
OR p.offer_id LIKE :search
OR p.custom_label_4 LIKE :search
OR p.custom_label_1 LIKE :search
OR c.campaign_name LIKE :search
OR ag.ad_group_name LIKE :search
)';
$params[':search'] = '%' . $search . '%';
}
if ( $custom_label_4 !== '' )
{
$sql .= ' AND p.custom_label_4 LIKE :custom_label_4';
$params[':custom_label_4'] = '%' . $custom_label_4 . '%';
}
if ( $custom_label_1 !== '' )
{
$sql .= ' AND p.custom_label_1 LIKE :custom_label_1';
$params[':custom_label_1'] = '%' . $custom_label_1 . '%';
}
}
static public function get_products( $client_id, $search, $limit, $start, $order_name, $order_dir, $campaign_id = 0, $ad_group_id = 0, $custom_label_4 = '', $custom_label_1 = '' )
{
global $mdb;
@@ -522,15 +555,17 @@ class Products
p.offer_id,
p.min_roas,
COALESCE( NULLIF( TRIM( p.custom_label_1 ), \'\' ), \'\' ) AS custom_label_1,
pa.campaign_id AS campaign_id,
COALESCE( NULLIF( TRIM( c.campaign_name ), \'\' ), \'--- brak kampanii ---\' ) AS campaign_name,
CASE
WHEN pa.ad_group_id = 0 THEN \'PMax (bez grup reklam)\'
ELSE COALESCE( NULLIF( TRIM( ag.ad_group_name ), \'\' ), \'--- brak grupy reklam ---\' )
WHEN COUNT( DISTINCT pa.campaign_id ) > 1 THEN CONCAT( \'Wiele kampanii (\', COUNT( DISTINCT pa.campaign_id ), \')\' )
ELSE COALESCE( NULLIF( TRIM( MAX( c.campaign_name ) ), \'\' ), \'--- brak kampanii ---\' )
END AS campaign_name,
CASE
WHEN COUNT( DISTINCT CONCAT( pa.campaign_id, \':\', pa.ad_group_id ) ) > 1 THEN CONCAT( \'Wiele grup (\', COUNT( DISTINCT CONCAT( pa.campaign_id, \':\', pa.ad_group_id ) ), \')\' )
WHEN MIN( pa.ad_group_id ) = 0 THEN \'PMax (bez grup reklam)\'
ELSE COALESCE( NULLIF( TRIM( MAX( ag.ad_group_name ) ), \'\' ), \'--- brak grupy reklam ---\' )
END AS ad_group_name,
pa.ad_group_id AS ad_group_id,
pa.campaign_id AS history_campaign_id,
pa.ad_group_id AS history_ad_group_id,
MIN( pa.campaign_id ) AS history_campaign_id,
MIN( pa.ad_group_id ) AS history_ad_group_id,
COALESCE( NULLIF( TRIM( p.title ), \'\' ), NULLIF( TRIM( p.name ), \'\' ), p.offer_id ) AS name,
SUM( pa.impressions_all_time ) AS impressions,
SUM( pa.impressions_30 ) AS impressions_30,
@@ -558,34 +593,9 @@ class Products
WHERE p.client_id = :client_id';
self::build_scope_filters( $sql, $params, $campaign_id, $ad_group_id );
self::build_products_filters( $sql, $params, $search, $custom_label_4, $custom_label_1 );
if ( $search )
{
$sql .= ' AND (
p.name LIKE :search
OR p.title LIKE :search
OR p.offer_id LIKE :search
OR p.custom_label_4 LIKE :search
OR p.custom_label_1 LIKE :search
OR c.campaign_name LIKE :search
OR ag.ad_group_name LIKE :search
)';
$params[':search'] = '%' . $search . '%';
}
if ( $custom_label_4 !== '' )
{
$sql .= ' AND p.custom_label_4 LIKE :custom_label_4';
$params[':custom_label_4'] = '%' . $custom_label_4 . '%';
}
if ( $custom_label_1 !== '' )
{
$sql .= ' AND p.custom_label_1 LIKE :custom_label_1';
$params[':custom_label_1'] = '%' . $custom_label_1 . '%';
}
$sql .= ' GROUP BY p.id, p.offer_id, p.min_roas, p.custom_label_1, p.name, p.title, pa.campaign_id, c.campaign_name, pa.ad_group_id, ag.ad_group_name';
$sql .= ' GROUP BY p.id, p.offer_id, p.min_roas, p.custom_label_1, p.name, p.title';
$sql .= ' ORDER BY ' . $order_sql . ' ' . $order_dir . ', product_id DESC LIMIT ' . $start . ', ' . $limit;
return $mdb -> query( $sql, $params ) -> fetchAll( \PDO::FETCH_ASSOC );
@@ -597,47 +607,30 @@ class Products
$params = [ ':client_id' => $client_id ];
$sql = 'SELECT MIN( p.min_roas ) AS min_roas,
MAX(
CASE
WHEN COALESCE( pa.cost_all_time, 0 ) > 0 THEN ROUND( COALESCE( pa.conversion_value_all_time, 0 ) / pa.cost_all_time * 100, 2 )
ELSE 0
END
) AS max_roas
FROM products_aggregate AS pa
INNER JOIN products AS p ON p.id = pa.product_id
LEFT JOIN campaigns AS c ON c.id = pa.campaign_id
LEFT JOIN campaign_ad_groups AS ag ON ag.id = pa.ad_group_id
WHERE p.client_id = :client_id
AND pa.conversions_all_time > 10';
$sql = 'SELECT
MIN( t.min_roas ) AS min_roas,
MAX( t.roas ) AS max_roas
FROM (
SELECT
p.id AS product_id,
p.min_roas AS min_roas,
CASE
WHEN SUM( pa.cost_all_time ) > 0 THEN ROUND( SUM( pa.conversion_value_all_time ) / SUM( pa.cost_all_time ) * 100, 2 )
ELSE 0
END AS roas,
SUM( pa.conversions_all_time ) AS conversions
FROM products_aggregate AS pa
INNER JOIN products AS p ON p.id = pa.product_id
LEFT JOIN campaigns AS c ON c.id = pa.campaign_id
LEFT JOIN campaign_ad_groups AS ag ON ag.id = pa.ad_group_id
WHERE p.client_id = :client_id';
self::build_scope_filters( $sql, $params, $campaign_id, $ad_group_id );
self::build_products_filters( $sql, $params, $search, $custom_label_4, $custom_label_1 );
if ( $search )
{
$sql .= ' AND (
p.name LIKE :search
OR p.title LIKE :search
OR p.offer_id LIKE :search
OR p.custom_label_4 LIKE :search
OR p.custom_label_1 LIKE :search
OR c.campaign_name LIKE :search
OR ag.ad_group_name LIKE :search
)';
$params[':search'] = '%' . $search . '%';
}
if ( $custom_label_4 !== '' )
{
$sql .= ' AND p.custom_label_4 LIKE :custom_label_4';
$params[':custom_label_4'] = '%' . $custom_label_4 . '%';
}
if ( $custom_label_1 !== '' )
{
$sql .= ' AND p.custom_label_1 LIKE :custom_label_1';
$params[':custom_label_1'] = '%' . $custom_label_1 . '%';
}
$sql .= ' GROUP BY p.id, p.min_roas
HAVING SUM( pa.conversions_all_time ) > 10
) AS t';
$row = $mdb -> query( $sql, $params ) -> fetch( \PDO::FETCH_ASSOC );
@@ -676,49 +669,103 @@ class Products
global $mdb;
$params = [ ':client_id' => (int) $client_id ];
$sql = 'SELECT COUNT(0)
FROM (
SELECT p.id
FROM products_aggregate AS pa
INNER JOIN products AS p ON p.id = pa.product_id
LEFT JOIN campaigns AS c ON c.id = pa.campaign_id
LEFT JOIN campaign_ad_groups AS ag ON ag.id = pa.ad_group_id
WHERE p.client_id = :client_id';
$sql = 'SELECT COUNT( DISTINCT p.id )
FROM products_aggregate AS pa
INNER JOIN products AS p ON p.id = pa.product_id
LEFT JOIN campaigns AS c ON c.id = pa.campaign_id
LEFT JOIN campaign_ad_groups AS ag ON ag.id = pa.ad_group_id
WHERE p.client_id = :client_id';
self::build_scope_filters( $sql, $params, $campaign_id, $ad_group_id );
if ( $search )
{
$sql .= ' AND (
p.name LIKE :search
OR p.title LIKE :search
OR p.offer_id LIKE :search
OR p.custom_label_4 LIKE :search
OR p.custom_label_1 LIKE :search
OR c.campaign_name LIKE :search
OR ag.ad_group_name LIKE :search
)';
$params[':search'] = '%' . $search . '%';
}
if ( $custom_label_4 !== '' )
{
$sql .= ' AND p.custom_label_4 LIKE :custom_label_4';
$params[':custom_label_4'] = '%' . $custom_label_4 . '%';
}
if ( $custom_label_1 !== '' )
{
$sql .= ' AND p.custom_label_1 LIKE :custom_label_1';
$params[':custom_label_1'] = '%' . $custom_label_1 . '%';
}
$sql .= ' GROUP BY p.id, pa.campaign_id, pa.ad_group_id
) AS grouped_rows';
self::build_products_filters( $sql, $params, $search, $custom_label_4, $custom_label_1 );
return $mdb -> query( $sql, $params ) -> fetchColumn();
}
static public function get_products_scope_breakdown( $client_id, $product_ids, $campaign_id = 0, $ad_group_id = 0, $search = '', $custom_label_4 = '', $custom_label_1 = '' )
{
global $mdb;
$product_ids = array_values( array_filter( array_map( 'intval', (array) $product_ids ) ) );
if ( empty( $product_ids ) )
{
return [];
}
$params = [ ':client_id' => (int) $client_id ];
$in_placeholders = [];
foreach ( $product_ids as $idx => $product_id )
{
$key = ':product_id_' . $idx;
$in_placeholders[] = $key;
$params[ $key ] = $product_id;
}
$sql = 'SELECT
pa.product_id,
pa.campaign_id,
pa.ad_group_id,
COALESCE( NULLIF( TRIM( c.campaign_name ), \'\' ), \'--- brak kampanii ---\' ) AS campaign_name,
CASE
WHEN pa.ad_group_id = 0 THEN \'PMax (bez grup reklam)\'
ELSE COALESCE( NULLIF( TRIM( ag.ad_group_name ), \'\' ), \'--- brak grupy reklam ---\' )
END AS ad_group_name,
SUM( pa.impressions_all_time ) AS impressions,
SUM( pa.impressions_30 ) AS impressions_30,
SUM( pa.clicks_all_time ) AS clicks,
SUM( pa.clicks_30 ) AS clicks_30,
CASE
WHEN SUM( pa.impressions_all_time ) > 0 THEN ROUND( SUM( pa.clicks_all_time ) / SUM( pa.impressions_all_time ) * 100, 2 )
ELSE 0
END AS ctr,
SUM( pa.cost_all_time ) AS cost,
CASE
WHEN SUM( pa.clicks_all_time ) > 0 THEN ROUND( SUM( pa.cost_all_time ) / SUM( pa.clicks_all_time ), 6 )
ELSE 0
END AS cpc,
SUM( pa.conversions_all_time ) AS conversions,
SUM( pa.conversion_value_all_time ) AS conversions_value,
CASE
WHEN SUM( pa.cost_all_time ) > 0 THEN ROUND( SUM( pa.conversion_value_all_time ) / SUM( pa.cost_all_time ) * 100, 2 )
ELSE 0
END AS roas
FROM products_aggregate AS pa
INNER JOIN products AS p ON p.id = pa.product_id
LEFT JOIN campaigns AS c ON c.id = pa.campaign_id
LEFT JOIN campaign_ad_groups AS ag ON ag.id = pa.ad_group_id
WHERE p.client_id = :client_id
AND pa.product_id IN (' . implode( ', ', $in_placeholders ) . ')';
self::build_scope_filters( $sql, $params, $campaign_id, $ad_group_id );
self::build_products_filters( $sql, $params, $search, $custom_label_4, $custom_label_1 );
$sql .= ' GROUP BY pa.product_id, pa.campaign_id, pa.ad_group_id, c.campaign_name, ag.ad_group_name
ORDER BY campaign_name ASC, ad_group_name ASC';
$rows = $mdb -> query( $sql, $params ) -> fetchAll( \PDO::FETCH_ASSOC );
$map = [];
foreach ( $rows as $row )
{
$product_id = (int) ( $row['product_id'] ?? 0 );
if ( $product_id <= 0 )
{
continue;
}
if ( !isset( $map[ $product_id ] ) )
{
$map[ $product_id ] = [];
}
$map[ $product_id ][] = $row;
}
return $map;
}
static public function get_product_full_context( $product_id )
{
global $mdb;