From 043c11a4edc5ca40f387e30130c3a3903d3d4794 Mon Sep 17 00:00:00 2001
From: Juan Ferrer Toribio <juan.ferrer.toribio@gmail.com>
Date: Thu, 9 Mar 2017 13:30:39 +0100
Subject: [PATCH] backup

---
 app.js                               |   1 -
 debian/changelog                     |   2 +-
 debian/control                       |   2 +-
 debian/install                       |   3 +-
 forms/ecomerce/basket/style.css      |  11 ++--
 forms/ecomerce/basket/ui.xml         |  82 +++++++++++++--------------
 forms/ecomerce/confirm/style.css     |   9 ---
 forms/ecomerce/ticket/style.css      |  13 +++--
 forms/ecomerce/ticket/ui.xml         |  38 ++++++++-----
 image/logo.png                       | Bin 0 -> 8577 bytes
 index.php                            |   1 -
 js/hedera/app.js                     |   2 +-
 js/hedera/login.js                   |   4 +-
 js/hedera/report.js                  |   1 -
 js/htk/style.css                     |   3 +-
 package.json                         |   2 +-
 pages/main/ui.php                    |  46 +--------------
 reports/delivery-note/locale/es.json |   3 +
 reports/delivery-note/ui.xml         |   2 +-
 rest/core/recover-password.php       |   6 +-
 web/html-service.php                 |  13 ++++-
 web/html.php                         |  73 ++++++++++++++++--------
 web/json-service.php                 |   1 +
 web/rest-service.php                 |  39 +++++++++++++
 web/service.php                      |  59 +++++++------------
 web/unavailable.html                 |  17 ++++--
 26 files changed, 227 insertions(+), 206 deletions(-)
 create mode 100644 image/logo.png
 create mode 100644 reports/delivery-note/locale/es.json

diff --git a/app.js b/app.js
index 138ca36b..28b7aaf2 100644
--- a/app.js
+++ b/app.js
@@ -61,4 +61,3 @@ function loadLocale (cb)
 				cb (require.context ('js', true, /locale\/en.json$/)); });
 	}
 }
-
diff --git a/debian/changelog b/debian/changelog
index 45f05bdb..c9b5ce4b 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,4 +1,4 @@
-hedera-web (2.0.1) stable; urgency=low
+hedera-web (2.0.3) stable; urgency=low
 
   * Initial Release.
 
diff --git a/debian/control b/debian/control
index d3ccdba8..05e31365 100644
--- a/debian/control
+++ b/debian/control
@@ -9,7 +9,7 @@ Vcs-Git: git://www.verdnatura.es/var/git/hedera-web
 
 Package: hedera-web
 Architecture: all
-Depends: apache2, php5-mysql, php5-mcrypt, php5-ssh2, php-vn-lib, php-acpu, nodejs, npm
+Depends: apache2, php5-mysql, php5-mcrypt, php5-ssh2, php5-apcu, php-vn-lib, nodejs, npm
 Suggests: php-text-captcha, php5-imap
 Section: misc
 Priority: optional
diff --git a/debian/install b/debian/install
index ddaaaa78..b709bf6e 100644
--- a/debian/install
+++ b/debian/install
@@ -10,5 +10,6 @@ reports                     usr/share/hedera-web
 rest                        usr/share/hedera-web
 index.php                   usr/share/hedera-web
 package.json                usr/share/hedera-web
-build                       usr/share/hedera-web
 manifest.json               usr/share/hedera-web
