<?php
namespace App\Controller;
use App\Entity\LogArchivos;
use App\Entity\LogArchivosImportacionDetalle;
use App\Entity\LogRechazadosDebitosAutomaticosDet;
use App\Repository\ComprobantesRepository;
use App\Repository\RecibosRepository;
use App\Service\ArrayAdapter;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\Persistence\ManagerRegistry as PersistenceManagerRegistry;
use phpDocumentor\Reflection\Types\Boolean;
use Sonata\AdminBundle\Templating\TemplateRegistryInterface;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\FileType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Validator\Constraints\File;
use Symfony\Component\HttpFoundation\File\File as FileFile;
use DateTime;
class SiteController extends AbstractController
{
private TemplateRegistryInterface $templateRegistry;
protected $container;
public function __construct(
ContainerInterface $container,
TemplateRegistryInterface $templateRegistry,
private ComprobantesRepository $comprobantesRepository,
private RecibosRepository $recibosRepository,
private PersistenceManagerRegistry $doctrine,
private ArrayAdapter $arrayAdapter,
private RecibosAdminController $recibosAdminController,
private EntityManagerInterface $entityManager,
private RequestStack $requestStack
)
{
$this->container = $container;
$this->templateRegistry = $templateRegistry;
}
/**
* @Route("/", name="index")
*/
public function index(): Response
{
return $this->redirectToRoute('sonata_admin_dashboard');
}
#[Route('/admin/archivos/exportar', name: 'app_archivos_exportar', methods: ['GET', 'POST'])]
public function exportarArchivos(Request $request)
{
$this->denyAccessUnlessGranted('ROLE_ARCHIVOS_EXP_IMP');
$fechaActual = new \DateTime();
$anioActual = date_format($fechaActual, 'Y');
$mesActual = date_format($fechaActual, 'n'); //NUMERO DEL MES SIN 0 PARA LOS MESES DE UN DIGITO
$form = $this->createFormBuilder()
->add('tipo', ChoiceType::class, [
'choices' => [
'Por tarjeta' => 'tarjeta',
'Por CBU' => 'cbu',
'Por planilla' => 'planilla',
],
"attr" => ['class' => "form-control"]
])
->add('organismo', EntityType::class, ['class' => 'App\Entity\Organismos', "attr" => ['class' => "form-control"], 'placeholder' => 'Todos', 'required' => false])
->add('tarjeta', EntityType::class, ['class' => 'App\Entity\Tarjetas', "attr" => ['class' => "form-control"]])
->add('periodoMes', ChoiceType::class, [
'choices' => [
'1' => '1',
'2' => '2',
'3' => '3',
'4' => '4',
'5' => '5',
'6' => '6',
'7' => '7',
'8' => '8',
'9' => '9',
'10' => '10',
'11' => '11',
'12' => '12',
],
'data' => $mesActual,
'label' => 'Mes'
])
->add('periodoAnio', ChoiceType::class, [
'choices' => [
$anioActual - 1 => $anioActual - 1,
$anioActual => $anioActual,
$anioActual + 1 => $anioActual + 1,
],
'data' => $anioActual,
'label' => 'Año'
])
->add('exportar', SubmitType::class, array('label' => 'Exportar', "attr" => array('class' => "btn btn-success")))
->getForm();
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) { // si el formulario es valido
$params = $form->getData();
$this->grabarLog('exportacion', $params);
if ($params['tipo'] == 'tarjeta') {
$comprobantesDebitoAutomaticoTarjeta = $this->comprobantesRepository->getComprobantesDebitoAutomaticoTarjeta($params['periodoMes'], $params['periodoAnio'], $params['tarjeta']->getId());
if ($comprobantesDebitoAutomaticoTarjeta) {
return $this->generarArchivo($comprobantesDebitoAutomaticoTarjeta, $params);
} else {
$this->addFlash('error', '¡No existen comprobantes para los filtros aplicados!');
}
$vars = array(
'form' => $form->createView(),
'base_template' => $this->templateRegistry->getTemplate('layout'),
);
return $this->render('\archivos\exportar.html.twig', $vars);
}
} else {
$vars = array(
'form' => $form->createView(),
'base_template' => $this->templateRegistry->getTemplate('layout'),
);
return $this->render('\archivos\exportar.html.twig', $vars);
}
}
#[Route('/admin/archivos/importar', name: 'app_archivos_importar', methods: ['GET', 'POST'])]
public function importarArchivos(Request $request)
{
$this->denyAccessUnlessGranted('ROLE_ARCHIVOS_EXP_IMP');
$fechaActual = new \DateTime();
$anioActual = date_format($fechaActual, 'Y');
$mesActual = date_format($fechaActual, 'n'); // NUMERO DEL MES SIN 0 PARA LOS MESES DE UN DIGITO
$tipoPuntoVenta = 1; // ENTRENAMIENTO
$form = $this->createFormBuilder()
->add('tipo', ChoiceType::class, [
'choices' => [
'Por tarjeta' => 'tarjeta',
'Por CBU' => 'cbu',
'Por planilla' => 'planilla',
],
"attr" => ['class' => "form-control"]
])
->add('organismo', EntityType::class, ['class' => 'App\Entity\Organismos', "attr" => ['class' => "form-control"], 'placeholder' => 'Todos', 'required' => false])
->add('tarjeta', EntityType::class, ['class' => 'App\Entity\Tarjetas', "attr" => ['class' => "form-control"]])
->add('periodoMes', ChoiceType::class, [
'choices' => [
'1' => '1',
'2' => '2',
'3' => '3',
'4' => '4',
'5' => '5',
'6' => '6',
'7' => '7',
'8' => '8',
'9' => '9',
'10' => '10',
'11' => '11',
'12' => '12',
],
'data' => $mesActual,
'label' => 'Mes'
])
->add('periodoAnio', ChoiceType::class, [
'choices' => [
$anioActual - 1 => $anioActual - 1,
$anioActual => $anioActual,
$anioActual + 1 => $anioActual + 1,
],
'data' => $anioActual,
'label' => 'Año'
])
->add('puntoVentaTipoComprobante', EntityType::class, array('class' => 'App\Entity\PuntoVentaTipocomprobante',
'required' => true,
'query_builder' => function (\Doctrine\ORM\EntityRepository $repository) use ($tipoPuntoVenta) {
return $repository->createQueryBuilder('d')
->leftJoin('d.puntoVenta', 'pv')
->leftJoin('d.tipocomprobantes', 'tc')
->where('pv.puntoVentaTipo = :tipoPuntoVenta and tc.categoria = 2') // RECIBOS
->setParameter('tipoPuntoVenta', $tipoPuntoVenta);
},
))
->add('archivo', FileType::class, [
'label' => 'Archivo (txt)',
'required' => true,
'constraints' => [
new File([
'mimeTypes' => [
'text/plain',
],
'mimeTypesMessage' => 'Por favor, suba un archivo txt',
])
],
])
->add('importar', SubmitType::class, array('label' => 'Importar', "attr" => array('class' => "btn btn-success")))
->getForm();
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) { // si el formulario es valido
$params = $form->getData();
$logArchivos = $this->grabarLog('importacion', $params);
$params['logArchivos'] = $logArchivos;
if ($params['tipo'] == 'tarjeta') {
$this->procesarArchivo($params);
$vars = array(
'form' => $form->createView(),
'base_template' => $this->templateRegistry->getTemplate('layout'),
);
return $this->render('\archivos\importar.html.twig', $vars);
}
} else {
$vars = array(
'form' => $form->createView(),
'base_template' => $this->templateRegistry->getTemplate('layout'),
);
return $this->render('\archivos\importar.html.twig', $vars);
}
}
#[Route('/admin/archivos/importarrechazados', name: 'app_archivos_importar_rechazados', methods: ['GET', 'POST'])]
public function importarArchivosRechazados(Request $request)
{
$this->denyAccessUnlessGranted('ROLE_ARCHIVOS_EXP_IMP');
$fechaActual = new \DateTime();
$anioActual = date_format($fechaActual, 'Y');
$mesActual = date_format($fechaActual, 'n'); // NUMERO DEL MES SIN 0 PARA LOS MESES DE UN DIGITO
$tipoPuntoVenta = 1; // ENTRENAMIENTO
$form = $this->createFormBuilder()
->add('tipo', ChoiceType::class, [
'choices' => [
'Por tarjeta' => 'tarjeta',
'Por CBU' => 'cbu',
'Por planilla' => 'planilla',
],
"attr" => ['class' => "form-control"]
])
->add('organismo', EntityType::class, ['class' => 'App\Entity\Organismos', "attr" => ['class' => "form-control"], 'placeholder' => 'Todos', 'required' => false])
->add('tarjeta', EntityType::class, ['class' => 'App\Entity\Tarjetas', "attr" => ['class' => "form-control"]])
->add('periodoMes', ChoiceType::class, [
'choices' => [
'1' => '1',
'2' => '2',
'3' => '3',
'4' => '4',
'5' => '5',
'6' => '6',
'7' => '7',
'8' => '8',
'9' => '9',
'10' => '10',
'11' => '11',
'12' => '12',
],
'data' => $mesActual,
'label' => 'Mes'
])
->add('periodoAnio', ChoiceType::class, [
'choices' => [
$anioActual - 1 => $anioActual - 1,
$anioActual => $anioActual,
$anioActual + 1 => $anioActual + 1,
],
'data' => $anioActual,
'label' => 'Año'
])
->add('archivo', FileType::class, [
'label' => 'Archivo (txt)',
'required' => true,
'constraints' => [
new File([
'mimeTypes' => [
'text/plain',
],
'mimeTypesMessage' => 'Por favor, suba un archivo txt',
])
],
])
->add('importar', SubmitType::class, array('label' => 'Importar', "attr" => array('class' => "btn btn-success")))
->getForm();
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) { // si el formulario es valido
$params = $form->getData();
$logArchivos = $this->grabarLog('rechazados', $params);
$params['logArchivos'] = $logArchivos;
if ($params['tipo'] == 'tarjeta') {
$this->procesarArchivoObservacion($params);
$this->addFlash('success', '¡Archivo importado con exito!');
$vars = array(
'form' => $form->createView(),
'base_template' => $this->templateRegistry->getTemplate('layout'),
);
return $this->render('\archivos\importarrechazados.html.twig', $vars);
}
} else {
$vars = array(
'form' => $form->createView(),
'base_template' => $this->templateRegistry->getTemplate('layout'),
);
return $this->render('\archivos\importarrechazados.html.twig', $vars);
}
}
public function grabarLog($accion, $form)
{
$form['tarjeta'] = $form['tarjeta']->getNombre();
if (isset($form['puntoVentaTipoComprobante'])) {
$form['puntoVentaTipoComprobante'] = $form['puntoVentaTipoComprobante']->getPuntoVenta() . " " . $form['puntoVentaTipoComprobante']->getTipocomprobantes();
}
unset($form['archivo']);
$logArchivos = new LogArchivos();
$logArchivos->setUser($this->getUser());
$logArchivos->setAccion($accion);
$logArchivos->setFechaCreacion(new \DateTime());
$logArchivos->setForm(json_encode($form));
$em = $this->doctrine->getManager();
$em->persist($logArchivos);
$em->flush();
return $logArchivos;
}
public function generarArchivo($comprobantesDebitoAutomaticoTarjeta, $params)
{
$tarjetaId = $params['tarjeta']->getId();
switch ($tarjetaId) {
case 231: // VISA - DEBITO -
return $this->generarArchivoExportacionFiserv($comprobantesDebitoAutomaticoTarjeta);
break;
case 151: // VISA - CREDITO -
return $this->generarArchivoExportacionFiserv($comprobantesDebitoAutomaticoTarjeta);
break;
case 71: // MASTERCARD - CREDITO -
return $this->generarArchivoExportacionFiserv($comprobantesDebitoAutomaticoTarjeta);
break;
case 141: // UNICA - CREDITO -
return $this->generarArchivoExportacionUnica($comprobantesDebitoAutomaticoTarjeta);
break;
default:
$this->addFlash('error', '¡No se encontró un procesador para la tarjeta seleccionada!');
$request = $this->requestStack->getCurrentRequest();
return $this->redirectToRoute($request->attributes->get('_route'));
}
}
public function generarArchivoExportacionFiserv($comprobantesDebitoAutomaticoTarjeta): BinaryFileResponse
{
$sumatoriaImportes = 0;
$detalles = array();
$numero_comercio = $this->getParameter('fiserv_number_store');
foreach ($comprobantesDebitoAutomaticoTarjeta as $comp) {
$comp['fecha_vencimiento'] = new DateTime($comp['fecha_vencimiento']);
$comp['fecha_vencimiento_formateada'] = $comp['fecha_vencimiento']->format('d-m-y');
$importe = str_replace('.', '', (number_format(floatval($comp['importe']), 2, '.', '')));
$dataDetalle = array(
'nro_comercio' => str_pad($numero_comercio, 8, '0', STR_PAD_LEFT),
'tipo_registro' => '2',
'nro_tarjeta' => $comp['numero_tarjeta'],
'nro_referencia' => str_pad($comp['comp_id'], 12, '0', STR_PAD_LEFT),
'cuotas' => '001',
'cuotasplan' => '999',
'frecuenciadb' => '01',
'importe' => str_pad($importe, 11, '0', STR_PAD_LEFT),
'periodo' => str_pad('1', 5, '0', STR_PAD_LEFT),
'filler1' => ' ',
'fecha_vto_pago' => str_replace('-', '', ($comp['fecha_vencimiento_formateada'])),
'datos_auxiliares' => str_pad('', 40, ' ', STR_PAD_LEFT),
'filler' => str_pad(' ', 92, ' ', STR_PAD_LEFT),
);
// Agregar el array de detalles al array general
$detalles[] = $dataDetalle;
$sumatoriaImportes += $importe;
}
if ($sumatoriaImportes >= 0) {
$signo = "0";
} else {
$signo = "-";
}
$fechaActual = new DateTime();
$dataEncabezado = array(
'nro_comercio' => str_pad($numero_comercio, 8, '0', STR_PAD_LEFT),
'tipo_registro' => '1',
'fecha_registracion' => str_replace('-', '', $fechaActual->format('d-m-y')),
'cantidad_registros' => str_pad(count($comprobantesDebitoAutomaticoTarjeta), 7, '0', STR_PAD_LEFT),
'signo' => $signo,
'importe' => str_pad($sumatoriaImportes, 14, '0', STR_PAD_LEFT),
'filler2' => str_pad(' ', 91, ' ', STR_PAD_LEFT)
);
$cadenaConcatenada = '';
foreach ($dataEncabezado as $valor) {
// Concatenar cada par clave-valor en la cadena
$cadenaConcatenada .= $valor . '';
}
$cadenaConcatenada .= "\n";
foreach ($detalles as $detalle) {
foreach ($detalle as $valor) {
// Concatenar cada par clave-valor en la cadena
$cadenaConcatenada .= $valor . '';
}
$cadenaConcatenada .= "\n";
}
// Directorio temporal para almacenar el archivo
$tempDir = sys_get_temp_dir();
// Ruta completa del archivo
$rutaArchivo = $tempDir . '/DA168D.txt';
// Crear el archivo y escribir el contenido
file_put_contents($rutaArchivo, $cadenaConcatenada);
// Crear una BinaryFileResponse para la descarga
$response = new BinaryFileResponse($rutaArchivo);
// Configurar el nombre del archivo descargado
$response->setContentDisposition(
ResponseHeaderBag::DISPOSITION_ATTACHMENT,
'DA168D.txt'
);
// Eliminar el archivo después de la descarga
$response->deleteFileAfterSend(true);
return $response;
}
public function generarArchivoExportacionUnica($comprobantesDebitoAutomaticoTarjeta): BinaryFileResponse
{
foreach ($comprobantesDebitoAutomaticoTarjeta as $comp) {
$importe = str_replace('.', '', (number_format(floatval($comp['importe']), 2, '.', '')));
$fechaActual = new DateTime();
$datadetalle = array(
'nro_socio' => str_pad($comp['comp_id'], 9, '0', STR_PAD_LEFT),
'nro_tarjeta' => $comp['numero_tarjeta'],
'importe' => str_pad($importe, 11, '0', STR_PAD_LEFT),
'libre1' => str_pad('', 82, ' ', STR_PAD_LEFT),
'nombre_comercio' => str_pad('CEMENTERIO PENTECOSTES', 25, ' ', STR_PAD_LEFT),
'fecha_registracion' => str_replace('-', '', $fechaActual->format('d-m-y')),
'libre2' => str_pad('', 27, ' ', STR_PAD_LEFT),
'numero_comercio' => str_pad('252525', 11, ' ', STR_PAD_LEFT),
'moneda' => 'P',
'libre3' => str_pad('', 21, ' ', STR_PAD_LEFT),
'nro_tiquet' => str_pad($comp['cliente_id'], 4, '0', STR_PAD_LEFT),
'libre4' => str_pad('', 10, ' ', STR_PAD_LEFT),
'codigo_operacion' => '01',
'libre5' => str_pad('', 15, ' ', STR_PAD_LEFT),
);
// Agregar el array de detalles al array general
$detalles[] = $datadetalle;
}
$cadenaConcatenada = '';
foreach ($detalles as $detalle) {
foreach ($detalle as $valor) {
// Concatenar cada par clave-valor en la cadena
$cadenaConcatenada .= $valor . '';
}
$cadenaConcatenada .= "\n";
}
// Directorio temporal para almacenar el archivo
$tempDir = sys_get_temp_dir();
// Ruta completa del archivo
$rutaArchivo = $tempDir . '/DA168D.txt';
// Crear el archivo y escribir el contenido
file_put_contents($rutaArchivo, $cadenaConcatenada);
// Crear una BinaryFileResponse para la descarga
$response = new BinaryFileResponse($rutaArchivo);
// Configurar el nombre del archivo descargado
$response->setContentDisposition(
ResponseHeaderBag::DISPOSITION_ATTACHMENT,
'DA168D.txt'
);
// Eliminar el archivo después de la descarga
$response->deleteFileAfterSend(true);
return $response;
}
public function procesarArchivo($params)
{
$tarjetaId = $params['tarjeta']->getId();
switch ($tarjetaId) {
case 231: // VISA - DEBITO
$this->procesarArchivoImportacionFiserv($params);
break;
case 151: // VISA - CREDITO -
$this->procesarArchivoImportacionFiserv($params);
break;
case 71: // MASTERCARD - CREDITO -
$this->procesarArchivoImportacionFiserv($params);
break;
case 141: // UNICA - CREDITO -
$this->procesarArchivoImportacionUnica($params);
break;
default:
$this->addFlash('error', '¡No se encontró un procesador para la tarjeta seleccionada!');
$request = $this->requestStack->getCurrentRequest();
return $this->redirectToRoute($request->attributes->get('_route'));
}
}
public function procesarArchivoImportacionFiserv($params)
{
// Ruta del archivo txt
$archivo = $params['archivo'];
$filePath = $archivo->getPathname();
// Verificar si el archivo existe
$filesystem = new Filesystem();
if (!$filesystem->exists($filePath)) {
throw $this->createNotFoundException('El archivo no existe.');
}
// Obtener un objeto SplFileObject para leer el archivo
$file = new FileFile($filePath);
$fileObject = $file->openFile('r');
// Recorrer el archivo línea por línea
$arrayDatosGeneral = array();
while (!$fileObject->eof()) {
$lines = $fileObject->fgets();
if (substr($lines, 2, 1) == "2") { // SOLO PROCESAR LOS DEBITOS
$arrayDatos = $this->procesarLineaFiserv($lines);
$arrayDatosGeneral[] = $arrayDatos;
}
}
foreach ($arrayDatosGeneral as $item) {
$paramsFromLines = $this->arrayAdapter->adaptFiserv($item, $params);
// VALIDACIONES ANTES DE GENERAR EL RECIBO
// VALIDAR QUE EL COMPROBANTE FACTURA, NO TENGA YA UN RECIBO ASOCIADO.
// VALIDAR EL IMPORTE DEL COMPROBANTE CONTRA EL IMPORTE QUE DICE EL ARCHIVO DE IMPORTACION.
if ($this->validacionesFiserv($item, $params, $paramsFromLines)) {
try {
$recibo = $this->recibosAdminController->grabarRecibo($paramsFromLines);
$this->grabarLogImportacionDetalle($recibo, $params, $paramsFromLines);
} catch (\Exception $e) {
$entityManager = $this->entityManager;
if ($entityManager->getConnection()->isTransactionActive()) {
$entityManager->rollback();
$entityManager->beginTransaction();
}
$mensaje = 'Error al realizar la acción: ' . $e->getMessage() . '. No se generó ningun recibo, corrija el error y vuelva a importar.';
$this->grabarLogImportacionDetalle(null, $params, $paramsFromLines, $mensaje);
$entityManager->commit();
}
}
}
}
public function procesarArchivoImportacionUnica($params)
{
// Ruta del archivo txt
$archivounica = $params['archivo'];
$filePath = $archivounica->getPathname();
// Verificar si el archivo existe
$filesystem = new Filesystem();
if (!$filesystem->exists($filePath)) {
throw $this->createNotFoundException('El archivo no existe.');
}
// Obtener un objeto SplFileObject para leer el archivo
$file = new FileFile($filePath);
$fileObject = $file->openFile('r');
// Recorrer el archivo línea por línea
$arrayDatosGeneral = array();
while (!$fileObject->eof()) {
$lines = $fileObject->fgets();
if (substr($lines, 115, 1) == " ") { // SOLO PROCESAR LOS DEBITOS
$arrayDatos = $this->procesarLineaUnica($lines);
$arrayDatosGeneral[] = $arrayDatos;
}
}
foreach ($arrayDatosGeneral as $item) {
$paramsFromLines = $this->arrayAdapter->adaptUnica($item, $params);
// VALIDACIONES ANTES DE GENERAR EL RECIBO
// VALIDAR QUE EL COMPROBANTE FACTURA, NO TENGA YA UN RECIBO ASOCIADO.
// VALIDAR EL IMPORTE DEL COMPROBANTE CONTRA EL IMPORTE QUE DICE EL ARCHIVO DE IMPORTACION.
if ($this->validacionesUnica($item, $params, $paramsFromLines)) {
try {
$recibo = $this->recibosAdminController->grabarRecibo($paramsFromLines);
$this->grabarLogImportacionDetalle($recibo, $params, $paramsFromLines);
} catch (\Exception $e) {
$entityManager = $this->entityManager;
if ($entityManager->getConnection()->isTransactionActive()) {
$entityManager->rollback();
$entityManager->beginTransaction();
}
$mensaje = 'Error al realizar la acción: ' . $e->getMessage() . '. No se generó ningun recibo, corrija el error y vuelva a importar.';
$this->grabarLogImportacionDetalle(null, $params, $paramsFromLines, $mensaje);
$entityManager->commit();
}
}
}
}
public function procesarLineaFiserv($lines)
{
$arrayDatos = array();
// 1 - Sigla "AC"-> 2 bytes
$arrayDatos['sigla'] = substr($lines, 0, 2);
// 2 - Tipo De Registro -> 1 bytes
$arrayDatos['tipo_de_ingreso'] = substr($lines, 2, 1);
if ($arrayDatos['tipo_de_ingreso'] == 1) {
// 3 - Identificacion -> 8 bytes
$arrayDatos['identificacion'] = substr($lines, 3, 7);
// 4 - Numero De Comercio -> 8 bytes
$arrayDatos['numero_comercio'] = substr($lines, 10, 8);
// 5 - Fecha Presentacion -> 6 bytes
// FORMATO DDMMAA
$arrayDatos['fecha_presentacion'] = substr($lines, 18, 6);
// 6- Filler -> 6 bytes
// Se completara con 0
$arrayDatos['filler'] = substr($lines, 24, 6);
// 7 - Cantidad de Debitos -> 6 bytes
$arrayDatos['cantidad_de_debitos'] = substr($lines, 30, 6);
// 8 - Signo Importe -> 1 bytes
// Valor '0' -> signo positivo
// Valor '-' -> signo negativo
$arrayDatos['signo_importe '] = substr($lines, 36, 1);
// Importe Total-> 12 bytes
$arrayDatos['importe_total '] = substr($lines, 37, 12);
// Filler 2-> 109 bytes
$arrayDatos['filler_2'] = substr($lines, 49, 109);
}
if ($arrayDatos['tipo_de_ingreso'] == 2) {
// 3 - Numero De tarjeta -> 16 bytes
$arrayDatos['numero_de_tarjeta'] = substr($lines, 3, 16);
// 4 - Filler -> 7 bytes
$arrayDatos['filler'] = substr($lines, 19, 7);
// 5 - Numero Referencia-> 12 bytes
$arrayDatos['numero_de_referencia'] = substr($lines, 26, 12);
// 6- Filler -> 6 bytes
// Se completara con 0
$arrayDatos['filler_2'] = substr($lines, 38, 2);
// 7 - Importe -> 6 bytes
$arrayDatos['cantidad_de_debitos'] = substr($lines, 40, 11);
// 8 - Cuotas Canceladas -> 1 bytes
$arrayDatos['cuotas_canceladas'] = substr($lines, 51, 3);
// 9 - Vencimiento de la Tarjeta -> 4 bytes
// Formato MMAA
$arrayDatos['vencimiento_total'] = substr($lines, 54, 4);
// 10 - Codigo De Rechazo-> 2 bytes
$arrayDatos['filler_3'] = substr($lines, 58, 2);
// 11 - Periodo -> 5 bytes
// Valor "CRED" ->
// Valor1 = 3 caracterires de la seccion y Valor 2 = numero de cuotas
$arrayDatos['periodo'] = substr($lines, 60, 5);
// 12 - Fecha Presentacion -> 6 bytes
$arrayDatos['fecha_presentacion_original'] = substr($lines, 65, 6);
// 13 - Datos Auxiliares -> 40 bytes
$arrayDatos['datos_auxiliares'] = substr($lines, 71, 40);
// 14 - Fecha Clearing -> 40 bytes
$arrayDatos['fecha_clearing'] = substr($lines, 111, 6);
// 15 - Marca Aplica Dev IVA -> 1 bytes
$arrayDatos['marca_dev_iva'] = substr($lines, 117, 1);
// 16 - Importe Gravado -> 11 bytes
$arrayDatos['importe_gravado'] = substr($lines, 118, 11);
// 17 - Numero de Factura -> 20 bytes
$arrayDatos['numero_factura'] = substr($lines, 129, 20);
// 18 - Importe Devolucion -> 20 bytes
$arrayDatos['importe_devolucion'] = substr($lines, 149, 11);
}
return $arrayDatos;
}
public function procesarLineaUnica($lines)
{
$arrayDatos = array();
// identificacion de socio longitud -> 9 bytes
$arrayDatos['id_socio'] = substr($lines, 0, 9);
// Numero de Tarjeta longitud -> 16 bytes
$arrayDatos['id_nro_tarjeta'] = substr($lines, 9, 16);
// Importe Del Debito (9 enteros 2 decimales) -> 11 bytes
$arrayDatos['importe_debito'] = substr($lines, 25, 11);
// longitud Domicilio -> 35 bytes
$arrayDatos['domicilio'] = substr($lines, 36, 35);
// longitud Libre 1 -> 4 bytes
$arrayDatos['libre1'] = substr($lines, 71, 4);
// Importe De La Localidad -> 20 bytes
$arrayDatos['localidad'] = substr($lines, 75, 20);
// longitud Libre 2-> 20 bytes
$arrayDatos['libre2'] = substr($lines, 95, 20);
// longitud indicativo del rechazo ->1 bytes
// A -> Codigo de Identificacion de socio no numerico o cero
// B -> Cuenta inhabilitada
// C -> Codigo de moneda Erroneo
// D -> Debito Duplicado
// E -> Cuenta Bloqueada Transitoriamente
// F -> Usuario Extranjero
// G -> Importe no numerico o cero
// H -> Fecha de Presentacion mayor a 35 o invalida
// I -> Tarjeta Inexitente
// J -> Numero de Cupon no numerico
// K -> Codigo de Operacion no numerico
// L -> Cuenta Sin Disponible
// M -> Cuenta en situacion irregular
// N -> Comercio Desactiavo
// O -> Consulte a la Entidad
// R -> Stop Debit
// V -> Tarjeta Vencida
$arrayDatos['indicativo_rechazo'] = substr($lines, 115, 1);
// longitud indicativo de la nueva tarjeta asiganada -> 1 bytes
// 0 -> No Fue Reemplazada
// 1 -> Fue Reemplazada
$arrayDatos['indicativo_tarjeta_nueva'] = substr($lines, 116, 1);
// longitud Libre 3 -> 1 bytes
$arrayDatos['libre3'] = substr($lines, 117, 1);
// longitud de Leyenda -> 25 bytes
$arrayDatos['leyenda'] = substr($lines, 118, 25);
// longitud Fecha De Presentacion -> 6 bytes
$arrayDatos['fecha_presentacion'] = substr($lines, 143, 6);
// longitud Nombre del titular -> 25 bytes
$arrayDatos['nombre_titular'] = substr($lines, 149, 25);
// longitud Ciclo de Facturacion Del Usuario-> 2 bytes
$arrayDatos['ciclo_facturacion'] = substr($lines, 174, 2);
// longitud Numero De Comercio -> 11 bytes
$arrayDatos['numero_comercio'] = substr($lines, 176, 11);
// longitud Moneda DEFAULT P -> 1 bytes
$arrayDatos['moneda'] = substr($lines, 187, 1);
// longitud Vencimiento de Tarjeta (AAMM)-> 4 bytes
$arrayDatos['venc_tarjeta'] = substr($lines, 188, 4);
// longitud Numero De Tarjeta Nuevo (Si es que se informo que hubo un cambio)-> 16 bytes
$arrayDatos['num_tarjeta_nuevo'] = substr($lines, 192, 16);
// longitud Signo Del Importe ( ' '=Positivo '-'=Negativo )-> 1 bytes
$arrayDatos['signo'] = substr($lines, 208, 1);
// longitud Numero Del Tiquet -> 4 bytes
$arrayDatos['num_ticket'] = substr($lines, 209, 4);
// longitud Numero Componente de la Cuenta('01'=Titular '02 a 09'= Adicional) -> 2 bytes
$arrayDatos['num_comp_cuenta'] = substr($lines, 213, 2);
// longitud Codigo Postal -> 8 bytes
$arrayDatos['codigo_postal'] = substr($lines, 215, 8);
// longitud Codigo De Operacion -> 2 bytes
$arrayDatos['codigo_operacion'] = substr($lines, 223, 2);
// longitud Numero De Contribuyente -> 15 bytes
$arrayDatos['num_contribuyente'] = substr($lines, 225, 15);
return $arrayDatos;
}
public function procesarArchivoObservacion($params)
{
$tarjetaId = $params['tarjeta']->getId();
switch ($tarjetaId) {
case 151: // VISA - CREDITO -
$this->procesarArchivoImportacionFiservObservacion($params);
break;
case 71: // MASTERCARD - CREDITO -
$this->procesarArchivoImportacionFiservObservacion($params);
break;
case 141: // UNICA - CREDITO -
$this->procesarArchivoImportacionUnicaObservacion($params);
break;
default:
$this->addFlash('error', '¡No se encontró un procesador para la tarjeta seleccionada!');
$request = $this->requestStack->getCurrentRequest();
return $this->redirectToRoute($request->attributes->get('_route'));
}
}
public function procesarArchivoImportacionFiservObservacion($params)
{
$em = $this->doctrine->getManager();
// Ruta del archivo txt
$archivo = $params['archivo'];
$filePath = $archivo->getPathname();
// Verificar si el archivo existe
$filesystem = new Filesystem();
if (!$filesystem->exists($filePath)) {
throw $this->createNotFoundException('El archivo no existe.');
}
// Obtener un objeto SplFileObject para leer el archivo
$file = new FileFile($filePath);
$fileObject = $file->openFile('r');
// Recorrer el archivo línea por línea
$arrayDatosGeneral = array();
$arrayDatos= array();
while (!$fileObject->eof()) {
$lines = $fileObject->fgets();
$arrayDatos = $this->procesarLineaFiservObservacion($lines);
$logRechazadosDebitosAutomaticosDet = new LogRechazadosDebitosAutomaticosDet();
$logRechazadosDebitosAutomaticosDet->setLogArchivos($params['logArchivos']);
$logRechazadosDebitosAutomaticosDet->setNroRef($arrayDatos['id_socio']);
$logRechazadosDebitosAutomaticosDet->setNroTarjeta($arrayDatos['nro_tarjeta']);
$logRechazadosDebitosAutomaticosDet->setNroTarjetaAnterior($arrayDatos['nro_tarjeta_anterior']);
$logRechazadosDebitosAutomaticosDet->setCuotas($arrayDatos['cuotas']);
$logRechazadosDebitosAutomaticosDet->setCuotasPlan($arrayDatos['cuotas_frecuencia']);
$logRechazadosDebitosAutomaticosDet->setCodFrecDebito($arrayDatos['cuotas_plan']);
$logRechazadosDebitosAutomaticosDet->setImporte($arrayDatos['importe']);
$logRechazadosDebitosAutomaticosDet->setCodError($arrayDatos['descripcion']);
$em->persist($logRechazadosDebitosAutomaticosDet);
$em->flush();
}
foreach ($arrayDatosGeneral as $item) {
$this->grabar;
}
}
public function procesarArchivoImportacionUnicaObservacion($params)
{
$em = $this->doctrine->getManager();
// Ruta del archivo txt
$archivounica = $params['archivo'];
$filePath = $archivounica->getPathname();
// Verificar si el archivo existe
$filesystem = new Filesystem();
if (!$filesystem->exists($filePath)) {
throw $this->createNotFoundException('El archivo no existe.');
}
// Obtener un objeto SplFileObject para leer el archivo
$file = new FileFile($filePath);
$fileObject = $file->openFile('r');
// Recorrer el archivo línea por línea
$arrayDatosGeneral = array();
$arrayDatos= array();
while (!$fileObject->eof()) {
$lines = $fileObject->fgets();
if (substr($lines, 115, 1) != " ") { // SOLO PROCESAR LOS DEBITOS
$arrayDatos =$this->procesarLineaUnicaObservacion($lines);
$arrayDatosGeneral[] = $arrayDatos;
}
}
foreach ($arrayDatosGeneral as $item) {
$logRechazadosDebitosAutomaticosDet = new LogRechazadosDebitosAutomaticosDet();
$logRechazadosDebitosAutomaticosDet->setLogArchivos($params['logArchivos']);
$logRechazadosDebitosAutomaticosDet->setNroRef($item['id_socio']);
$logRechazadosDebitosAutomaticosDet->setNroTarjeta($item['num_tarjeta_nuevo']);
$logRechazadosDebitosAutomaticosDet->setNroTarjetaAnterior($item['id_nro_tarjeta']);
$logRechazadosDebitosAutomaticosDet->setCuotasPlan(intval($item['ciclo_facturacion']));
$logRechazadosDebitosAutomaticosDet->setImporte($item['importe_debito']);
$logRechazadosDebitosAutomaticosDet->setCodError($item['leyenda']);
$em->persist($logRechazadosDebitosAutomaticosDet);
$em->flush();
}
}
public function procesarLineaFiservObservacion($lines)
{
$linesArray = explode(";", $lines);
$arrayDatos = array();
// 1 - Numero de Referencia o ID de socio-> 12 bytes
$arrayDatos['id_socio'] = $linesArray[0];
// 2 - Numero de Tarjeta -> 17 bytes
$arrayDatos['nro_tarjeta'] = $linesArray[1];
// 3 - Numero de Tarjeta Anterior -> 16 bytes
$arrayDatos['nro_tarjeta_anterior'] = $linesArray[2];
// 4 - Cuotas -> 2 bytes
$arrayDatos['cuotas'] = $linesArray[3];
// 5 - Cuotas de Frecuencia de Debito -> 2 bytes
$arrayDatos['cuotas_frecuencia'] = $linesArray[4];
// 6 - Cuotas de Plan -> 2 bytes
$arrayDatos['cuotas_plan'] = $linesArray[5];
// 7 - Importe -> 6 bytes
$arrayDatos['importe'] = $linesArray[6];
// 8 - Descripcion -> 85 bytes
$arrayDatos['descripcion'] = $linesArray[7];
return $arrayDatos;
}
public function procesarLineaUnicaObservacion($lines)
{
$arrayDatos = array();
// identificacion de socio longitud -> 9 bytes
$arrayDatos['id_socio'] = substr($lines, 0, 9);
// Numero de Tarjeta longitud -> 16 bytes
$arrayDatos['id_nro_tarjeta'] = substr($lines, 9, 16);
// Importe Del Debito (9 enteros 2 decimales) -> 11 bytes
$importeUnica = intval(substr($lines, 25, 11));
$parte_entera = substr($importeUnica, 0, -2);
$parte_decimal = substr($importeUnica, -2);
$arrayDatos['importe_debito']= floatval($parte_entera . "." . $parte_decimal);
// longitud Domicilio -> 35 bytes
$arrayDatos['domicilio'] = substr($lines, 36, 35);
// longitud Libre 1 -> 4 bytes
$arrayDatos['libre1'] = substr($lines, 71, 4);
// Importe De La Localidad -> 20 bytes
$arrayDatos['localidad'] = substr($lines, 75, 20);
// longitud Libre 2-> 20 bytes
$arrayDatos['libre2'] = substr($lines, 95, 20);
// longitud indicativo del rechazo ->1 bytes
// A -> Codigo de Identificacion de socio no numerico o cero
// B -> Cuenta inhabilitada
// C -> Codigo de moneda Erroneo
// D -> Debito Duplicado
// E -> Cuenta Bloqueada Transitoriamente
// F -> Usuario Extranjero
// G -> Importe no numerico o cero
// H -> Fecha de Presentacion mayor a 35 o invalida
// I -> Tarjeta Inexitente
// J -> Numero de Cupon no numerico
// K -> Codigo de Operacion no numerico
// L -> Cuenta Sin Disponible
// M -> Cuenta en situacion irregular
// N -> Comercio Desactiavo
// O -> Consulte a la Entidad
// R -> Stop Debit
// V -> Tarjeta Vencida
$arrayDatos['indicativo_rechazo'] = substr($lines, 115, 1);
// longitud indicativo de la nueva tarjeta asiganada -> 1 bytes
// 0 -> No Fue Reemplazada
// 1 -> Fue Reemplazada
$arrayDatos['indicativo_tarjeta_nueva'] = substr($lines, 116, 1);
// longitud Libre 3 -> 1 bytes
$arrayDatos['libre3'] = substr($lines, 117, 1);
// longitud de Leyenda -> 25 bytes
$arrayDatos['leyenda'] = substr($lines, 118, 25);
// longitud Fecha De Presentacion -> 6 bytes
$arrayDatos['fecha_presentacion'] = substr($lines, 143, 6);
// longitud Nombre del titular -> 25 bytes
$arrayDatos['nombre_titular'] = substr($lines, 149, 25);
// longitud Ciclo de Facturacion Del Usuario-> 2 bytes
$arrayDatos['ciclo_facturacion'] = substr($lines, 174, 2);
// longitud Numero De Comercio -> 11 bytes
$arrayDatos['numero_comercio'] = substr($lines, 176, 11);
// longitud Moneda DEFAULT P -> 1 bytes
$arrayDatos['moneda'] = substr($lines, 187, 1);
// longitud Vencimiento de Tarjeta (AAMM)-> 4 bytes
$arrayDatos['venc_tarjeta'] = substr($lines, 188, 4);
// longitud Numero De Tarjeta Nuevo (Si es que se informo que hubo un cambio)-> 16 bytes
$arrayDatos['num_tarjeta_nuevo'] = substr($lines, 192, 16);
// longitud Signo Del Importe ( ' '=Positivo '-'=Negativo )-> 1 bytes
$arrayDatos['signo'] = substr($lines, 208, 1);
// longitud Numero Del Tiquet -> 4 bytes
$arrayDatos['num_ticket'] = substr($lines, 209, 4);
// longitud Numero Componente de la Cuenta('01'=Titular '02 a 09'= Adicional) -> 2 bytes
$arrayDatos['num_comp_cuenta'] = substr($lines, 213, 2);
// longitud Codigo Postal -> 8 bytes
$arrayDatos['codigo_postal'] = substr($lines, 215, 8);
// longitud Codigo De Operacion -> 2 bytes
$arrayDatos['codigo_operacion'] = substr($lines, 223, 2);
// longitud Numero De Contribuyente -> 15 bytes
$arrayDatos['num_contribuyente'] = substr($lines, 225, 15);
return $arrayDatos;
}
public function grabarLogImportacionDetalle($recibo, $param, $paramsFromLines, $mensaje = "") {
$em = $this->doctrine->getManager();
$facturaSeleccionada = $paramsFromLines['facturasSeleccionadas'];
$comprobanteId = explode(",", $facturaSeleccionada);
$comprobante = $em->getRepository('App\Entity\Comprobantes')->find(intval($comprobanteId[8]));
$logArchivosImportacionDetalle = new LogArchivosImportacionDetalle();
if($recibo){
$mensaje = $this->recibosRepository->getMensajeLogImportacion($recibo);
}
$logArchivosImportacionDetalle->setLogArchivos($param['logArchivos']);
$logArchivosImportacionDetalle->setComprobantes($comprobante);
$logArchivosImportacionDetalle->setMensaje($mensaje);
$em->persist($logArchivosImportacionDetalle);
$em->flush();
}
private function validacionesFiserv(mixed $item, $params, $paramsFromLines) : bool
{
$em = $this->doctrine->getManager();
$facturaObj = $em->getRepository('App\Entity\Comprobantes')->find(intval($item['numero_de_referencia']));
$mensajeRecibosAsociados = $this->validarExistenRecibos($facturaObj);
if($mensajeRecibosAsociados){
$this->grabarLogImportacionDetalle(null, $params, $paramsFromLines, $mensajeRecibosAsociados);
return false;
}
// VALIDO LOS IMPORTES
$immporteSaldoFactura = $facturaObj->getSaldo();
$importeEnArchivoAux = intval($item['cantidad_de_debitos']);
$parte_entera = substr($importeEnArchivoAux, 0, -2);
$parte_decimal = substr($importeEnArchivoAux, -2);
$importeEnArchivo = floatval($parte_entera . "." . $parte_decimal);
if ($immporteSaldoFactura < $importeEnArchivo) { // EL IMPORTE QUE VIENE EN EL ARCHIVO, ES MAS GRANDE QUE EL DE LA FACTURA
$mensaje = "El importe que viene en el archivo ({$importeEnArchivo}) es mayor al saldo de la factura ({$immporteSaldoFactura}). No se generó el recibo.";
$this->grabarLogImportacionDetalle(null, $params, $paramsFromLines, $mensaje);
return false;
} else if ($immporteSaldoFactura > $importeEnArchivo) { // EL IMPORTE QUE VIENE EN EL ARCHIVO, ES MAS CHICO QUE EL DE LA FACTURA
$mensaje = "El importe que viene en el archivo ({$importeEnArchivo}) es menor al saldo de la factura ({$immporteSaldoFactura}). No se generó el recibo.";
$this->grabarLogImportacionDetalle(null, $params, $paramsFromLines, $mensaje);
return false;
}
return true;
}
private function validacionesUnica(mixed $item, $params, $paramsFromLines) : bool
{
$em = $this->doctrine->getManager();
$facturaObj = $em->getRepository('App\Entity\Comprobantes')->find(intval($item['id_socio']));
$mensajeRecibosAsociados = $this->validarExistenRecibos($facturaObj);
if($mensajeRecibosAsociados){
$this->grabarLogImportacionDetalle(null, $params, $paramsFromLines, $mensajeRecibosAsociados);
return false;
}
// VALIDO LOS IMPORTES
$immporteSaldoFactura = $facturaObj->getSaldo();
$importeEnArchivoAux = intval($item['importe_debito']);
$parte_entera = substr($importeEnArchivoAux, 0, -2);
$parte_decimal = substr($importeEnArchivoAux, -2);
$importeEnArchivo = floatval($parte_entera . "." . $parte_decimal);
if ($immporteSaldoFactura < $importeEnArchivo) { // EL IMPORTE QUE VIENE EN EL ARCHIVO, ES MAS GRANDE QUE EL DE LA FACTURA
$mensaje = "El importe que viene en el archivo ({$importeEnArchivo}) es mayor al saldo de la factura ({$immporteSaldoFactura}). No se generó el recibo.";
$this->grabarLogImportacionDetalle(null, $params, $paramsFromLines, $mensaje);
return false;
} else if ($immporteSaldoFactura > $importeEnArchivo) { // EL IMPORTE QUE VIENE EN EL ARCHIVO, ES MAS CHICO QUE EL DE LA FACTURA
$mensaje = "El importe que viene en el archivo ({$importeEnArchivo}) es menor al saldo de la factura ({$immporteSaldoFactura}). No se generó el recibo.";
$this->grabarLogImportacionDetalle(null, $params, $paramsFromLines, $mensaje);
return false;
}
return true;
}
private function validarExistenRecibos($factura) {
$recibosAsociados = $this->comprobantesRepository->recibosAsociado($factura);
if($recibosAsociados) {
$mensaje = "";
foreach ($recibosAsociados as $item) {
$mensaje .= $item['recibo'] . ". ";
}
return $mensaje = "El comprobante ya tiene recibo/s asociado/s ({$mensaje}). No se generaron nuevos recibos.";
}
return false;
}
}