testes/src_2/features/financeiro-cnab/hooks/useGerarRemessa.js

147 lines
4.8 KiB
JavaScript

import { useState, useCallback } from 'react';
import { toast } from 'sonner';
import cnabService from '../services/cnabService';
/**
* @typedef {Object} MappingSchema
* @property {string} key
* @property {string} label
* @property {boolean} required
*/
const MODEL_SCHEMAS = {
PIX: [
{ key: 'NOME_FAVORECIDO', label: 'Nome Favorecido', required: true },
{ key: 'CPF_CNPJ_FAVORECIDO', label: 'CPF/CNPJ', required: true },
{ key: 'TIPO_CHAVE_PIX', label: 'Tipo Chave Pix', required: true },
{ key: 'CHAVE_PIX', label: 'Chave Pix', required: true },
{ key: 'VALOR_PAGAMENTO', label: 'Valor', required: true }
],
TED: [
{ key: 'NOME_FAVORECIDO', label: 'Nome Favorecido', required: true },
{ key: 'CPF_CNPJ_FAVORECIDO', label: 'CPF/CNPJ', required: true },
{ key: 'BANCO_FAVORECIDO', label: 'Banco', required: true },
{ key: 'AGENCIA_FAVORECIDA', label: 'Agência', required: true },
{ key: 'CONTA_FAVORECIDA', label: 'Conta', required: true },
{ key: 'DIGITO_CONTA_FAVORECIDA', label: 'Dígito Conta', required: true },
{ key: 'TIPO_CONTA_FAVORECIDA', label: 'Tipo Conta', required: true },
{ key: 'FINALIDADE_TED', label: 'Finalidade', required: true },
{ key: 'VALOR_PAGAMENTO', label: 'Valor', required: true }
]
};
/**
* Hook customizado para lógica de geração de remessa CNAB
*/
export const useGerarRemessa = () => {
const [step, setStep] = useState('upload'); // upload | mapping | validate | success
const [paymentType, setPaymentType] = useState('TED');
const [loading, setLoading] = useState(false);
// Dados do arquivo
const [rawHeaders, setRawHeaders] = useState([]);
const [rawData, setRawData] = useState([]);
const [columnMapping, setColumnMapping] = useState({});
const [data, setData] = useState([]);
/**
* Processa o upload do arquivo
*/
const handleUpload = useCallback(async (file) => {
setLoading(true);
try {
const result = await cnabService.uploadAndParseExcel(file, paymentType);
setRawHeaders(result.headers);
setRawData(result.rows);
// Sugestão automática de mapeamento baseada em nomes similares
const newMapping = {};
const clean = (s) => s.toLowerCase().replace(/[^a-z]/g, '');
MODEL_SCHEMAS[paymentType].forEach(field => {
const match = result.headers.find(h =>
clean(h).includes(clean(field.key.split('_')[0])) ||
clean(h).includes(clean(field.label.split(' ')[0]))
);
if (match) newMapping[field.key] = match;
});
setColumnMapping(newMapping);
setStep('mapping');
toast.success('Arquivo processado. Verifique o mapeamento.');
} catch (error) {
toast.error('Erro ao processar arquivo.');
} finally {
setLoading(false);
}
}, [paymentType]);
/**
* Confirma o mapeamento e prepara dados para validação
*/
const confirmMapping = useCallback(() => {
const mappedData = rawData.map(row => {
const newRow = { id: row.id };
MODEL_SCHEMAS[paymentType].forEach(field => {
const sourceCol = columnMapping[field.key];
newRow[field.key] = sourceCol ? row[sourceCol] : '';
});
return newRow;
});
setData(mappedData);
setStep('validate');
}, [rawData, columnMapping, paymentType]);
/**
* Edita uma célula individualmente
*/
const updateCell = useCallback((rowId, field, value) => {
setData(prev => prev.map(item => item.id === rowId ? { ...item, [field]: value } : item));
}, []);
/**
* Finaliza e gera o arquivo .REM
*/
const finalize = useCallback(async () => {
setLoading(true);
try {
const result = await cnabService.generateRemessa(data);
if (result.success) {
setStep('success');
toast.success('Arquivo de remessa gerado com sucesso!');
}
} catch (error) {
toast.error('Falha na geração do arquivo.');
} finally {
setLoading(false);
}
}, [data]);
const reset = useCallback(() => {
setStep('upload');
setData([]);
setRawData([]);
setColumnMapping({});
}, []);
return {
step,
setStep,
paymentType,
setPaymentType,
loading,
rawHeaders,
rawData,
columnMapping,
setColumnMapping,
data,
handleUpload,
confirmMapping,
updateCell,
finalize,
reset,
schemas: MODEL_SCHEMAS
};
};