Validar botón submit

Hola amigos de yii, despues de un tiempo fuera del foro por problemas de conectividad con internet, les traigo una duda que espewro me ayuden a resolver, el problema es que tengo un sistema (facturacion) que necesito generar los numeros de facturas automáticos, para ello tengo dos tablas en mi BD, una tabla facturas con los datos de las facturas incluyendo un campo Idn autonumerico y otra tabla detallesfacturas donde se llenan los datos de los productos a facturar con un campo Id_sal entero relacionado con el campo Idn de la tabla factura uno a muchos, o sea, si tengo una factura con el Idn = 1 entonces puedo tener varios ptoductos en esa factura con Id_sal = 1, de esta lleno las tablas, el problema es que si en el navegador la conexion es lenta al dar clic, demora al hacer la factura, entonces cuando la persona que esta haciendo la operacion le da clic mas de una vez al botón submit de crear la factura, entonces me crea la operacion mas de una vez, generando errores, ya que como todo es automatico, entonces me rebaja los saldos mas de una vez de la tabla submayor, que es donde se guardan los saldos de los productos.

Si alguien tiene una validacion para eso y me la puede dar a traves de este post, se lo agradeceria, en conclusion, lo que quiero es que al hacer clic en el botón submit de crear la factura, entonces me la cree y si le hago clic otra vez entonces ya este inabilitado para que no la vuelva a crear.

Para evitar reenvíos de formularios tienes estas alternativas:

1.- Redirigir a otra página/acción distinta de la que recibe los datos post del form, es la solución más sencilla.

2.- Comprobar, mediante una variable de control guardada en sesión, si el formulario ya ha sido enviado.

Además de, obviamente, validar todos los permisos y datos antes de guardar cualquier cosa en la BD.

Espero te sirva.

Buenas, Rafael.

Deberías tener una acción en tu FacturasController (nombre de ejemplo) que capture la creación de la factura. Desde tu formulario deberías llamar a esta acción mediante AJAX y cuando lo haces cambiar el atributo del botón a "disabled". Una vez que tengas éxito (success), vuelves a habilitar el botón o redireccionas al usuario.

Para desabilitar:




$('#saveBtn').prop('disabled', true);



Llamada ejemplo AJAX:




