Aplicació de facturació trimestral

De wikijoan
Salta a la navegació Salta a la cerca

Enunciat del problema

Formulari aplicacio facturacio.jpg

Tenim una empresa amb 4 delegacions, i volem portar el control de la facturació trimestral de cadascuna de les delegacions.

Fer una petita aplicació web amb les següents especificacions. La interfície web consta d'una taula a l'esquerra, i un petit formulari a la dreta. La taula consta de tres camps i 4 files amb les següents dades:

  • capçalera: sucursal, nom, telefon, mail
  • dades:
    • Barcelona;Arnau Guinovart;93.345.54.45;aguinovart@gmail.com
    • Tarragona;Maria Peris;977.34.34.22;mperis@gmail.com
    • Lleida;Josep Anglerill;973.33.44.55;janglerill@gmail.com
    • Girona;Montserrat Sirera;972.44.55.66;msirera@gmail.com

El camp sucursal és un link. Quan cliquem sobre la sucursal s'executarà la funció de Javascript: escriure_formulari().

El formulari consta dels següents camps:

  • Sucursal. Camp de text que no es pot escriure (atribut readonly).
  • Nom. Camp de text que no es pot escriure (atribut readonly).
  • Any. Llista desplegable amb els següents valors: 2015, 2016, 2017, 2018, 2019.
  • Trimestre. Llista desplegable amb els següents valors: 1T, 2T, 3T, 4T (que es correspon amb els 4 trimestres).
  • Facturació. Caixa de text. Regla de validació: número que admet dues posicions decimals.

Es tracta d'omplir semi-automàticament els camps del formulari i enviar les dades del formulari a una taula de MySQL. Quan cliquem sobre la sucursal en la taula se'ns omplirà automàticament els camps sucursal i nom del formulari. Aleshores seleccionarem un any i trimestre, posarem un valor decimal de facturació, i només quan totes les dades estiguin plenes (regla de validació global per a tot el formulari), enviarem les dades per ser inserides en la taula jbalmes.facturacio (sucursal, nom, year, trimestre, euros).

  • l'aplicatiu ha de tenir

A continuació se't mostra una estructura possible de l'aplicatiu web, sense cap mena de full d'estils.

CREATE TABLE facturacio(
sucursal varchar(30) not null,
nom varchar(30) not null,
year smallint not null,
trimestre varchar(2) not null,
euros decimal(10,2) not null
);

insert into facturacio values ('Barcelona', 'Arnau Guinovart', 2015, '1T', 1854.34);

Solució parcial

NOTA: El professor et presenta una possible solució. Ara bé, la teva solució ha d'incloure entre d'altres les següents millores:

  • fitxer d'estils CSS extern.
  • fitxer de funcions javascript extern.
  • els events javascript que implementis els has de definir en un fitxer .js extern amb el mètode addEventListener.

script facturacio.php:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="es">
<head>
<meta charset="UTF-8" />
<title>Formulari de contactes (amb varis mails)</title>

<script>
function escriure_formulari(obj) {
	console.log(obj.text);
	var taula = document.getElementById("taula_sucursals");
	var files = taula.rows;
	for (i=1;i<files.length; i++) {
		//alert(files[i].cells[0].innerHTML);
		str = files[i].cells[0].innerHTML;
		if (str.indexOf(obj.text) > 0) {
			//document.frm_facturacio.sucursal.value = obj.text;
			document.frm_facturacio.sucursal.value = obj.innerHTML;
			document.frm_facturacio.nom.value = files[i].cells[1].innerHTML;
		}


	}
}

function validar_numero_2decimals(obj){
	val = obj.value;
	//alert(val);

	var patro=/^\d+(\.\d{1,2})?$/;
	if(!patro.test(val)){
		obj.value = "";
		return false;
	}else{
		return true;
	}
}

