En una entrada anterior, comenté algo sobre este gran programa de contabilidad pero no llegué a explicar como generar los libros de IVA. Voy a ir explicando paso a paso que es lo que he hecho yo y después compartiré el script.

Lo primero que hago, es definir una serie de constantes para conectar al servidor donde se almacenan los datos. En el ejemplo he supuesto que está en un servidor mysql, así que habría que hacer las modificaciones pertinentes si no es así. También he definido una constante debug, que si tiene el valor verdadero no insertará nada en la bbdd, simplemente guardará las sentencias en un fichero de texto para analizarlas o ejecutarlas directamente.

define('BD_SERVIDOR', 'iponombredelservidor');
define('BD_NOMBRE', 'nombrebbdd');
define('BD_USUARIO', 'usuario');
define('BD_PASSWORD', 'contraseñabbdd');

define('DEBUG',false); //false o true

//La conexión
$db = new PDO('mysql:host=' . BD_SERVIDOR . ';dbname=' . BD_NOMBRE . ';charset=utf8', BD_USUARIO, BD_PASSWORD);

Para no tener que ir andando con fechas y demás, he decidido seleccionar los registros a partir del ejercicio. En una variable almaceno el valor del ejercicio del que quiero generar los libros de IVA. Este valor hay que cambiarlo según cada caso.

//Aquí ponemos el nombre que le hayamos dado al ejercicio.
$ejercicio="Año 2018";

Generamos la sentencia SQL que buscará en el diario aquellos asientos que contengan IVA, pero como este script genera el libro de facturas recibidas, buscará en las cuentas 472.X. Si en tu plan contable el IVA soportado no está en la cuenta 472, tendrás que modificarlo. Nótese también, que el debe tiene que ser distinto a 0.

/*
Primero localizamos los asientos del $ejercicio que contienen iva
y voy a limitarlos a los que tengan una cantidad en el debe
*/

$consulta = $db->prepare("SELECT * FROM diario WHERE ejercicio='$ejercicio' AND cuenta>47200000 AND cuenta<47300000 AND (debe>0 OR debe<0) ORDER BY asiento;");
$consulta->execute();
$resultado = $consulta->fetchAll(PDO::FETCH_ASSOC);
$trabajototal=sizeof($resultado);

Un par de sentencias mas para abrir un fichero de depuración y una variable contador que nos informa del % que lleva del proceso:

//Esto es un simple contador para saber por que % del proceso vamos
$i=0;

//Si debug es verdadero, solo va a guardar las sentencias en un fichero de texto
if(DEBUG)
	 $file = fopen("debug.txt", "w");

Ahora el bucle principal del programa. Va a recorrer cada uno de los registros (asientos) obtenidos y por cada uno de ellos voy a buscar el pase que contiene una entrada en la cuenta 6 (compras y gastos). En mi caso, lo he limitado a la cuenta 60000001, pero se puede incluso poner un rango simplemente modificando la sentencia SQL. Cada uno de estos registros (asientos) obtenidos será una factura recibida de un proveedor o acreedor.

Para introducir la factura en el libro de IVA correspondiente necesitamos los siguientes datos básicos: el pase, el tipo de IVA, la base, la cuota de IVA y la cuenta del proveedor. Los demás datos a introducir los he puesto con valores por defecto porque no he querido complicar mucho el script pero modificando la sentencia INSERT podríamos adaptarla a nuestro gusto. Tengo que añadir una salvedad y es que una factura podría tener varios tipos de iva, por lo tanto varias bases y este script lo tiene en cuenta.