+webpack.config.json         usr/share/hedera-web
+build                       usr/share/hedera-web
diff --git a/forms/ecomerce/basket/style.css b/forms/ecomerce/basket/style.css
index bed6bd76..e7c05999 100644
--- a/forms/ecomerce/basket/style.css
+++ b/forms/ecomerce/basket/style.css
@@ -8,9 +8,10 @@
 }
 .basket .head
 {
+	padding: 0;
 	padding-bottom: 2em;
-	margin: 0;
 	border-bottom: 1px solid #DDD;
+	margin-bottom: 1em;
 }
 .basket .head p
 {
@@ -22,13 +23,9 @@
 
 /* Lines */
 
-.basket .lines
-{
-	padding: .8em 0;
-}
 .basket .line
 {
-	padding: 1em 0;
+	padding: .5em 0;
 }
 .basket .line > .delete
 {
@@ -48,7 +45,7 @@
 .basket .line > p
 {
 	margin: .1em 0;
-	margin-left: 7.5em;
+	margin-left: 6em;
 }
 .basket .line .subtotal
 {
diff --git a/forms/ecomerce/basket/ui.xml b/forms/ecomerce/basket/ui.xml
index 07d111df..549a07af 100755
--- a/forms/ecomerce/basket/ui.xml
+++ b/forms/ecomerce/basket/ui.xml
@@ -26,50 +26,48 @@
 				</htk-text>
 			</p>
 		</div>
-		<div class="lines">
-			<htk-repeater form-id="iter" renderer="repeaterFunc">
-				<db-model id="items" property="model" updatable="true">
-					<custom>
-						SELECT i.id, i.amount, i.price, a.Article, a.Categoria, 
-						a.Medida, a.Tallos, a.Color, o.Abreviatura, a.Foto
-							FROM basket_item i
-								JOIN vn2008.Articles a ON a.Id_Article = i.item_id
-								LEFT JOIN vn2008.Origen o ON a.id_origen = o.id
-					</custom>
-				</db-model>
+		<htk-repeater form-id="iter" renderer="repeaterFunc">
+			<db-model id="items" property="model" updatable="true">
 				<custom>
-					<div class="line">
-						<htk-button
-							form="iter"
-							column="ticket_id"
-							class="delete"
-							tip="_Remove"
-							icon="delete"
-							on-click="onDeleteClick"/>
-						<htk-image
-							form="iter"
-							column="Foto"
-							class="photo"
-							directory="catalog"
-							subdir="200x200"
-							full-dir="900x900"/>
-						<p class="concept">
-							<htk-text form="iter" column="Article"/> 
-							<htk-text form="iter" column="Medida"/> 
-							<htk-text form="iter" column="Categoria"/>
-						</p>
-						<p class="amount">
-							<htk-text form="iter" column="amount"/> x
-							<htk-text form="iter" column="price" format="%.2d€"/>
-							<span class="subtotal">
-								<htk-text id="subtotal" format="%.2d€"/>
-							</span>
-						</p>
-						<div class="clear"/>
-					</div>
+					SELECT i.id, i.amount, i.price, a.Article, a.Categoria, 
+					a.Medida, a.Tallos, a.Color, o.Abreviatura, a.Foto
+						FROM basket_item i
+							JOIN vn2008.Articles a ON a.Id_Article = i.item_id
+							LEFT JOIN vn2008.Origen o ON a.id_origen = o.id
 				</custom>
-			</htk-repeater>
-		</div>
+			</db-model>
+			<custom>
+				<div class="line">
+					<htk-button
+						form="iter"
+						column="ticket_id"
+						class="delete"
+						tip="_Remove"
+						icon="delete"
+						on-click="onDeleteClick"/>
+					<htk-image
+						form="iter"
+						column="Foto"
+						class="photo"
+						directory="catalog"
+						subdir="200x200"
+						full-dir="900x900"/>
+					<p class="concept">
+						<htk-text form="iter" column="Article"/> 
+						<htk-text form="iter" column="Medida"/> 
+						<htk-text form="iter" column="Categoria"/>
+					</p>
+					<p class="amount">
+						<htk-text form="iter" column="amount"/> x
+						<htk-text form="iter" column="price" format="%.2d€"/>
+						<span class="subtotal">
+							<htk-text id="subtotal" format="%.2d€"/>
+						</span>
+					</p>
+					<div class="clear"/>
+				</div>
+			</custom>
+		</htk-repeater>
 	</div>
 </div>
 </vn>
diff --git a/forms/ecomerce/confirm/style.css b/forms/ecomerce/confirm/style.css
index 01dbb62d..3ab459fe 100644
--- a/forms/ecomerce/confirm/style.css
+++ b/forms/ecomerce/confirm/style.css
@@ -2,14 +2,6 @@
 {
 	color: #555;
 }
-.confirm .card
-{
-	padding: 2.2em 2.5em;
-}
-.confirm .summary
-{
-	margin-bottom: 1em;
-}
 .confirm .address
 {
 	margin-top: .8em;
@@ -119,4 +111,3 @@
 {
 	margin: .1em 0;
 }
-
diff --git a/forms/ecomerce/ticket/style.css b/forms/ecomerce/ticket/style.css
index e7b533df..142ef4da 100644
--- a/forms/ecomerce/ticket/style.css
+++ b/forms/ecomerce/ticket/style.css
@@ -31,13 +31,18 @@
 {
 	padding: .5em 0;
 }
+.ticket .line > .photo
+{
+	margin-right: 1em;
+	float: left;
+	border-radius: 50%;
+	height: 3.2em;
+	width: 3.2em;
+}
 .ticket .line p
 {
 	margin: .1em 0;
-}
-.ticket .amount
-{
-	float: left;
+	margin-left: 4em;
 }
 .ticket .subtotal
 {
diff --git a/forms/ecomerce/ticket/ui.xml b/forms/ecomerce/ticket/ui.xml
index 96125e7b..605bb999 100755
--- a/forms/ecomerce/ticket/ui.xml
+++ b/forms/ecomerce/ticket/ui.xml
@@ -6,12 +6,12 @@
 		<db-model id="ticket-data" property="model">
 			<custom>
 				SELECT t.id, date, a.Agencia, note, p.name province,
-				zip_code, city, c.name, consignee, invoice, delivery
+					zip_code, city, c.name, consignee, invoice, delivery
 					FROM ticket_view t
-					JOIN address_view c ON t.address_id = c.id
-					JOIN vn2008.Agencias a ON t.agency_id = a.Id_Agencia
-					JOIN vn2008.province p ON c.province_id = p.province_id
-						WHERE t.id = #ticket
+						JOIN address_view c ON t.address_id = c.id
+						JOIN vn2008.Agencias a ON t.agency_id = a.Id_Agencia
+						JOIN vn2008.province p ON c.province_id = p.province_id
+					WHERE t.id = #ticket
 			</custom>
 			<sql-batch property="batch">
 				<custom>
@@ -69,14 +69,15 @@
 		<htk-repeater form-id="iter" renderer="repeaterFunc">
 			<db-model property="model" id="movements">
 				<custom>
-					SELECT m.item_id, amount, concept, Categoria, Medida, Tallos, Color,
-					Abreviatura, IF(fixed != FALSE, price, NULL) price, fixed, discount
+					SELECT m.item_id, m.amount, m.concept,
+						IF(m.fixed != FALSE, m.price, NULL) price, m.fixed, m.discount,
+						o.Abreviatura, a.Categoria, a.Medida, a.Tallos, a.Color, a.Foto
 						FROM ticket_row_view m
-						INNER JOIN vn2008.Articles a
-							ON m.item_id = a.Id_Article AND ticket_id = #ticket 
-						LEFT JOIN vn2008.Origen o
-							ON a.id_origen = o.id
-							ORDER BY concept
+							INNER JOIN vn2008.Articles a
+								ON m.item_id = a.Id_Article AND ticket_id = #ticket 
+							LEFT JOIN vn2008.Origen o
+								ON a.id_origen = o.id
+						ORDER BY concept
 				</custom>
 				<sql-batch property="batch">
 					<custom>
@@ -86,6 +87,13 @@
 			</db-model>
 			<custom>
 				<div class="line">
+					<htk-image
+						form="iter"
+						column="Foto"
+						class="photo"
+						directory="catalog"
+						subdir="200x200"
+						full-dir="900x900"/>
 					<p class="concept">
 						<htk-text form="iter" column="concept"/> 
 						<htk-text form="iter" column="Medida"/> 
@@ -94,9 +102,9 @@
 					<p class="amount">
 						<htk-text form="iter" column="amount"/> x
 						<htk-text form="iter" column="price" format="%.2d€"/>
-					</p>
-					<p class="subtotal">
-						<htk-text id="subtotal" format="%.2d€"/>
+						<span class="subtotal">
+							<htk-text id="subtotal" format="%.2d€"/>
+						</span>
 					</p>
 					<div class="clear"/>
 				</div>
diff --git a/image/logo.png b/image/logo.png
new file mode 100644
index 0000000000000000000000000000000000000000..55e26fec6d6a2abff506862b1f851e1554f603c6
GIT binary patch
literal 8577
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
Hu0mjfoM~Q-

literal 0
HcmV?d00001

diff --git a/index.php b/index.php
index b9b0cad3..02b59a37 100755
--- a/index.php
+++ b/index.php
@@ -5,4 +5,3 @@ require_once 'vn-autoload.php';
 
 $webApp = new Vn\Web\App ('hedera-web');
 $webApp->run ();
-
diff --git a/js/hedera/app.js b/js/hedera/app.js
index cd6ce000..6871c10b 100644
--- a/js/hedera/app.js
+++ b/js/hedera/app.js
@@ -48,7 +48,7 @@ module.exports = new Class
 		gui.show ();
 	}
 	
-	,_onLogout: function (gui)
+	,_onLogout: function ()
 	{
 		this.clearAutoLogin ();
 		this._freeGui ();
diff --git a/js/hedera/login.js b/js/hedera/login.js
index 56144131..78fa4d4d 100644
--- a/js/hedera/login.js
+++ b/js/hedera/login.js
@@ -44,7 +44,7 @@ module.exports = new Class
 			this.$('spinner').stop ();
 	}
 
-	,show: function (firstLogin)
+	,show: function ()
 	{
 		document.body.appendChild (this.node);
 
@@ -114,7 +114,7 @@ module.exports = new Class
 		if (!user)
 			Htk.Toast.showError (_('Please write your user name'));
 		else
-			this._conn.send ('core/recover-password', {'user': user},
+			this._conn.send ('core/recover-password', {'recoverUser': user},
 				this._onPasswordRecovered.bind (this));
 	}
 	
diff --git a/js/hedera/report.js b/js/hedera/report.js
index d48c5b86..b7fe0165 100644
--- a/js/hedera/report.js
+++ b/js/hedera/report.js
@@ -100,4 +100,3 @@ module.exports = new Class
 		this.doc.body.appendChild (res.$('report'));
 	}
 });
-
diff --git a/js/htk/style.css b/js/htk/style.css
index 27e88c9e..6f345467 100644
--- a/js/htk/style.css
+++ b/js/htk/style.css
@@ -99,7 +99,7 @@ th.cell-radio
 }
 td.cell-button
 {
-	max-width: 1px;
+	width: 1em;
 	text-align: center;
 }
 td.cell-button > button
@@ -633,4 +633,3 @@ td.cell-image .htk-image
 {
 	to {-webkit-transform: rotate(360deg);}
 }
-
diff --git a/package.json b/package.json
index 8e77c567..83b993b3 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "hedera-web",
-  "version": "2.0.1",
+  "version": "2.0.3",
   "description": "Verdnatura web page",
   "devDependencies": {
     "assets-webpack-plugin": "^3.5.1",
diff --git a/pages/main/ui.php b/pages/main/ui.php
index f081b50b..65a7a283 100755
--- a/pages/main/ui.php
+++ b/pages/main/ui.php
@@ -1,47 +1,7 @@
 <?php
 
 $lang = Vn\Lib\Locale::get ();
-$result = $db->query('SELECT name, content FROM metatag');
-
-$wpConfig = json_decode (file_get_contents ('webpack.config.json'));
-$buildDir = $wpConfig->buildDir;
-$devServerPort = $wpConfig->devServerPort;
-
-$host = $_SERVER['SERVER_NAME'];
-$assets = new stdClass();
-
-if (!_DEV_MODE)
-{
-	$wpAssets = json_decode (file_get_contents ("$buildDir/webpack-assets.json"));
-
-	$manifestJs = $wpAssets->manifest->js;
-	$mainJs = $wpAssets->main->js;
-	unset ($wpAssets->manifest);
-	unset ($wpAssets->main);
-
-	foreach ($wpAssets as $name => $asset)
-	if (property_exists ($asset, 'js'))
-		$assets->$name = $asset->js;
-}
-else
-{
-	$devServerPath = "http://$host:$devServerPort/$buildDir";
-	$manifestJs = "$devServerPath/manifest.js";
-	$mainJs = "$devServerPath/main.js";
-
-	unset ($wpConfig->entry->main);
-
-	foreach ($wpConfig->entry as $asset => $files)
-		$assets->$asset = "$devServerPath/$asset.js";
-}
-
-$jsFiles = [];
-$jsFiles[] = $manifestJs;
-
-foreach ($assets as $jsFile)
-	$jsFiles[] = $jsFile;
-
-$jsFiles[] = $mainJs;
+$result = $db->query ('SELECT name, content FROM metatag');
 
 ?>
 <!DOCTYPE html>
@@ -58,11 +18,11 @@ $jsFiles[] = $mainJs;
 		<meta name="theme-color" content="#009688"/>
 		<meta name="content-language" content="<?=$lang?>"/>
 		
-		<?php while ($row = $result->fetch_object()): ?>
+		<?php while ($row = $result->fetch_object ()): ?>
 		<meta name="<?=$row->name?>" content="<?=$row->content?>"/>
 		<?php endwhile ?>
 
-		<?php foreach ($jsFiles as $js): ?>
+		<?php foreach (getWebpackAssets () as $js): ?>
 		<script type="text/javascript" src="<?=$js?>"></script>
 		<?php endforeach ?>
 
diff --git a/reports/delivery-note/locale/es.json b/reports/delivery-note/locale/es.json
new file mode 100644
index 00000000..d6cc0100
--- /dev/null
+++ b/reports/delivery-note/locale/es.json
@@ -0,0 +1,3 @@
+{
+    "Import": "Importe"
+}
\ No newline at end of file
diff --git a/reports/delivery-note/ui.xml b/reports/delivery-note/ui.xml
index e92107b1..16c24034 100755
--- a/reports/delivery-note/ui.xml
+++ b/reports/delivery-note/ui.xml
@@ -56,7 +56,7 @@
 		<htk-column-text title="_S1" column="Medida"/>
 		<htk-column-text title="_Cat" column="Categoria"/>
 		<htk-column-spin title="_Price" column="price" unit="€" digits="2"/>
-		<htk-column-spin title="_Subtotal" unit="€" digits="2" renderer="subtotalRenderer"/>
+		<htk-column-spin title="_Import" unit="€" digits="2" renderer="subtotalRenderer"/>
 	</htk-grid>
 	<p class="footer">
 		<htk-text format="%.2d€">
diff --git a/rest/core/recover-password.php b/rest/core/recover-password.php
index 876a110c..9c2c2307 100755
--- a/rest/core/recover-password.php
+++ b/rest/core/recover-password.php
@@ -4,7 +4,7 @@ use Vn\Web;
 
 class RecoverPassword extends Vn\Web\JsonRequest
 {
-	const PARAMS = ['user'];
+	const PARAMS = ['recoverUser'];
 
 	function run ($db)
 	{
@@ -13,14 +13,14 @@ class RecoverPassword extends Vn\Web\JsonRequest
 				FROM vn2008.Clientes c
 					JOIN account.user u ON u.id = c.Id_Cliente
 				WHERE u.name = #',
-			[$_REQUEST['user']]
+			[$_REQUEST['recoverUser']]
 		);
 
 		if (!($user['active'] && $user['mail']))
 			return TRUE;
 
 		$service = $this->service;
-		$token = $service->createToken ($_REQUEST['user'], FALSE, TRUE);
+		$token = $service->createToken ($_REQUEST['recoverUser'], FALSE, TRUE);
 		$url = $service->getUrl () ."#!form=account/conf&token=$token";
 
 		$report = new Vn\Web\Report ($db, 'recover-password', ['url' => $url]);
diff --git a/web/html-service.php b/web/html-service.php
index dee901fe..1600ee7d 100644
--- a/web/html-service.php
+++ b/web/html-service.php
@@ -13,12 +13,20 @@ class HtmlService extends Service
 {
 	function run ()
 	{
+		$eFlag =
+			  E_ERROR
+			| E_USER_ERROR;
+
+		set_error_handler ([$this, 'errorHandler'], $eFlag);
+		set_exception_handler ([$this, 'errorHandler']);
+
+		$this->init ();
 		$db = $this->db;
 
 		if (!$this->isHttps ()
 		&& $db->getValue ('SELECT https FROM config') && !_DEV_MODE)
 		{
-			header ("Location: https://{$_SERVER['SERVER_NAME']}{$_SERVER['REQUEST_URI']}");
+			header ("Location: https://{$this->getUri()}");
 			exit (0);
 		}
 
@@ -96,11 +104,12 @@ class HtmlService extends Service
 		//header ("Content-Security-Policy: default-src *; img-src *;");
 	}
 
-	function globalErrorHandler ()
+	function errorHandler ()
 	{
 		$this->printHeader ();
 		include (__DIR__.'/unavailable.html');
 		exit (0);
+		return FALSE;
 	}
 	
 	function isMobile ()
diff --git a/web/html.php b/web/html.php
index e1e7fae3..f810b145 100644
--- a/web/html.php
+++ b/web/html.php
@@ -3,29 +3,11 @@
 function getUrl ($fileName)
 {
 	if (file_exists ($fileName))
-    {
-		$hashes = apc_fetch ("$appName.hashes", $success);
-
-        if (!$success)
-        {
-			apc_store ("$appName.version", $version);
-            $hashes = [];
-        }
-
-        if (!isset ($hashes[$fileName]))
-        {
-            $hash = md5_file($fileName);
-            $hashes[$fileName] = $hash;
-        }
-        else
-            $hash = $hashes[$fileName];
-
-		$mTime = "?$hash";
-    }
-	else
-		$mTime = '';	
-	
-	return $fileName.$mTime;
+        $mTime = '?'. strftime ('%G%m%d%H%M%S', filemtime ($fileName));
+    else
+        $mTime = '?'. $this->getVersion ();	
+    
+    return $fileName.$mTime;
 }
 
 function js ($fileName)
@@ -37,3 +19,48 @@ function css ($fileName)
 {
 	return '<link rel="stylesheet" type="text/css" href="'. getUrl ($fileName) .'"/>'."\n";
 }
+
+function getWebpackAssets ()
+{
+	$wpConfig = json_decode (file_get_contents ('webpack.config.json'));
+	$buildDir = $wpConfig->buildDir;
+	$devServerPort = $wpConfig->devServerPort;
+
+	$host = $_SERVER['SERVER_NAME'];
+	$assets = new stdClass();
+
+	if (!_DEV_MODE)
+	{
+		$wpAssets = json_decode (file_get_contents ("$buildDir/webpack-assets.json"));
+
+		$manifestJs = $wpAssets->manifest->js;
+		$mainJs = $wpAssets->main->js;
+		unset ($wpAssets->manifest);
+		unset ($wpAssets->main);
+
+		foreach ($wpAssets as $name => $asset)
+		if (property_exists ($asset, 'js'))
+			$assets->$name = $asset->js;
+	}
+	else
+	{
+		$devServerPath = "http://$host:$devServerPort/$buildDir";
+		$manifestJs = "$devServerPath/manifest.js";
+		$mainJs = "$devServerPath/main.js";
+
+		unset ($wpConfig->entry->main);
+
+		foreach ($wpConfig->entry as $asset => $files)
+			$assets->$asset = "$devServerPath/$asset.js";
+	}
+
+	$jsFiles = [];
+	$jsFiles[] = $manifestJs;
+
+	foreach ($assets as $jsFile)
+		$jsFiles[] = $jsFile;
+
+	$jsFiles[] = $mainJs;
+
+	return $jsFiles;
+}
diff --git a/web/json-service.php b/web/json-service.php
index 59ead94a..e7da96e0 100644
--- a/web/json-service.php
+++ b/web/json-service.php
@@ -17,6 +17,7 @@ class JsonService extends RestService
 		set_error_handler ([$this, 'errorHandler'], E_ALL);
 		set_exception_handler ([$this, 'exceptionHandler']);
 
+		$this->init ();
 		$this->startSession ();
 		$this->checkVersion ();
 
diff --git a/web/rest-service.php b/web/rest-service.php
index 2376fdfd..96f8a6e6 100644
--- a/web/rest-service.php
+++ b/web/rest-service.php
@@ -3,6 +3,8 @@
 namespace Vn\Web;
 
 use Vn\Lib;
+use Vn\Lib\Locale;
+use Vn\Lib\UserException;
 
 /**
  * Base class for REST application.
@@ -15,9 +17,46 @@ class RestService extends Service
 		set_error_handler ([$this, 'errorHandler'], E_ALL);
 		set_exception_handler ([$this, 'exceptionHandler']);
 
+		$this->init ();
 		$this->startSession ();
 		$this->loadMethod (__NAMESPACE__.'\RestRequest');
 	}
+
+	/**
+	 * Runs a REST method.
+	 */
+	function loadMethod ($class)
+	{
+		$db = $this->db;
+		$this->login ();
+
+		$method = $this->app->loadMethod (
+			$_REQUEST['method'], $class, './rest');
+		$method->service = $this;
+
+		if ($method::SECURITY == Security::DEFINER)
+		{
+			$isAuthorized = $db->getValue ('SELECT userCheckRestPriv (#)',
+				[$_REQUEST['method']]);
+	
+			if (!$isAuthorized)
+				throw new UserException (s('You don\'t have enough privileges'));
+			
+			$methodDb = $db;
+		}
+		else
+			$methodDb = $this->getUserDb ($_SESSION['user']);
+
+		if ($method::PARAMS !== NULL && !$method->checkParams ($_REQUEST, $method::PARAMS))
+			throw new UserException  (s('Missing parameters'));
+		
+		Locale::addPath ("rest/{$_REQUEST['method']}");
+
+		$res = $method->run ($methodDb);
+		$db->query ('CALL account.userLogout ()');
+		
+		return $res;
+	}
 	
 	function statusFromException ($e)
 	{
diff --git a/web/service.php b/web/service.php
index eac532a0..64d59708 100755
--- a/web/service.php
+++ b/web/service.php
@@ -37,7 +37,11 @@ abstract class Service
 	function __construct ($app)
 	{
 		$this->app = $app;
-		$this->db = $app->getSysConn ();
+	}
+
+	function init ()
+	{
+		$this->db = $this->app->getSysConn ();
 	}
 
 	/**
@@ -45,7 +49,7 @@ abstract class Service
 	 */
 	function startSession ()
 	{
-		$db = $this->db;
+		$db = $this->app->getSysConn ();
 
 		ini_set ('session.cookie_secure', $this->isHttps ());
 		ini_set ('session.hash_function', 'sha256');
@@ -147,7 +151,10 @@ abstract class Service
 			catch (\Vn\Db\Exception $e)
 			{
 				if ($e->getMessage () == 'INVALID_CREDENTIALS')
+				{
+					sleep (3);
 					throw new BadLoginException ();
+				}
 				else
 					throw $e;
 			}
@@ -258,42 +265,6 @@ abstract class Service
 		$key = $this->db->getValue ('SELECT jwtKey FROM config');
 		return Jwt::encode ($payload, $key);
 	}
-
-	/**
-	 * Runs a method.
-	 */
-	function loadMethod ($class)
-	{
-		$db = $this->db;
-		$this->login ();
-
-		$method = $this->app->loadMethod (
-			$_REQUEST['method'], $class, './rest');
-		$method->service = $this;
-
-		if ($method::SECURITY == Security::DEFINER)
-		{
-			$isAuthorized = $db->getValue ('SELECT userCheckRestPriv (#)',
-				[$_REQUEST['method']]);
-	
-			if (!$isAuthorized)
-				throw new UserException (s('You don\'t have enough privileges'));
-			
-			$methodDb = $db;
-		}
-		else
-			$methodDb = $this->getUserDb ($_SESSION['user']);
-
-		if ($method::PARAMS !== NULL && !$method->checkParams ($_REQUEST, $method::PARAMS))
-			throw new UserException  (s('Missing parameters'));
-		
-		Locale::addPath ("rest/{$_REQUEST['method']}");
-
-		$res = $method->run ($methodDb);
-		$db->query ('CALL account.userLogout ()');
-		
-		return $res;
-	}
 	
 	/**
 	 * Obtains the application version number. It is extracted and
@@ -344,6 +315,16 @@ abstract class Service
 	{
 		return isset ($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on';
 	}
+
+	/**
+	 * Returns the current URI without the GET part.
+	 *
+	 * @return string The current URI
+	 */
+	function getUri ()
+	{
+		return "{$_SERVER['SERVER_NAME']}{$_SERVER['REQUEST_URI']}";
+	}
 	
 	/**
 	 * Returns the current URL without the GET part.
@@ -353,7 +334,7 @@ abstract class Service
 	function getUrl ()
 	{
 		$proto = $this->isHttps () ? 'https' : 'http';
-		return "$proto://{$_SERVER['SERVER_NAME']}{$_SERVER['REQUEST_URI']}";
+		return "$proto://{$this->getUri()}";
 	}
 }
 
diff --git a/web/unavailable.html b/web/unavailable.html
index 5d882273..af574787 100755
--- a/web/unavailable.html
+++ b/web/unavailable.html
@@ -3,36 +3,41 @@
 <html xmlns="http://www.w3.org/1999/xhtml">
 <head>
 	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
-	<title>No disponible - Verdnatura</title>
+	<title>Not available - Verdnatura</title>
 	<style type="text/css">
 		body
 		{
 			font-size: 16pt;
+			font-family: Sans;
 		}
 		div
 		{
 			position: absolute;
-			width: 36em;
+			width: 32em;
 			margin-top: -7em;
 			margin-left: -18em;
 			top: 50%;
 			left: 50%;		
 			text-align: center;	
 		}
+		div h2
+		{
+			font-weight: normal;
+		}
 		div a
 		{
-			color: #444;
+			color: #2962FF;
+			text-decoration: none;
 		}
 	</style>
 </head>
 <body>
 	<div>
 		<h2>
-			Estamos teniendo problemas; por favor,
-			espera unos minutos e int&eacute;ntalo de nuevo.
+			We are having problems; Please wait a few minutes and try again.
 		</h2>
 		<a href="javascript: location.reload (true)">
-			Intentarlo de nuevo
+			Try it again
 		</a>
 	</div>
 </body>