function controlar_camps_formulari(){
	forms = document.getElementsByTagName("form");
	for (i=0;i<forms[0].elements.length-1;i++) {
		//alert(forms[0].elements[i].value);
		if (forms[0].elements[i].value=="") {
			alert("camp buit: " + forms[0].elements[i].name);
			return false;
		}
	}


}

</script>
</head>
<body>
<?php

if (isset($_POST['sucursal'])) {
	$vsucursal=$_POST['sucursal'];
	$vnom=$_POST['nom'];
	$vyear=$_POST['year'];
	$vtrimestre=$_POST['trimestre'];
	$veuros=$_POST['euros'];

	if ($vsucursal!="") {
		include("open_db.php");

		$sqlstring  = "INSERT INTO facturacio ";
		$sqlstring .= "(sucursal, nom, year, trimestre, euros) values (";
		$sqlstring .= "'" . $vsucursal . "','" . $vnom . "'," . $vyear . ",'" . $vtrimestre . "'," . $veuros . ")";

		//echo $sqlstring."<br />";
		//$result = mysqli_query($conn, $sqlstring);

	    if (!($result = mysqli_query($conn, $sqlstring))) {
	        echo "Error: ".mysqli_error($conn)."<br />";
			echo "NO s'ha inserit el valor a la base de dades.<br />";
	    } else {

			echo "S'ha inserit el valor a la base de dades.<br />";
		}

		include("close_db.php");
	}
}
?>

<h1>Facturació per delegacions</h1>
<table id="taula_sucursals" border="1">
<tr><td><b>Delegació</b></td><td><b>Nom</b></td><td><b>Telèfon</b></td><td><b>Mail</b></td></tr>
<tr><td><a href="#" onclick="escriure_formulari(this)">Barcelona</a></td><td>Arnau Guinovart</td><td>93.345.54.45</td><td>aguinovart@gmail.com</td></tr>
<tr><td><a href="#" onclick="escriure_formulari(this)">Tarragona</a></td><td>Maria Peris</td><td>977.34.34.22</td><td>mperis@gmail.com</td></tr>
<tr><td><a href="#" onclick="escriure_formulari(this)">Lleida</a></td><td>Josep Anglerill</td><td>973.33.44.55</td><td>janglerill@gmail.com</td></tr>
<tr><td><a href="#" onclick="escriure_formulari(this)">Girona</a></td><td>Montserrat Sirera</td><td>972.44.55.66</td><td>msirera@gmail.com</td></tr>
</table>
<br />
<form name="frm_facturacio" method="post" onsubmit="controlar_camps_formulari()" action="facturacio.php" >
			<label>Sucursal: </label> <input type="text" name="sucursal" readonly />
			<br />

			<label>Nom: </label> <input type="text" name="nom" readonly />
			<br />

			<label>Any: </label> 
			<select name="year" >
			<option value="2017">2017</option>
			<option value="2018">2018</option>
			<option value="2019">2019</option>
			<option value="2020" selected="selected">2020</option>
			</select>
			<br />

			<label>Trimestre: </label> 
			<select name="trimestre" >
			<option value="1">1T</option>
			<option value="2">2T</option>
			<option value="3">3T</option>
			<option value="4">4T</option>
			</select>
			<br />

			<label>Facturació: </label> <input type="text"  name="euros" onchange="validar_numero_2decimals(this)" /> (format: punt decimal)
			<br />

			<input type="submit" value="Enviar" />
</form>

</body>
</html>

script open.php:

<?php
$conn = mysqli_connect("localhost", "alumne", "keiL2lai", "jbalmes");
if (!$conn) {
    $log->error('Could not connect: ' . mysql_error());
    die('Could not connect: ' . mysql_error());
}

mysqli_set_charset($conn,'utf8');
?>

script close.php:

<?php
mysqli_close($conn);
?>

Solució addEventListener

...
<script>
...
function carregar_events(){
	var enllacos = document.links;
	for (i=0;i<enllacos.length; i++) {
		//alert(enllacos[i].href);
		enllacos[i].addEventListener("click", function(){escriure_formulari(this)});
	}
}
...
</script>
...
<body onload="carregar_events()">
...