foreach($resultado as $asiento) {
	$i+=100;	//Esto solo es para calcular el porcentaje terminado

	//por cada asiento, debemos buscar sus ivas
	print("\nGenerando asiento " . $asiento['asiento'] . "\t\t". round($i/$trabajototal) . " %");

	//He supuesto que usamos la cuenta 60000001, pero aqui podemos poner cualquier otra o incluso un rango
	$coniva = $db->prepare("SELECT * FROM diario WHERE ejercicio='$ejercicio' AND asiento=:asiento AND cuenta=60000001 AND (debe>0 OR debe<0);");
	$coniva->execute(array(':asiento'=>$asiento['asiento']));
	$resivas = $coniva->fetchAll(PDO::FETCH_ASSOC);

	foreach($resivas as $resiva) {
		//En asiento['debe'] tenemos la cuota de iva
		//En resiva['debe'] tenemos la base

		//Una subconsulta que nos obtiene la cuenta del proveedor o acreedor
		$cuenta_fra="(SELECT cuenta FROM diario WHERE ejercicio='$ejercicio' AND asiento=" . $asiento['asiento'] . " AND ((cuenta>40000000 AND cuenta<40100000) OR (cuenta>41000000 AND cuenta<41100000)) AND (haber>0 OR haber<0))";

		//Calcular el tipo de iva a partir de la base y el iva
		$tipoiva=round($asiento['debe'] / $resiva['debe'] * 100);

		//Esta es la sentencia que debemos introducir en la bbdd.
		$sql="INSERT INTO libroiva (pase, cta_base_iva, base_iva, clave_iva, tipo_iva, tipo_re, cuota_iva, cuenta_fra, fecha_fra, soportado, prorrata, afecto, aib, eib, rectificativa, autofactura, agrario, fecha_operacion, bi_costo, nfacturas, autofactura_no_ue, pr_servicios_ue, bien_inversion, op_no_sujeta, exento_dcho_ded, isp_op_interiores, importacion, exportacion, noincluir347, caja_iva, ventas_fuera_tac, donacion_2ejer, donacion_especie, enviado_sii, oro_inversion, arrto_local_sin_ret, reav) VALUES (:pase, :cta_base_iva, :base_iva, :clave_iva, $tipoiva, :tipo_re, :cuota_iva, $cuenta_fra, :fecha_fra, :soportado, :prorrata, :afecto, 0, 0, 0, 0, 0, :fecha_operacion, 0, 0, 0, 0, 0, 0, :exento_dcho_ded, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);";

		/* 
		Esta clave de iva no existe, pero la he puesto para poder localizar los registros que he introducido en la bbdd
		despues se puede hacer un update y cambiarla o bien introducirla directamente
		*/

		$claveiva="GG";
		$parametros=array(':pase'=>$asiento['pase'], ':cta_base_iva'=>"47200001", ':base_iva'=>$resiva['debe'], ':clave_iva'=>$claveiva, ':tipo_re'=>0, ':cuota_iva'=>$asiento['debe'], ':fecha_fra'=>$asiento['fecha'], ':soportado'=>1, ':prorrata'=>1.0, ':afecto'=>1.0000, ':fecha_operacion'=>$asiento['fecha'], ':exento_dcho_ded'=>1);

		/* Tengo que comprobar que el iva esté dentro de unos valores, si no, no lo meto
		Ciertos asientos pueden contener facturas con varios tipos de iva al mismo tiempo, con esto me aseguro
		que se introducen los ivas correctos. Si en un futuro cambiaran los ivas, habría que cambiar esto.
		*/
		
		switch($tipoiva) {
			case 0:
			case 4:
			case 10:
			case 21:
				if(DEBUG) {
					debugSQL($sql, $parametros, $file);
				} else {
					$consulta = $db->prepare($sql);
					$estado=$consulta->execute($parametros);
				}
		}
	}

}

Y por último, cerrar el fichero por si estamos en modo depuración y la función que genera la sentencia mysql para depurar. (mas información en esta entrada)

//Si estoy en modo depuración, cierro el fichero abierto antes.
if(DEBUG)
	fclose($file);

print("\n\n");

/* 
Esta función es solo para generar una sentencia sql a partir de la sentencia propiamente dicha
y la matriz de parámetros
*/
function debugSQL($sentencia, $params, $file) {
	foreach($params as $clave => $valor)
		$sentencia=str_replace($clave, "'". $valor ."'", $sentencia);
	
	fwrite($file, $sentencia . PHP_EOL . "\n");
	print($sentencia); //Es opcional mostrarlo por pantalla
	
}

He dicho ya que el código está en php? y por qué php y no otro? He supuesto que si la bbdd se tiene en un servidor mysql, lo mas normal es que se hubiera aprovechado un servidor de internet en un proveedor de hosting. Estos suelen tener paquetes básicos por muy poco dinero que incluyen bbdd mysql, apache y php.

A ver, antes que nada… no es el código mas bonito del mundo ni pretende serlo y seguro que tiene muchos fallos, pero para la casuística de la mayoría de mis clientes funciona a la perfección porque no se han tenido en cuenta temas como las retenciones y demás.

Categories:

One response

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Time limit is exhausted. Please reload CAPTCHA.