Código

// Função auxiliar para formatar datas no padrão DD/MM/YYYY
function formatDate(dateString) {
  if (!dateString) return null;
  const date = new Date(dateString);
  if (isNaN(date)) return null;
  const day = String(date.getDate()).padStart(2, '0');
  const month = String(date.getMonth() + 1).padStart(2, '0');
  const year = date.getFullYear();
  return `${day}/${month}/${year}`;
}
 
// Função auxiliar para calcular idade
function calculateAge(dateString) {
  if (!dateString) return null;
  const date = new Date(dateString);
  if (isNaN(date)) return null;
  const today = DateTime.now().startOf('day');
  let age = today.year - date.getFullYear();
  if (
    today.month < date.getMonth() + 1 ||
    (today.month === date.getMonth() + 1 && today.day < date.getDate())
  ) {
    age--;
  }
  return age;
}
 
// Função auxiliar para extrair nomes
function extractNames(fullName) {
  if (!fullName) return { firstName: '', lastName: '' };
  const parts = fullName.trim().split(/\s+/);
  const firstName = parts[0] || '';
  const lastName = parts.length > 1 ? parts.slice(1).join(' ') : '';
  return { firstName, lastName };
}
 
const user = $json;
const lead = user.lead;
 
const birthDate = user.birthDate;
const formattedDate = formatDate(birthDate);
const age = calculateAge(birthDate);
const { firstName, lastName } = extractNames(user.name);
 
function formatPhone(phone) {
  return phone ? phone.replace('+55', '') : '';
}
 
const formattedUser = {
  cpf: user.cpf,
  uid: user.uid,
  full_name: user.name,
  phone: formatPhone(user.whatsappNumber),
  email: user.email,
  last_access: user.lastAccess,
  notification_token: user.notificationToken,
  is_valid_lead: user.isValidLead,
  is_hard_bounced: user.isHardBounced,
  has_active_follow_up: null,
  ban_expiration_date: user.banExpirationDate,
  has_recently_finished_follow_up: null,
  exists: true,
  address: user.address,
};
 
// Função para mapear registries sem mutar array externo
function mapRegistries(lead) {
  if (!lead?.loansDetails || !Array.isArray(lead.loansDetails) || lead.loansDetails.length < 1) return null;
  const registriesFound = new Set();
  return lead.loansDetails.map((l) => {
    const registry = l.Matricula;
    if (!registry || registriesFound.has(registry.Numero)) {
      return null;
    }
    registriesFound.add(registry.Numero);
    return {
    "covenant": 
      {
        "acronym": $('SubWorkflow: ID Covenant').first().json.convenioAcronimo,
    },
      registry_number: registry.Numero,
      occupancy: registry.Lotacao,
      salary: l.Salario,
      employee_type: {
        description: registry.DescricaoVinculoServidor,
      },
      department: {
        description: registry.Secretaria,
      },
      margins: {
        total_loan_margin: l.MargemTotal,
        available_loan_margin: l.MargemDisponivel,
        total_clt_margin: null,
        available_clt_margin: null,
        reserved_loan_margin: null,
        total_credit_card_margin: null,
        available_credit_card_margin: null,
        reserved_credit_card_margin: null,
        available_compulsory_margin: l.LimiteDisponivelCartaoConsignado,
        total_compulsory_margin: l.LimiteTotalCartaoConsignado,
        reserved_compulsory_margin: null,
        total_assistencial_benefit_margin: null,
        available_assistencial_benefit_margin: null,
        total_purchase_benefit_card_margin: null,
        available_purchase_benefit_card_margin: null,
        reserved_purchase_benefit_card_margin: null,
        total_withdraw_benefit_card_margin: l.LimiteTotalCartaoBeneficios,
        available_withdraw_benefit_card_margin: l.LimiteDisponivelCartaoBeneficios,
        reserved_withdraw_benefit_card_margin: null,
      },
      inss: {
        has_legal_representative: registry.PossuiRepresentanteLegal ?? null,
        is_elegible_for_loan: registry.ElegivelEmprestimo ?? null,
        is_released_for_loan: registry.LiberadoEmprestimo ?? null,
        benefit_kind: {
          code: registry.CodigoEspecieBeneficio ?? null,
          description: null,
        },
        alimony: {
          hasAlimony: registry.PossuiPensaoAlimenticia ?? null,
          code: null,
          description: null,
        },
      },
      clt: {
        admission_date: registry.DataAdmissao ?? null,
        is_elegible_for_loan: null,
      },
      mode: "app",
      created_at: null,
      updated_at: null,
      last_hygienization_date: null
    };
  }).filter(Boolean);
}
 
return {
    user: formattedUser,
    cpf: user.cpf,
    opportunities: {},
    proposals: {},
    name: user.name,
    first_name: firstName,
    last_name: lastName,
    birthdate: formattedDate,
    age,
    random_email: user.cpf ? `email_aleatorio_${user.cpf}@konsi.dev` : null,
    phones: [
      {
        number: formatPhone(user.whatsappNumber),
        importance: 1,
        data_origin: 'app',
      },
    ],
    emails: [
      {
        email: user.email,
        importance: 1,
        data_origin: 'app',
      },
    ],
    registries: mapRegistries(lead),
};

Saídas

  • Objeto UnifiedLead completo com estrutura padronizada contendo:
    • user: Dados formatados do usuário
    • cpf, name, first_name, last_name: Identificação
    • birthdate, age: Dados demográficos
    • phones, emails: Arrays de contatos
    • registries: Array de matrículas/vínculos formatados
    • opportunities, proposals: Objetos vazios (preenchidos depois)

Descrição adicional

Transforma dados do usuário do formato do app para o formato UnifiedLead padronizado. Realiza:

  • Formatação de datas (DD/MM/YYYY)
  • Cálculo de idade
  • Extração de primeiro/último nome
  • Formatação de telefone (remove +55)
  • Mapeamento de registries com todas as margens e dados de vínculo
  • Criação de email aleatório para testes

Relações

← Recebe de: 19-flow-variable---set-user-app-data → Envia para: 21-flow-variable---set-unified-lead

Observações

  • Usa DateTime do Luxon para cálculo de idade
  • Remove duplicatas de registries usando Set
  • Preenche estrutura completa de margens mesmo quando alguns valores são null