i també ho podem fer d'una manera més genèrica, cercant els enllaços que hi ha dins de les cel.les:

...
<script>
...
function carregar_events(){
	var taula = document.getElementById("taula_sucursals");
	var files = taula.rows;
	for (i=1;i<files.length; i++) {
		files[i].children[0].children[0].addEventListener("click", function(){escriure_formulari(this)});
	}
}
...
</script>
...
<body onload="carregar_events()">
....

En aquest cas hem de pensar el nostre document com si fos XML (veure childNodes). És la manera més general de recórrer l'estructura d'una document web.

Millores a implementar

  • Solució amb addEventListener.
  • Posar automàticament l'any actual (segons la data del sistema)
  • Posar automàticament el trimestre actual (segons la data del sistema)
  • Ficar el codi javascript en un fitxer extern
  • Ficar un full d'estils extern, i treballar la capa de disseny i maquetació. Concretament, la gestió de la validació dels camps del formulari.
  • Eliminar el botó Enviar. Després de posar el valor de la facturació, ja s'envien les dades del formulari al servidor.
  • En el servidor, si es tornen a enviar les dades corresponents a un any i trimestre, fer un update en comptes d'un insert.
  • petit script informe.php: per cada any, avariguar quina sucursal ha facturat més diners.
  • etc...

Solució 2

En aquesta solució hem eliminat tota la part de PHP i ens centrem en la part de javascript (el front-end). Objectius:

  • volem separar totalment la part de html i la parts de javascript
  • volem que el codi funcioni per al 2020, 2021,..., 2050. Han d'aparèixer els últims 4 anys a partir de l'actual.
  • Volem que l'any i el trimestre surtin bé (en el sentit de portar la comptabilitat d'una empresa). Si ara estem a gener/febrer de 2021, l'últim trimestre tancat és el 4rt trimestre de 2020: 4T 2020.
  • Tots els events amb addEventListener.

Us passo dos fitxers de solució:

script facturacio.html:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="es">
<head>
<meta charset="UTF-8" />
<title>Formulari de contactes (amb varis mails)</title>

</head>

<body>

<h1>Facturació per delegacions</h1>
<table id="taula_sucursals" border="1">
<tr><td><b>Delegació</b></td><td><b>Nom</b></td><td><b>Telèfon</b></td><td><b>Mail</b></td></tr>
<tr><td><a href="#">Barcelona</a></td><td>Arnau Guinovart</td><td>93.345.54.45</td><td>aguinovart@gmail.com</td></tr>
<tr><td><a href="#">Tarragona</a></td><td>Maria Peris</td><td>977.34.34.22</td><td>mperis@gmail.com</td></tr>
<tr><td><a href="#">Lleida</a></td><td>Josep Anglerill</td><td>973.33.44.55</td><td>janglerill@gmail.com</td></tr>
<tr><td><a href="#">Girona</a></td><td>Montserrat Sirera</td><td>972.44.55.66</td><td>msirera@gmail.com</td></tr>
</table>
<br />
<form name="frm_facturacio" method="post" action="facturacio.php" >
			<label>Sucursal: </label> <input type="text" name="sucursal" readonly />
			<br />

			<label>Nom: </label> <input type="text" name="nom" readonly />
			<br />

			<label>Any: </label> 
			<select name="year" id="year" >
			</select>
			<br />

			<label>Trimestre: </label> 
			<select name="trimestre" id="trimestre">
			<option value="1">1T</option>
			<option value="2">2T</option>
			<option value="3">3T</option>
			<option value="4">4T</option>
			</select>
			<br />

			<label>Facturació: </label> <input type="text"  name="euros" /> (format: punt decimal)
			<br />

			<input type="submit" value="Enviar" />
</form>

</body>
</html>

<!-- important al final -->
<script src="script.js"></script>

script script.js:

