feat(brief): add product and landing_url to brief, map from campaign_products and inherit from source creative
This commit is contained in:
@@ -81,14 +81,37 @@ export async function POST(req: NextRequest) {
|
|||||||
|
|
||||||
const admin = getAdmin();
|
const admin = getAdmin();
|
||||||
|
|
||||||
// Get tenant slug
|
// Get tenant slug and maps
|
||||||
const { data: tenant } = await admin
|
const { data: tenant } = await admin
|
||||||
.from('tenants')
|
.from('tenants')
|
||||||
.select('slug, name, campaign_audience')
|
.select('slug, name, campaign_audience, campaign_products')
|
||||||
.eq('id', tenantId)
|
.eq('id', tenantId)
|
||||||
.maybeSingle();
|
.maybeSingle();
|
||||||
|
|
||||||
const campaignName = body.campaign_name || null;
|
// Si viene source_creative_id, obtener datos de la creatividad fatigada
|
||||||
|
let creativeCampaignName: string | null = null;
|
||||||
|
let creativeAdsetId: string | null = null;
|
||||||
|
let creativeAngle: string | null = null;
|
||||||
|
|
||||||
|
if (body.source_creative_id) {
|
||||||
|
const { data: srcCreative } = await admin
|
||||||
|
.from('creatives')
|
||||||
|
.select('campaign_name, adset_id, angle')
|
||||||
|
.eq('id', body.source_creative_id)
|
||||||
|
.eq('tenant_id', tenantId)
|
||||||
|
.maybeSingle();
|
||||||
|
|
||||||
|
if (srcCreative) {
|
||||||
|
creativeCampaignName = srcCreative.campaign_name || null;
|
||||||
|
creativeAdsetId = srcCreative.adset_id || null;
|
||||||
|
creativeAngle = srcCreative.angle || null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Priorizar campaign_name y adset_id de la creatividad de origen si existe
|
||||||
|
const campaignName = creativeCampaignName || body.campaign_name || null;
|
||||||
|
const adsetId = creativeAdsetId || body.adset_id || null;
|
||||||
|
|
||||||
const campaignAudienceMap = (tenant as any)?.campaign_audience || {};
|
const campaignAudienceMap = (tenant as any)?.campaign_audience || {};
|
||||||
let audience: 'b2b' | 'b2c' | null = body.audience || null;
|
let audience: 'b2b' | 'b2c' | null = body.audience || null;
|
||||||
if (!audience && campaignName && campaignAudienceMap && typeof campaignAudienceMap === 'object' && campaignAudienceMap[campaignName]) {
|
if (!audience && campaignName && campaignAudienceMap && typeof campaignAudienceMap === 'object' && campaignAudienceMap[campaignName]) {
|
||||||
@@ -98,6 +121,22 @@ export async function POST(req: NextRequest) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const campaignProductsMap = (tenant as any)?.campaign_products || {};
|
||||||
|
let product: string | null = body.product || null;
|
||||||
|
let landingUrl: string | null = body.landing_url || null;
|
||||||
|
|
||||||
|
if (campaignName && campaignProductsMap && typeof campaignProductsMap === 'object' && campaignProductsMap[campaignName]) {
|
||||||
|
const pVal = campaignProductsMap[campaignName];
|
||||||
|
if (typeof pVal === 'string') {
|
||||||
|
if (!product) product = pVal;
|
||||||
|
} else if (typeof pVal === 'object' && pVal !== null) {
|
||||||
|
if (!product) product = pVal.product ? String(pVal.product) : null;
|
||||||
|
if (!landingUrl) landingUrl = pVal.landing_url ? String(pVal.landing_url) : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const avoidAngles = body.avoid_angles || (creativeAngle ? [creativeAngle] : []);
|
||||||
|
|
||||||
const brief = {
|
const brief = {
|
||||||
tenant_id: tenantId,
|
tenant_id: tenantId,
|
||||||
client_id: tenantId,
|
client_id: tenantId,
|
||||||
@@ -107,8 +146,11 @@ export async function POST(req: NextRequest) {
|
|||||||
format: body.format || 'estatico',
|
format: body.format || 'estatico',
|
||||||
variants_requested: Number(body.variants_requested || 3),
|
variants_requested: Number(body.variants_requested || 3),
|
||||||
campaign_name: campaignName,
|
campaign_name: campaignName,
|
||||||
adset_id: body.adset_id || null,
|
adset_id: adsetId,
|
||||||
audience,
|
audience,
|
||||||
|
product,
|
||||||
|
landing_url: landingUrl,
|
||||||
|
avoid_angles: avoidAngles,
|
||||||
notes: body.notes || null,
|
notes: body.notes || null,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -108,10 +108,10 @@ export async function GET(
|
|||||||
topCreatives = fallbackRows || [];
|
topCreatives = fallbackRows || [];
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5. Obtener datos del cliente (drive_folder_id, slug, nombre)
|
// 5. Obtener datos del cliente (drive_folder_id, slug, nombre, mapas)
|
||||||
const { data: tenant } = await adminClient
|
const { data: tenant } = await adminClient
|
||||||
.from('tenants')
|
.from('tenants')
|
||||||
.select('id, name, slug, drive_folder_id, meta_ad_account_id')
|
.select('id, name, slug, drive_folder_id, meta_ad_account_id, campaign_audience, campaign_products')
|
||||||
.eq('id', tenantId)
|
.eq('id', tenantId)
|
||||||
.maybeSingle();
|
.maybeSingle();
|
||||||
|
|
||||||
@@ -127,6 +127,8 @@ export async function GET(
|
|||||||
name: tenant?.name || null,
|
name: tenant?.name || null,
|
||||||
slug: tenant?.slug || null,
|
slug: tenant?.slug || null,
|
||||||
drive_folder_id: tenant?.drive_folder_id || null,
|
drive_folder_id: tenant?.drive_folder_id || null,
|
||||||
|
campaign_audience: (tenant as any)?.campaign_audience || {},
|
||||||
|
campaign_products: (tenant as any)?.campaign_products || {},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ export async function POST(req: NextRequest) {
|
|||||||
// 1. Obtener la creatividad a marcar
|
// 1. Obtener la creatividad a marcar
|
||||||
const { data: creative, error: getErr } = await adminClient
|
const { data: creative, error: getErr } = await adminClient
|
||||||
.from('creatives')
|
.from('creatives')
|
||||||
.select('*, tenant:tenants(slug, name, campaign_audience)')
|
.select('*, tenant:tenants(slug, name, campaign_audience, campaign_products)')
|
||||||
.eq('id', creativeId)
|
.eq('id', creativeId)
|
||||||
.eq('tenant_id', tenantId)
|
.eq('tenant_id', tenantId)
|
||||||
.maybeSingle();
|
.maybeSingle();
|
||||||
@@ -79,7 +79,11 @@ export async function POST(req: NextRequest) {
|
|||||||
const avoidAngles = creative.angle ? [creative.angle] : [];
|
const avoidAngles = creative.angle ? [creative.angle] : [];
|
||||||
const clientSlug = (creative.tenant as any)?.slug || 'bps';
|
const clientSlug = (creative.tenant as any)?.slug || 'bps';
|
||||||
const campaignAudienceMap = (creative.tenant as any)?.campaign_audience || {};
|
const campaignAudienceMap = (creative.tenant as any)?.campaign_audience || {};
|
||||||
const campaignName = creative.campaign_name || '';
|
const campaignProductsMap = (creative.tenant as any)?.campaign_products || {};
|
||||||
|
|
||||||
|
// campaign_name y adset_id tomados directamente de la creatividad fatigada
|
||||||
|
const campaignName = creative.campaign_name || null;
|
||||||
|
const adsetId = creative.adset_id || null;
|
||||||
|
|
||||||
let audience: 'b2b' | 'b2c' | null = null;
|
let audience: 'b2b' | 'b2c' | null = null;
|
||||||
if (campaignName && campaignAudienceMap && typeof campaignAudienceMap === 'object' && campaignAudienceMap[campaignName]) {
|
if (campaignName && campaignAudienceMap && typeof campaignAudienceMap === 'object' && campaignAudienceMap[campaignName]) {
|
||||||
@@ -89,6 +93,18 @@ export async function POST(req: NextRequest) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let product: string | null = null;
|
||||||
|
let landingUrl: string | null = null;
|
||||||
|
if (campaignName && campaignProductsMap && typeof campaignProductsMap === 'object' && campaignProductsMap[campaignName]) {
|
||||||
|
const pVal = campaignProductsMap[campaignName];
|
||||||
|
if (typeof pVal === 'string') {
|
||||||
|
product = pVal;
|
||||||
|
} else if (typeof pVal === 'object' && pVal !== null) {
|
||||||
|
product = pVal.product ? String(pVal.product) : null;
|
||||||
|
landingUrl = pVal.landing_url ? String(pVal.landing_url) : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const deadline = new Date();
|
const deadline = new Date();
|
||||||
deadline.setDate(deadline.getDate() + 1); // 24 horas después
|
deadline.setDate(deadline.getDate() + 1); // 24 horas después
|
||||||
|
|
||||||
@@ -102,9 +118,11 @@ export async function POST(req: NextRequest) {
|
|||||||
aspect_ratio: '4:5',
|
aspect_ratio: '4:5',
|
||||||
variants_requested: 2,
|
variants_requested: 2,
|
||||||
avoid_angles: avoidAngles,
|
avoid_angles: avoidAngles,
|
||||||
campaign_name: creative.campaign_name || 'General',
|
campaign_name: campaignName,
|
||||||
adset_id: creative.adset_id || null,
|
adset_id: adsetId,
|
||||||
audience,
|
audience,
|
||||||
|
product,
|
||||||
|
landing_url: landingUrl,
|
||||||
language: 'es',
|
language: 'es',
|
||||||
deadline: deadline.toISOString(),
|
deadline: deadline.toISOString(),
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user