$.ajax({

type:'get',

url: "<?= Yii::app()->createUrl('factura/create') ?>/",

success: function()

{

$('#saveBtn').prop('disabled', false);

...

});



por favor, necesito un ejemplo de esto, es muy importante, ya que hoy lo tengo poniendo en número consecutivo en en campo numerico entero, no autoincrementable y luego genera el numero de factura con ese consecutivo al final, pero necesito hacerlo automatico, creo debe ser con ese consecutivo autonumerico, pero si lo pongo asi, entonces al dar mas de un clic en el botón submit me genera mas de una factura

Hola Rafael,

Yo suelo hacerlo de otra manera, no dejo crear 2 facturas vacias de 1 mismo proveedor o cliente.

De esta manera te da igual que pulsen 1, 10 ó 100 veces.

En la accion create miras si existe una factura vacia, si existe no creas nada y redireccionas a la vista de factura con el id encontrado.

Si no hay ninguna factura vacia, creas una nueva y rediriges a la vista de la nueva factura.

No resuelves el problema de enviar 2 ó mas veces el formulario pero evitas tener facturas creadas sin mas.

Saludos

Gracias rahif, explicate un poco mejor, ilustrando lo que me dices con un ejemplo.

No se como haces las facturas, para mi una factura es un encabezado (que va en una tabla), y una serie de conceptos (que van en 1 u otras tablas). Si no hay conceptos la factura esta vacia.

En tu caso, creo que detalles facturas es la tabla que tiene los conceptos, si una factura esta vacia aqui no hay ninguna linea enlazada con tu factura.

Si enlazas conceptos automaticamente al crear la factura, esto no valdría. (Quiza habría otra forma de verlo.)

El tema del ajax esta bien, pero esto se controla en el cliente (debes tenerlo en cuenta para futuros cambios).

Saludos

Ok, mi factura la hago en dos tablas, una tabla de facturas y otra de detalles de facturas, en la tabla factura pongo los detalles preliminares de los clientes, conceptos de facturas, etc. y en la tabla detalles pongo los productos con precios, cantidades de productos, importes, almacenes donde estan los productos, etc., por productos todos por codigos, entre la tabla facturas y detalles estan relacionadas por el consecutivo de la factura, la que genera el numero de factura con la tabla detalles, ejemplo:

Tabla facturas:

Idn (integer no autoincrementable) es el consecutivo, entonces se genera el numero de factura nfactura (varchar 20), aqui este numero se forma segun algunas condiciones que le pongo, entonces en la tabla detalles tengo un campo Id_sal (varchar 20), donde lo toma del numero de factura (nfactura), estos campos esta relacionados uno a muchos, ya que una factura puede tener muchos productos, lo que quiero es que este campo (Idn) sea autoincrementable, por supuesto, entonces usted me sugiere que ponga en la tabla facturas una factura vacia para cada cliente, donde debe llevar un valor Idn y en el campo codigo_cliente el numero de cliente, le pongo de antemano que tengo una tabla cliente con todos los clientes (mas de 2500) con todas las generalidades de estos, con campo codigo_cliente de llave que se relaciona con la tabla factura por ese campo uno a muchos, o sea un cliente puede tener muchas facturas, asi las facturas tiene otros campors tambien relacionados con otras tablas, pero le pongo el de clientes que es el que importa en cuestion, le digo esto porque si tengo que agregar una factura si pongo una factura vacia para cada cliente, entonces voy a utilizar por adelantado mas de 2500 numeros.

Disculpe si no entendi lo de poner una factura vacia.

Hola Rafael,

Un programa de facturación es complejo, pero puede ser que te estés ahogando en un vaso de agua?

Tienes dos tablas, una de resumen facturas y otra de lineas factura, eso está bien.

Relaciona las líneas factura con su factura a través del id autoincrementable de toda la vida de la tabla facturas

Y no uses este id como el número de factura. El número de factura calcúlalo de otra forma: lees el valor MAX(numfactura) y le sumas 1 a la factura que se va a crear, así de sencillo.

Cómo evitar números duplicados? al validar los datos debes comprobar que ese número de factura no existe.

Cómo evitar reenvíos del formulario? Revisa la anterior respuesta. Creo que no se pueden evitar porque es cosa del navegador. Simplemente si el número de factura ya existe no cumplirá las reglas de validación, avisas al usuario y no la guardas, como es lógico.

Otra cosa que puedes hacer es usar una variable de sesión para controlar si la factura ya ha sido creada o no, por ejemplo guardando su número en esa variable, o usar ajax o pasar los datos a otra página por json… Hay diversas maneras de controlar eso.

Una cosa respecto a los clientes: los datos del cliente pueden cambiar, pero los datos del cliente en una factura ya hecha no. Con esto quiero decirte que los datos del cliente deberías guardarlos en la tabla facturas, en lugar de la referencia a su id de cliente.

Saludos.

Hola Rafa,

El post anterior de Fher es todo ok. Respecto del mio anterior creo que te he liado totalmente.

Lo de los clientes que te comenta es super importante, una factura debe tener todos las datos como texto porque es un documento final y tal como se ha calculado debe quedar sin modificar.

Yo en mi caso suelo crear un campo lineas en la tabla facturas y cada vez que agrego productos a la factura incremento el numero (si elimino resto), esto me obliga a hacer un update de la factura cada vez que se agregan o eliminan articulos pero me permite controlar que no se creen varias facturas al enviar un formulario o por otras razones.

saludos

Gracias Fher y rahif

hola de nuevo he trabajado en lo que me dice dicen, pero no logro evitar lo de hacer varias facturas cada vez que se hace clic, eso lo necesito resolver, ya que cada vez que se hace una factura en cada clic, me rebaja los saldos aunque se haga con numeros diferentes.

Hola Rafael, a ver:

Es de suponer que en el formulario tienes un input con el número de factura, si ese número no lo cambias las reglas de validación deben dar el error de que ese número ya existe y la factura no se debe guardar.

¿Por qué cambia el número de factura?

En el modo "normal", el usuario puede reenviar el formulario y eso es cosa del navegador y del usuario, eso pasa con todos los formularios. Lo que nosotros debemos hacer con php es validar que esos datos sean correctos antes de guardarlos.

Si lo haces con ajax una vez guardada la nueva factura inicializas los datos del formulario y problema resuelto. Pero vamos que se puede hacer de las dos formas.

Si sigues sin solucionarlo pon un ejemplo más claro.

Saludos.

Hola Fher gracias por responder te explico, el numero de factura cambia, porque yo tengo un campo Id [color="#0000FF"]autoincrementable [/color]y un campo Idn numerico pero [color="#FF0000"]no autoincrementable[/color], este campo lo formo de la siguiente forma: Busco en la tabla factura el mayor numero Idn MAX(Idn) y le adiciono uno. o sea, Idn=MAX(Idn)+1, y este numero obtenido es con el formo el [color="#800080"]número de factura[/color] (con otros elementos en varias cadenas), lo que pasa es que cada vez que se hace clic en el botón submit para crear la factura, hace la misma operacion y me crea tantos Idn y facturas como veces de clic en este botón, esto es lo que quiero resolver, pongo la validacion en la accion crear factura del controlador:




if ($id) {

        	$model = $this->loadModel($id);

    	} else {

        	$model = new Facturas;

        	//verificar si el consecutivo ya existe

        	$fact = Facturas::model()->find('Idn = :fa', array(':fa' => $_POST['idn']));

        	if ($fact) {

            	echo "fail";

            	yii::app()->end();

        	}

    	}



y en el form cuando formo los datos pongo esto:




 success: function(data) {

            	if (data === 'fail')

                	alert('Ya existe un registro con ese número consecutivo');

            	else

                	window.location.href = 'index.php?r=facturas/admin';

        	}



pero esto no funciona, ya que siempre forma un nuevo Idn.

Hola,

Lo del número de factura autoincrementable es muy común y como dices esta bien Rafael Idn=MAX(Idn)+1.

Lo de evitar los submits duplicados con ajax como lo haces no vale porque el numero cambia con cada envio.

Yo creo que hay 2 formas:

  • Javascript, de la forma que dice migueArgentina en el 3º post. (Pero aqui en el servidor no se comprueba nada)

    al pulsar submit bloqueas el envio para evitar repeticiones.

  • comprobarlo en el servidor. Para esto necesitas saber algo que te permita distinguir si la factura es nueva o no.

    ¿tienes alguna forma de distinguirlo? (nº lineas de factura, estados factura, … o cualquier otra cosa)

saludos

Hola rahif, lo que necesito implementar es lo que dice migue, o s ea, cuando se envie el primer clic desabilitar el boton submit para que no se repita, pero no se como hacerlo.

Hola Rafael,

Sin javascript, lo más sencillo:

1.- En la acción crearFactura calculas el número de factura a crear, tal como dices con consulta max()+1, y muestras e inicializas el form con ese número.

2.- En la acción guardarFactura validas todos los datos y la guardas.

3.- Al volver a crearFactura se genera un nuevo número y se inicializa el form.

4.- Si el usuario reenvía el formulario ese número de factura ya existe > error de validación.

El próximo número de factura debe calcularse siempre al inicializar el form, en la acción crearFactura y consultando la base de datos, no al hacer clic en el botón enviar.

Salu2.

Gracias por responder, he probado varias veces y se me ha hecho dificil, esto, aqui voy a poner mi accion donde creo la factura en el controlador (salvaFactura) y el form (vista), para ver si me pueden ayudar mas claro:

accion del Contralador




   public function actionSalvarFactura() {


    	$id = $_POST['modelid'];

    	$importeTotal = 0;

    	$importeTotalc = 0;

    	$impdl = 0;

    	$imventas = 0;

    	$imrecargo = 0;


    	if ($id) {

        	$model = $this->loadModel($id);

    	} else {

        	$model = new Datossal;

        	//verificar si el consecutivo ya existe

        	/*  $fact = Datossal::model()->find('Idn = :fa', array(':fa' => $_POST['idn']));

          	if ($fact) {

          	echo "fail";

          	yii::app()->end();

          	} */

    	}

    	$firm = Firmantes::model()->find('CI=:CI', array(':CI' => $_POST['ci']));

    	$Ent = Entidades::model()->find('CodUEB=:CodUEB', array(':CodUEB' => $_POST['codUEB']));

    	//echo $firm->Fechaf;

    	$query = "select Idn as may from datossal order by Idn desc limit 1";

    	Yii::app()->db->createCommand($query)->execute();

    	$model = $query->createCommand();

    	$model = $command->queryAll();

    	

    	if ($firm->Fechaf > date('Y-m-d') && (isset($_POST['detalle']))) {


        	$model->Idn = $query->may+1;

        	$model->fecha = $_POST['fecha'];

        	$model->CodCliente = $_POST['cliente'];

        	$model->CodUEB = $_POST['codUEB'];

        	$model->CI = $_POST['ci'];

        	$model->IdEstado = $_POST['idestado'];

        	$model->CIFac = $_POST['cifac'];

        	$model->CodOp = 1;

        	$model->NConduce = $_POST['nconduce'];

        	$model->norden = $_POST['norden'];

        	$model->Codde = 1;

        	$model->CodDoc = 2;

        	$model->CITra = $_POST['citra'];

        	$model->bultos = $_POST['bultos'];

        	$model->entregar = $_POST['entregar']; //


        	if ($model->save()) {


            	$fecha = date("y");

            	$cadena1 = "$Ent->Cod";

            	$cadena3 = "-";

            	$cadena4 = "$model->Idn"; //

            	$cadena5 = "0";

            	$cadena6 = "00";

            	$cadena7 = "000";

            	$cadena8 = "MN";

            	//llenar numero de factura

            	if (!$id) {

                	$criteria = new CDbCriteria;

                	$criteria->addCondition('Idn=:Idn');

                	$criteria->params = array(':Idn' => $model->Idn);

                	$objFact = datossal::model()->find($criteria);

                	if ($model->Idn <= 9) {

                    	$objFact->nfactura = $fecha . $cadena1 . $cadena8 . $cadena3 . $cadena7 . $cadena4;

                	} elseif ($model->Idn >= 10 & $model->Idn <= 99) {

                    	$objFact->nfactura = $fecha . $cadena1 . $cadena8 . $cadena3 . $cadena6 . $cadena4;

                	} elseif ($model->Idn >= 100 & $model->Idn <= 999) {

                    	$objFact->nfactura = $fecha . $cadena1 . $cadena8 . $cadena3 . $cadena5 . $cadena4;

                	} elseif ($model->Idn >= 1000) {

                    	$objFact->nfactura = $fecha . $cadena1 . $cadena8 . $cadena3 . $cadena4;

                	}

                	$objFact->save();


                	Detallesfact::model()->deleteAll('Id_sal=:nfactura', array(':nfactura' => $model->nfactura));

//date("y")

                	foreach ($_POST['detalle'] as $item) {

                    	//Lo que se guarda en tabla Detallesfactc

                    	$detalle = new Detallesfact;

                    	$detalle->Id_sal = $objFact->nfactura;

                    	$detalle->Codprod = $item['producto']; //

                    	$detalle->cantidad = $item['cantidad']; //

                    	$detalle->prod = $item['prod']; //

                    	$detalle->recargo = $item['recargo']; //

                    	$detalle->cmay = $item['cmay'];

                    	$produ = Productos::model()->find('Codprod=:Codprod', array(':Codprod' => $item['producto']));

                    	$produp = Subproductos::model()->find('Codpro=:Codpro', array(':Codpro' => $produ->CodSubp));

                    	$prodtipo = Tipoprod::model()->find('Codtipo = :Codtipo', array(':Codtipo' => $produp->Codtipo));

                    	$turcadm = Turcadm::model()->find('CodOp=:CodOp', array(':CodOp' => $model->CodOp));

                    	$detalle->Codpro = $produp->Codpro; //

                    	// $producmayor = Submyproductos::model()->find('Codpro=:Codpro and CodPVen=:codpven', array(':Codpro' => $produp->Codpro, ':codpven' => $venta));

                    	$producmayor = Submyproductos::model()->find('Codpro=:Codpro', array(':Codpro' => $produp->Codpro));

                    	$detalle->CodPVen = $producmayor->CodPVen;

                    	$detalle->SaldoDes = $producmayor->SaldoAct - $detalle->cantidad;

                    	$mayor = Cmayorista::model()->find('IdMay=:IdMay', array(':IdMay' => $item['cmay']));

                    	//formacion de precio mn              	

                    	switch ($model->CodOp) {

                        	case 1:

                            	if ($mayor->IdMay <> 1) {

                                	$detalle->premn = ROUND($produ->PreMay / $turcadm->Tasa, $produ->lg);

                            	} elseif ($mayor->IdMay <> 2) {

                                	$detalle->premn = ROUND($produ->PreMay, $produ->lg);

                            	}

                            	break;

                    	}

                    	//importemn

                    	$detalle->importemn = ROUND($detalle->premn * $detalle->cantidad, 2);


                    	//iventas mn

                    	switch ($model->CodOp) {//revisar cuando realmente lo lleve

                        	case 1:

                            	if ($mayor->IdMay <> 1) {

                                	$detalle->imventas = ROUND((($produ->PreMay / $turcadm->Tasa - $produ->PreMay)) * $detalle->cantidad, 2);

                            	} elseif ($mayor->IdMay <> 2) {

                                	0;

                            	}

                            	break;

                    	}

                    	// $detalle->imventas = ROUND((($produ->PreMay / $turcadm->Tasa - $produ->PreMay)) * $detalle->cantidad, 2);

                    	//recargo

                    	if ($detalle->recargo <> 1) {

                        	$detalle->Recargoca = ROUND($detalle->cantidad * $prodtipo->recargo, 2);

                    	}


                    	$importeTotal += $detalle->importemn;

                    	$imventas += $detalle->imventas;

                    	$imrecargo += $detalle->Recargoca;

                    	$detalle->save();


                    	//para actualizar los saldos en tabla Submyproductos 

                    	if (!$id) {

                        	$criteria = new CDbCriteria;

                        	$criteria->addCondition('CodPVen=:codpven');

                        	$criteria->addCondition('Codpro=:codigo');

                        	$criteria->params = array(':codpven' => $detalle->CodPVen, ':codigo' => $produp->Codpro);

                        	$objSubmp = Submyproductos::model()->find($criteria);

                        	$objSubmp->SaldoAct = $objSubmp->SaldoAct - $item['cantidad'];

                        	$objSubmp->SaldoAnt = $objSubmp->SaldoAct + $item['cantidad'];

                        	$objSubmp->save();

                    	}

                    	//llenar historico de operaciones

                    	$histoper = Histoper::model()->find('nfactura=:nfactura and Cliente=:Cliente', array(':nfactura' => $objFact->nfactura, ':Cliente' => $model->CodCliente));


                    	if (!$histoper) {//Si no existe crearla	

                        	$histoper = new Histoper;

                        	$histoper->nfactura = $objFact->nfactura;

                        	$histoper->fecha = $model->fecha; //

                        	$histoper->CodUEB = $model->CodUEB; //

                        	$histoper->Cliente = $model->CodCliente; //

                        	$histoper->CodDoc = 2; //

                        	$histoper->IdEstado = $model->IdEstado; //

                        	$histoper->ndocu = $model->norden; //

                        	$histoper->CodOp = $model->CodOp; //

                        	$histoper->Codde = $model->Codde; //

                        	$histoper->CIFac = $model->CIFac; //

                        	$histoper->CICli = $model->CI; //

                        	$histoper->CITra = $model->CITra; //

                        	$histoper->save();

                    	}

                    	//llenar otros calculos


                    	if (!$id) {

                        	$criteria = new CDbCriteria;

                        	$criteria->addCondition('nfactura=:nfactura');

                        	$criteria->params = array(':nfactura' => $objFact->nfactura);

                        	$objFac = Datossal::model()->find($criteria);

                        	$histopera = Histoper::model()->find($criteria);

                        	$histopera->ImporteMN = $importeTotal + $imrecargo;

                        	$histopera->Recargo = $imrecargo;

                        	$histopera->Imporventas = $imventas;

                        	$objFac->Imporventas = $imventas;

                        	$objFac->Recargo = $imrecargo;

                        	$objFac->ImporteMN = $importeTotal + $imrecargo;

                        	$histopera->save();

                        	$objFac->save();


                        	//llenar historico de facturas

                    	}

                    	//Guardar saldos despues de guardarlos en subcmayor en Histsalpro

                    	$histsalpro = Histsalpro::model()->find('id=:id and Codpro=:Codpro and CodPVen=:CodPVen', array(':id' => $model->nfactura, ':Codpro' => $produp->Codpro, ':CodPVen' => $detalle->CodPVen));

                    	// $productos = Submyproductos::model()->find('Codpro=:Codpro and CodPVen=:CodPVen', array(':Codpro' => $produp->Codpro, ':CodPVen' => $detalle->CodPVen));

                    	$productos = Submyproductos::model()->find('Codpro=:Codpro', array(':Codpro' => $produp->Codpro));

                    	if (!$histsalpro) {//Si no existe crearla	

                        	$histsalpro = new Histsalpro;

                        	$histsalpro->Codpro = $produp->Codpro;

                        	$histsalpro->CodPVen = $detalle->CodPVen;

                        	$histsalpro->SaldoAnt = $productos->SaldoAnt;

                        	$histsalpro->SaldoAct = $productos->SaldoAct;

                        	$histsalpro->fecha = date('Y-m-d_h.i.s'); //Fecha de la modificación Y-m-d h:mm:ss 	

                        	$histsalpro->save();

                    	}


                    	//llenar historicos de detalles de operaciones

                    	$histdetaoper = Histdetallesoper::model()->find('nfactura=:nfactura and Codpro=:Codpro', array(':nfactura' => $model->nfactura, ':Codpro' => $produp->Codpro));

                    	if (!$histdetaoper) {//Si no existe crearla	

                        	$histdetaoper = new Histdetallesoper;

                        	$histdetaoper->nfactura = $detalle->Id_sal; //

                        	$histdetaoper->Codprod = $detalle->Codprod; //

                        	$histdetaoper->cantidad = $detalle->cantidad; //

                        	$histdetaoper->Codpro = $produp->Codpro;

                        	$histdetaoper->SaldoDes = $detalle->SaldoDes; //

                        	$histdetaoper->importemne = ROUND($detalle->SaldoDes * $detalle->premn, 2); //

                        	$histdetaoper->importemn = ROUND($detalle->cantidad * $detalle->premn, 2); //

                        	$histdetaoper->Recargo = $detalle->Recargoca; //

                        	$histdetaoper->impventasmn = $detalle->imventas; //

                        	$histdetaoper->premn = $detalle->premn; //

                        	$histdetaoper->CodPVen = $detalle->CodPVen;

                        	$histdetaoper->cmay = $detalle->cmay; //

                        	$histdetaoper->prod = $detalle->prod;

                        	$histdetaoper->save();

                    	}

                	}//para todos los detalles cierra aqui

                	$factura = Facturas::model()->find('nfactura=:nfactura and CodCliente=:CodCliente and CodUEB=:CodUEB', array(':nfactura' => $model->nfactura, ':CodCliente' => $model->CodCliente, ':CodUEB' => $model->CodUEB));

                	// printf("rafael"); //para ver si entra aqui

                	//die();

                	if (!$factura) {//Si no existe crearla	

                    	$factura = new Facturas;

                    	$factura->CodCliente = $model->CodCliente;

                    	$factura->CodUEB = $model->CodUEB;

                    	$factura->nfactura = $objFac->nfactura;

                    	$factura->estado = $model->IdEstado;

                    	$factura->nfactura = $objFac->nfactura;

                    	$factura->estado = $model->IdEstado;

                    	$factura->ImporteMN = $objFac->ImporteMN;

                    	$factura->save();

                	}

            	}

        	}

        	Yii::app()->user->setFlash('success', 'Factura realizada satisfactoriamente');

    	} else {

        	Yii::app()->user->setFlash('error', 'No puede facturar, actualice su contrato');

    	}

	}



mi forma




<?php

/* @var $this DatossalController */

/* @var $model Datossal */

/* @var $form CActiveForm */

?>

<script>

	$(function() {

    	//Add, Save, Edit and Delete functions code

    	$(".btnEdit").on("click", Edit);

    	$(".btnDelete").on("click", Delete);

    	$("#btnAdd").on("click", Add);

    	ActualizarCodigo();

    	$.ajax({

        	url: 'index.php?r=datossal/actualizarFirmantes',

        	type: 'POST',

        	dataType: 'json',

        	data: {

            	"idCodigo": $('#Datossal_CodCliente').val()

        	},

        	success: function(data) {

            	$("#Datossal_CI").html(data.firmantes);

        	}

    	});


    	$.ajax({

        	url: 'index.php?r=datossal/actualizarCombos',

        	type: 'POST',

        	dataType: 'json',

        	data: {

            	"idCod": $('#Datossal_CodUEB').val()

        	},

        	success: function(data) {

            	$("#Datossal_CIFac").html(data.nfacturador);

        	}

    	});


	});


	function Add() {


    	if ($('#producto').val() !== '') {

        	var codigo = $('#incodigo').val() === '' ? '0' : $('#incodigo').val(); //incodigo 

        	var cantidad = $('#incantidad').val() === '' ? '0' : $('#incantidad').val();

        	var prod = $('#inprod').val() === '' ? '0' : $('#inprod').val();

        	var recargo = $('#inrecargo').val() === '' ? '0' : $('#inrecargo').val();

        	var cmay = $('#incmay').val() === '' ? '0' : $('#incmay').val();


        	$.ajax({

            	url: 'index.php?r=datossal/comprobarSaldo',

            	type: 'POST',

            	dataType: 'text',

            	data: {"codigo": codigo,

                	"cantidad": cantidad,

                	"prod": prod,

                	"recargo": recargo,

                	"cmay": cmay,

            	},

            	success: function(data) {

                	if (data.trim() === "ok")

                	{

                    	$("#tblData tbody").append(

                            	"<tr class='even'>" +

                            	"<td>" + codigo + "</td>" +

                            	"<td>" + $('#producto').val() + "</td>" +

                            	"<td>" + cantidad + "</td>" +

                            	"<td>" + prod + "</td>" +

                            	"<td>" + recargo + "</td>" +

                            	"<td>" + cmay + "</td>" +

                            	"<td><img src='images/update.png' class='btnEdit' title='Actualizar' style='cursor:pointer'>	<img src='images/delete.png' class='btnDelete' title='Eliminar' style='cursor:pointer'/></td>" +

                            	"</tr>");

                    	$(".btnEdit").off("click");

                    	$(".btnDelete").off("click");

                    	$(".btnEdit").on("click", Edit);

                    	$(".btnDelete").on("click", Delete);

                    	document.getElementById('incantidad').value = '';

                    	document.getElementById('inprod').value = '';

                    	document.getElementById('inrecargo').value = '';

                    	document.getElementById('incmay').value = '';


                    	$('#inprod').val("");

                    	$('#incodigo').val("");

                    	$('#producto').val("");

                    	$('#productos').val("");


                    	ActualizarCodigo();

                	}

                	else

                    	alert("No tiene saldo para facturar");

            	}

        	});

    	}

    	else {

        	alert('Debe introducir un producto');

    	}

	}

	;

	var oldCantidad;

	var oldprod;

	var oldrecargo;

	var oldcmay;


	function Edit() {

    	var par = $(this).parent().parent(); //tr 

    	var tdprod = par.children("td:nth-child(4)");

    	var tdrecargo = par.children("td:nth-child(5)");

    	var tdcmay = par.children("td:nth-child(6)");

    	var tdButtons = par.children("td:nth-child(7)");


    	oldCantidad = tdCantidad.html();

    	oldprod = tdprod.html();

    	oldrecargo = tdrecargo.html();

    	oldcmay = tdcmay.html();


    	tdCantidad.html("<input type='text' id='txtCantidad' value='" + tdCantidad.html() + "'/>");

    	tdprod.html("<input type='text' id='txtprod' value='" + tdprod.html() + "'/>");

    	tdrecargo.html("<input type='text' id='txtrecargo' value='" + tdrecargo.html() + "'/>");

    	tdcmay.html("<input type='text' id='txtcmay' value='" + tdcmay.html() + "'/>");

    	tdButtons.html("<img src='images/save.png' class='btnSave' title='Guardar' style='cursor:pointer'/>	<img src='images/cancel.gif' class='btnCancel' title='Cancelar' style='cursor:pointer'/>");


    	$(".btnEdit").off("click");

    	$(".btnDelete").off("click");

    	$(".btnSave").on("click", Save);

    	$(".btnCancel").on("click", Cancel);

    	$(".btnEdit").on("click", Edit);

    	$(".btnDelete").on("click", Delete);

	}

	;

	function Save() {


    	var par = $(this).parent().parent(); //tr

    	var tdCantidad = par.children("td:nth-child(3)");

    	var tdprod = par.children("td:nth-child(4)");

    	var tdrecargo = par.children("td:nth-child(5)");

    	var tdcmay = par.children("td:nth-child(6)");

    	var tdButtons = par.children("td:nth-child(7)");


    	tdCantidad.html(tdCantidad.children("input[type=text]").val());

    	tdprod.html(tdprod.children("input[type=text]").val());

    	tdrecargo.html(tdrecargo.children("input[type=text]").val());

    	tdcmay.html(tdcmay.children("input[type=text]").val());

    	tdButtons.html("<img src='images/update.png' class='btnEdit' title='Actualizar' style='cursor:pointer'/>	<img src='images/delete.png' class='btnDelete' title='Eliminar' style='cursor:pointer'/>");


    	$(".btnEdit").off("click");

    	$(".btnDelete").off("click");

    	$(".btnEdit").on("click", Edit);

    	$(".btnDelete").on("click", Delete);

	}

	;

	function Cancel() {

    	var par = $(this).parent().parent(); //tr

    	var tdCantidad = par.children("td:nth-child(3)");

    	var tdprod = par.children("td:nth-child(4)");

    	var tdrecargo = par.children("td:nth-child(5)");

    	var tdcmay = par.children("td:nth-child(6)");

    	var tdButtons = par.children("td:nth-child(7)");


    	tdCantidad.html(oldCantidad);

    	tdprod.html(oldprod);

    	tdrecargo.html(oldrecargo);

    	tdcmay.html(oldcmay);

    	tdButtons.html("<img src='images/update.png' class='btnEdit' title='Actualizar' style='cursor:pointer'/>	<img src='images/delete.png' class='btnDelete' title='Eliminar' style='cursor:pointer'/>");

    	$(".btnEdit").off("click");

    	$(".btnDelete").off("click");

    	$(".btnEdit").on("click", Edit);

    	$(".btnDelete").on("click", Delete);

	}

	;

	function Delete() {

    	var par = $(this).parent().parent(); //tr

    	$('#producto')

            	.append($("<option></option>")

                    	.attr("value", par.children("td:nth-child(1)").html())

                    	.text(par.children("td:nth-child(2)").html()));

    	ActualizarCodigo();

    	par.remove();

	}

	;

	function ActualizarCodigo() {


    	$('#incodigo').val($('#producto option:selected').val());


	}

	;


	$('#datossal-form').live('submit', function() {


    	var tbl = $('#tblData tbody tr').map(function() {

        	var row = $(this);

        	return {producto: row.find(':nth-child(1)').text(),

            	//return {	prcmay: row.find(':nth-child(2)').text(),

            	// return {	producto: row.find(':nth-child(3)').text(), 

            	//  productos: row.find(':nth-child(4)').text(),

            	cantidad: row.find(':nth-child(3)').text(),

            	prod: row.find(':nth-child(4)').text(),

            	recargo: row.find(':nth-child(5)').text(),

            	cmay: row.find(':nth-child(6)').text(),

        	};

    	}).get();

    	$.ajax({

        	url: 'index.php?r=datossal/salvarFactura',

        	type: 'POST',

        	dataType: 'text',

        	data: {"detalle": tbl,

            	"$query->may+1": $('#Datossal_Idn').val(),

            	"fecha": $('#Datossal_fecha').val(),

            	"nfactura": $('#Datossal_nfactura').val(),

            	"codsalida": $('#Datossal_Codsalida').val(),

            	"cliente": $('#Datossal_CodCliente').val(),

            	"codUEB": $('#Datossal_CodUEB').val(),

            	"1": $('#Datossal_Codde').val(),

            	"ci": $('#Datossal_CI').val(),

            	"idestado": $('#Datossal_IdEstado').val(),

            	"cifac": $('#Datossal_CIFac').val(),

            	"2": $('#Datossal_CodDoc').val(),

            	"citra": $('#Datossal_CITra').val(),

            	"1": $('#Datossal_CodOp').val(),

                    	"nconduce": $('#Datossal_NConduce').val(),

            	"norden": $('#Datossal_norden').val(),

            	"bultos": $('#Datossal_bultos').val(),

            	"entregar": $('#Datossal_entregar').val(),

            	"modelid": $('#modelid').val()

        	},

        	success: function(data) {

            	if (data === 'fail')

                	alert('Ya existe un registro con ese número consecutivo');

            	else

                	window.location.href = 'index.php?r=datossal/admin';

        	}

    	});

    	return false;

	});

</script>

<style>

	.mystyle

	{

    	background: white;

    	border-collapse: collapse;

    	width: 75%;

    	border: 1px #D0E3EF solid;


	}

	.mystyle th, .mystyle td

	{	

    	border: 1px white solid;

    	padding: 0.3em;

	}

	.mystyle th

	{

    	color: white;

    	background: #c00;

    	text-align: center;

	}

	.mystyle tr.even

	{

    	background: #F8F8F8;

	}

	.mystyle tr.odd

	{

    	background: #E5F1F4;

	}

	.mystyle tr.selected

	{

    	background: #BCE774;

	}

	.mystyle tbody tr:hover

	{

    	background: #ECFBD4;

	}

	.rojo1 {background-color: #FF0033; }

</style>

<!-- TemplateParam name="OptionalRegion1" type="boolean" value="true" -->

<!-- TemplateBeginIf cond="OptionalRegion1" --><!-- TemplateBeginEditable name="EditRegion1" -->

<div class="panel panel-default">

	<table>

    	<tr>

    	<div class="panel-heading">

        	<b contextmenu="Crear factura">Crear Factura en MN</b>

        	<b>(</b>

        	<b>Los campos con <span class="required">*</span> son necesarios.</b>

        	<b>)</b>

    	</div>

    	</tr>

	</table>

	<div class="panel-default">

    	<div class="form">

        	<?php

        	$form = $this->beginWidget('CActiveForm', array(

            	'id' => 'datossal-form',

            	'enableAjaxValidation' => TRUE,

        	));

        	$this->layout = '//layouts/column1';

        	?>

        	<?php echo '<input type="hidden" id="modelid" value="' . $model->Idn . '"/>'; ?><?php echo $form->errorSummary($model); ?>

        	<hr>          	

        	<table>

            	<tr>


                	<td>

                    	<?php echo $form->labelEx($model, 'CodUEB'); ?>

                    	<?php

                    	echo $form->dropDownList($model, 'CodUEB', CHtml::listData(Entidades::model()->findAll(array('order' => 'NEnt DESC')), 'CodUEB', 'NEnt'), array(

                        	'ajax' => array(

                            	'type' => 'POST',

                            	'url' => CController::createUrl('datossal/actualizarCombos'),

                            	'dataType' => 'json',

                            	'data' => array('idCod' => 'js:this.value'),

                            	'success' => 'function(data) {

                    	$("#Datossal_CIFac").html(data.nfacturador);  

                            	}')

                            	)

                    	);

                    	?>

                    	<?php echo $form->error($model, 'CodUEB'); ?>   


                	</td>

                	<td colspan="3" title="Selecione el cliente">

                    	<?php echo $form->labelEx($model, 'Cliente'); ?>

                    	<?php

                    	echo $form->dropDownList($model, 'CodCliente', CHtml::listData(Clientes::model()->findAll(array('order' => 'Descripcion')), 'CodCliente', 'Descripcion'), array(

                        	'ajax' => array(

                            	'type' => 'POST',

                            	'url' => CController::createUrl('datossal/actualizarFirmantes'),

                            	'dataType' => 'json',

                            	'data' => array('idCodigo' => 'js:this.value'),

                            	'success' => 'function(data) {

				$("#Datossal_CI").html(data.firmantes); 

			}')

                            	)

                    	);

                    	?>

                    	<?php echo $form->error($model, 'CodCliente'); ?>

                	</td>

            	</tr>

            	<tr>

                	<td>

                    	<?php echo $form->labelEx($model, 'Fecha'); ?>

                    	<?php

                    	$feriados = "['25/12/2017','01/01/2017','02/01/2017', '01/05/2017','25/07/2017','26/07/2017','27/07/2017','10/10/2017','25/12/2017','01/01/2015','02/01/2015', '01/05/2015','25/07/2015','26/07/2015','27/07/2015','10/10/2015','25/12/2015','01/01/2016','02/01/2016', '01/05/2016','25/07/2016','26/07/2016','27/07/2016','10/10/2016','25/12/2016','01/01/2018','02/01/2018', '01/05/2018','25/07/2018','26/07/2018','27/07/2018','10/10/2018','25/12/2018']";

                    	$this->widget('CJuiDatePickerEvents', array(

                        	'model' => $model,

                        	'attribute' => 'fecha',

                        	'value' => $model->fecha,

                        	'htmlOptions' => array('readonly' => "readonly"),

                        	'language' => 'es',

                        	'events' => array("beforeShowDay" => "function(date) {var events = $feriados ;

 				var current='';

              	//agrego el cero a izq si corresponde

                	if (date.getDate()<10)

                    	current='0'+date.getDate()+'/';

                	else

                    	current=date.getDate()+'/';

                	if (date.getMonth() + 1<10)

                    	current=current+'0'+(date.getMonth()+1)+'/';

                	else

                    	current=current+(date.getMonth()+1)+'/';

                	current=current+date.getFullYear();

                	//feriados, s&aacute;bados y domingos

                	return (jQuery.inArray(current, events) == -1 && date.getDay()!=0 && date.getDay()!=7)?[true, '']:[true,'rojo1','D&iacute;a no laborable'];},"),

                        	'options' => array(

                            	'autoSize' => true,

                            	'defaultDate' => $model->fecha,

                            	'dateFormat' => 'dd-mm-yy',

                            	// 'buttonImage' => Yii::app()->baseUrl . '/images/calendar.png',

                            	// 'buttonImageOnly' => TRUE,

                            	// 'buttonText' => 'Fecha',

                            	'dateFormat' => 'yy-mm-dd',

                            	'selectOtherMonths' => true,

                            	'showAnim' => 'slide',

                            	'showButtonPanel' => true,

                            	// 'showOn' => 'button',

                            	'selectOtherMonths' => true,

                            	'showOtherMonths' => true,

                            	'changeMonth' => true,

                            	'changeYear' => true,

                            	'minDate' => 'date-30("d-m-Y")', //fecha minima

                            	'maxDate' => "+20Y", //fecha maxima

                        	),

                    	));

                    	?>

                    	<?php echo $form->error($model, 'fecha'); ?>   		

                	</td>

                	<td title="Selecione quien factura">

                    	<?php echo $form->labelEx($model, 'CIFac'); ?><?php echo $form->dropDownList($model, 'CIFac', array());

                    	?><?php echo $form->error($model, 'CIFac'); ?> 

                	</td>


                	<td title="Al seleccionar el cliente se muestra los autorizados a firmar facturas">

                    	<?php echo $form->labelEx($model, 'CI'); ?> <?php echo $form->dropDownList($model, 'CI', array()); ?>

                    	<?php echo $form->error($model, 'CI'); ?>  

                	</td>


            	</tr>

            	<tr>

                	<td>

                    	<?php echo $form->labelEx($model, 'bultos'); ?> <?php echo $form->textField($model, 'bultos', array('size' => 10, 'maxlength' => 30)); ?> <?php echo $form->error($model, 'bultos'); ?></td>        	





                	<td title="Selecione el transportista">

                    	<?php echo $form->labelEx($model, 'CITra'); ?><?php echo $form->dropDownList($model, 'CITra', CHtml::listData(NomTransportista::model()->findAll(array('order' => 'chofer ASC')), 'CITra', 'chofer', 'chapa'));

                    	?><?php echo $form->error($model, 'CITra'); ?> 

                	</td>

                	<td title="Generada si no se ha pagado">

                    	<?php echo $form->labelEx($model, 'Estado'); ?><?php echo $form->dropDownList($model, 'IdEstado', CHtml::listData(Estado::model()->findAll(array('order' => 'Descripcion DESC')), 'IdEstado', 'Descripcion'));

                    	?><?php echo $form->error($model, 'IdEstado'); ?> 

                	</td>

            	</tr>

            	<tr>

                	<td title="Orden de despacho">

                    	<?php echo $form->labelEx($model, 'norden'); ?> <?php echo $form->textField($model, 'norden', array('size' => 10, 'maxlength' => 15)); ?> 

                    	<?php echo $form->error($model, 'norden'); ?>        	

                	</td>


                	<td title="Número de los conduces hechos previamente en caso necesario">

                    	<?php {

                        	echo $form->labelEx($model, 'NConduce');

                        	?>

                        	<?php echo $form->textArea($model, 'NConduce', array('rows' => 1, 'cols' => 22, 'readonly' => FALSE)); ?>

                        	<?php

                        	echo $form->error($model, 'NConduce');

                    	}

                    	?>

                	</td>

                	<td title="Donde se entrega el producto en caso necesario">

                    	<?php {

                        	echo $form->labelEx($model, 'entregar');

                        	?>

                        	<?php echo $form->textArea($model, 'entregar', array('rows' => 1, 'cols' => 18, 'readonly' => FALSE)); ?>

                        	<?php

                        	echo $form->error($model, 'entregar');

                    	}

                    	?>

                	</td>

 				

            	</tr>

        	</table>

    	</div>

	</div>

</div>

<!-- ----------------------------------------Llenar detalles de los productos, segunda tabla ------------------------------------- -->

<div>

	<fieldset>

    	<legend>Llenar datos de los productos</legend>

    	<table>

        	<tr>

            	<td width="129" title="Código de venta"><label><span class="selected">C&oacute;digo</span></label>

                	<?php

                	echo CHtml::textField('incodigo', '', array(

                    	'id' => 'incodigo',

                    	'ajax' => array(

                        	'type' => 'POST',

                        	'url' => CController::createUrl('datossal/obtenerProducto'),

                        	'dataType' => 'json',

                        	'data' => array(

                            	'incodigo' => 'js:this.value',

                            	'idde' => 'js:$("#Datossal_Codde").val()',

                        	),

                        	'success' => 'function(data) { 

                                            	$("#producto").val(data.descripcion);

                                            	$("#inproductos").val(data.codigo);                                        	

                                            	$("#preciomn").val(data.preciomn);

                                            	$("#existencia").val(data.existencia);

                                            	$("#Idum").val(data.Idum);  

                                            	$("#codpro").val(data.CodSubp); 

                                            	$("#CodPVen").val(data.CodPVen);  

                                            	}')

                	));

                	?>

            	</td>

            	<td title="Cantidad a facturar"><label class="selected">Cantidad</label>

                	<input name="text" type="text" id="incantidad" value="" size="8" />

            	</td>

            	<td colspan="3" title="Nombre del producto"><label class="odd">Producto</label>

                	<?php

                	echo CHtml::textField('producto', '', array('size' => 70, 'readonly' => true));

                	?>

            	</td>

            	<td width="140" title="Precio May sin impuesto"><label class="odd">Precio MN</label>

                	<input name="text2" type="text" id="preciomn" size="6" readonly="true"/>

            	</td>

 			

        	</tr>

        	<tr>

            	<td width="140" title="Unidad de medida"><label class="odd">UM</label>

                	<input type="text" id ="Idum" size="20" readonly="true"/>

            	</td>

            	<td width="140" title="Saldo actual"><label class="odd">Existencia</label>

                	<input  type="text" id="existencia" onchange="true" size="6" readonly="true"/>

            	</td>

            	<td width="140" title="Mayorista no aplica impuesto"><label class="odd">¿Mayorista?</label>

                	<h4>

                    	<?php

                    	echo CHtml::dropDownList('incmay', '', CHtml::listData(Cmayorista::model()->findAll(array('order' => 'Descripcion DESC')), 'IdMay', 'Descripcion'));

                    	?>

                	</h4>

            	</td>

            	<td width="140" class="odd" title="Si, si lleva Recargo"><label>Recargo</label>

                	<h4>

                    	<?php

                    	echo CHtml::dropDownList('inrecargo', '', CHtml::listData(Enum::model()->findAll(array('order' => 'Id')), 'Id', 'Nom'));

                    	?>

                	</h4></td>

            	<td width="140" title="Es Producción la que hace en la empresa"><label class="odd">¿Producción?</label>

                	<h4>

                    	<?php

                    	echo CHtml::dropDownList('inprod', '', CHtml::listData(Entprod::model()->findAll(array('order' => 'Descripcion DESC')), 'IdEnt', 'Descripcion'));

                    	?>

                	</h4>

            	</td>

            	<td width="24" title="Código del almacén"><label>Almacén</label>

                	<input name="text2" type="text" id ="CodPVen" size="6" readonly="true"/>

            	</td>

        	</tr>

        	<tr>

            	<td><input name="button" type="button" id="btnAdd" value="Adicionar Producto"/>

            	</td>

        	</tr>

    	</table>

    	<table id="tblData" class="mystyle">

        	<thead>

            	<tr>

                	<th>Código</th>

                	<th>Producto_Nominal</th>

                	<th>Cantidad</th>

                	<th>¿Producción?</th>

                	<th>¿Recargo?</th>

                	<th>¿Mayorista?</th>

            	</tr>

        	</thead>

        	<tbody>

            	<?php

            	foreach ($model->detalleFacturas as $value) {

                	echo "<tr>";

                	echo "<td>" . $value->idProducto->Codprod . "</td>";

                	echo "<td>" . $value->idProducto->NProductos . "</td>";

                	echo "<td>" . $value->cantidad . "</td>";

                	echo "<td>" . $value->prod . "</td>";

                	echo "<td>" . $value->recargo . "</td>";

                	echo "<td>" . $value->cmay . "</td>";

                	echo "<td><img src='" . Yii::app()->request->baseUrl . "/images/update.png' class='btnEdit' title='Actualizar' style='cursor:pointer'>

         					<img src='" . Yii::app()->request->baseUrl . "/images/delete.png' class='btnDelete' title='Eliminar' style='cursor:pointer'/></td>";

                	echo "</tr>";

            	}

            	?>

        	</tbody>

    	</table>

    	<div class="buttons">

        	<?php

        	echo CHtml::submitButton($model->isNewRecord ? 'Crear' : 'Guardar');

        	$disable = true;

        	if (!$model->isNewRecord)

            	$disable = false;

        	?>

    	</div>

    	<?php $this->endWidget(); ?>

</div><!-- form -->



Buenas, Rafael.

No se si he entendido bien tu post, pero lo que entiendo es que deseas que un usuario o pueda enviar una factura hasta que la anterior haya sido procesada.

Lo más fácil en mi opinión sería sustituir tu botón submit por el siguiente botón:




echo CHtml::button('Send', 

                   array(

                        'id' => 'sendForm',

                        'onclick' => '

                                     $("#sendForm").prop("disabled", true);

                                     $("#id-form").submit();

                                     '

                                     ));



Cuando se haga click el botón se desactiva y se envía el formulario. Una vez el formulario es procesado, la página se vuelve a recargar, con lo que el botón vuelve a activarse. De esta forma no puedes enviar el formulario mientras se esté procesando un envío anterior.

Además, no tienes que tocar para nada la base de datos y puedes dejar tu campo en autonumérico.

De todas formas, a mi me gusta (y lo veo muy útil) que las facturas siguan expresiones regulares y no están formadas sólo por números correlativos. De esta forma simplemente viendo el número de factura puedes saber más datos del pedido sin tener que consultar nada más.

Por ejemplo:

  • ES001 : pedido nº 001 a españa

  • 34-001: pedido nº 001 a españa

Un saludo.

Hola lagogz, buenos dias aca, alla buenas tardes, mira cambie el botón submit que tenia por el que me indicaste, pero, al hacer clic sobre él, me lo desabilita, pero no ejecuta la acción crear factura.

En cuanto al post, es realmante lo que quiero, que tengo el Idn como autonumerico y al hacer clic me cre la factura y no permita hacer mas facturas si diera mas clic.

Gracias por la ayuda que me puedas dar.

Buenas, Rafael.

Siguiendo tu código, el identificador de tu formulairo debería ser "datossal-form", por lo que tendrías que escribir el siguiente botón:




echo CHtml::button('Send', 

                   array(

                        'id' => 'sendForm',

                        'onclick' => '

                                     $("#sendForm").prop("disabled", true);

                                     $("#datossal-form").submit();

                                     '

                                     ));



Esto debería lanzarte la acción asociada a este formulario. El identificador que yo te puse era un ejemplo.

Lo he probado y funciona. En caso de que no te funcione, qué es lo que te muestra?

Un saludo.