//s'executa quan s'ha carregat la pàgina
document.body.addEventListener("load", inici(), false);

function inici() {
	document.forms[0].euros.addEventListener("change",
        function (event) {
            event.preventDefault();
            validar_numero_2decimals(this);
        }, 
        false);

	document.forms[0].addEventListener("submit",
        function (event) {
            event.preventDefault();
            controlar_camps_formulari();
        }, 
        false);

	var year = new Date().getFullYear()-1;
	var month = new Date().getMonth();
	//console.log(year);
	var trimestre;
	if (month>=0 && month<=2) {//hem de posar el trimestre anterior. Si ara estem al trimestre 1, hem de posar el 4
		trimestre = 4;
	} else if (month>=3 && month<=5) {
		trimestre = 1;
	} else if (month>=6 && month<=8) {
		trimestre = 2;
	} else {
		trimestre = 3;
	}

	//creem les opcions de la select
	var sel_year = document.getElementById("year");

	//Create and append the options
	for (var i = 0; i < 4; i++) {
	    var option = document.createElement("option");
	    option.value = year-i;
	    option.text = year-i;
	    console.log(year-i)
	    if (trimestre==4 && i==1) {
		    option.selected = "selected"
		} else if (i==year) {
		    option.selected = "selected"
		}
	    sel_year.appendChild(option);
	}

	//console.log(trimestre);

	var sel_trimestre = document.getElementById("trimestre");
	var opcions = sel_trimestre.childNodes;
	//console.log(opcions)
	for(var i=0; i<opcions.length; i++) {
    	//console.log(opcions[i].nodeType);
    	if (opcions[i].nodeType==1) {
    		//console.log(opcions[i].value);
    		if(opcions[i].value == trimestre) { //hem de posar selected
    			opcions[i].selected = "selected"
    		}
    	}
	}

	//links
	//https://stackoverflow.com/questions/6041593/adding-click-event-via-addeventlistener-to-confirm-navigation-from-a-hyperlink
	var links = document.links;
	var anchors = document.getElementsByTagName("a");
		//console.log(anchors.length);
	for (var i=0; i<anchors.length; i++) { //recorrem tots els links
		//posem els events associats als links
		anchors[i].addEventListener("click", 
        function (event) {
            event.preventDefault();
            escriure_formulari(this);
        }, 
        false);
	}
}

function escriure_formulari(obj) {
	console.log(obj.text);
	var taula = document.getElementById("taula_sucursals");
	var files = taula.rows;
	for (i=1;i<files.length; i++) {
		//alert(files[i].cells[0].innerHTML);
		str = files[i].cells[0].innerHTML;
		if (str.indexOf(obj.text) > 0) {
			//document.frm_facturacio.sucursal.value = obj.text;
			document.frm_facturacio.sucursal.value = obj.innerHTML;
			document.frm_facturacio.nom.value = files[i].cells[1].innerHTML;
		}

	}
}

function validar_numero_2decimals(obj){
	val = obj.value;
	//alert(val);

	var patro=/^\d+(\.\d{1,2})?$/;
	if(!patro.test(val)){
		obj.value = "";
		return false;
	}else{
		return true;
	}
}

function controlar_camps_formulari(){
	forms = document.getElementsByTagName("form");
	for (i=0;i<forms[0].elements.length-1;i++) {
		//alert(forms[0].elements[i].value);
		if (forms[0].elements[i].value=="") {
			alert("camp buit: " + forms[0].elements[i].name);
			return false;
		}
	}

}

Entrega

Els alumnes entregaran al Google Classroom tots els fitxers generats. S'empaquetaran tots aquests fitxers i es pujaran al Google Classroom dins del termini d'entrega de la pràctica.

Recorda la normativa per entregar les pràctiques al Schoology: ASIX-M10-UF2#Normativa_d.27entrega_de_les_pr.C3.A0ctiques_al_Schoology


creat per Joan Quintana Compte, gener 2021