147 lines
4.8 KiB
JavaScript
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
|
|
};
|
|
};
|