PcComponentes: cuando el cliente no importa [Actualizado – Caso solucionado]

[Actualización 19/12/2017] Tras publicar este artículo PcComponentes se puso en contacto conmigo interesándose por el caso y comprometiéndose a estudiarlo; finalmente me devolvió los portes de envío y devolución del Router, tal y como solicité. Es un poco desconcertante porque en este contacto (como en algunos de los originales) el trato fue muy bueno y personalizado, no como en los que causaron mi enfado.

PcComponentes.com ha crecido mucho desde sus inicios gracias a los numerosos clientes que hemos confiado en la tienda, principalmente gracias a los precios, pero ahora ha llegado a ese punto de las grandes compañías donde perder clientes cada mes le da igual porque entraran una cantidad equivalente de nuevos. Filosofía que con el tiempo está abocada al fracaso.

Los precios son buenos o al menos dentro de lo esperado, en muchos casos similares a los de sus competidores. Los portes aunque excesivos en algunos productos, especialmente si tenemos en cuenta el pésimo reparto final, pueden ser comprensibles. Lo que no tiene justificación ninguna es el pésimo servicio de atención al cliente que tienen.

De primeras nos puede dar la sensación de que se preocupan, ya que el número no es un 902, pero lo que no sabes hasta que te toca lidiar con ellos es cómo funcionan. Todo tipo de prácticas en las que ignoran a los clientes y hacen lo que les apetece: llamadas que cuelgan, mensajes que ignoran y responden de forma automática, imposibilidad de contactar con ellos en horas punta, … que al final convierten las compras en un suplicio.

Recientemente con motivo del Black Friday he tenido dos incidencias con ellos y se han resuelto de manera lenta, penosa y con coste para mi en el caso de una de ellas. Tengo claro que intentaré evitar PcComponentes en el futuro y comprar todo en Amazon, donde al menos puedes contactar con el servicio de atención al cliente en períodos claves como este. Para el que tenga curiosidad detallo al final de forma muy resumida los problemas que he tenido.

Mi sensación es que quieren competir con los grandes y lo hacen a base de publicidad y tirar precios de forma puntual; pero a la hora de la verdad caen donde muchos: en atención al cliente.

Impresora

Compré una impresora multifunción grande, cerca de 15Kg la caja. El día que tenía que llegar, como es tristemente habitual sin noticias del paquete. Después de ir a las instalaciones del transportista y hablar varias veces con el servicio de atención al cliente me comunican que se ha enviado a otra provincia por error, pero que al día siguiente la tengo. Estos mensajes son así hasta que una semana después la dan oficialmente por perdida y me dicen que lo pasan a otro departamento para que estudie el caso. En este momento les indico que quiero una devolución completa del importe porque necesito la impresora (y la voy a comprar en tienda física ya).

La próxima respuesta que recibo de ellos es que se resuelve el caso y ¡que me envían otra! Intento contactar por mensaje desde el área cliente, por teléfono e incluso por Twitter. Al final no recuerdo si fue por llamada o por alguno de los mensajes me indican que he tenido suerte y que como no ha sido enviada todavía pueden cancelarlo y lo pasan a devoluciones… donde después de bastante espera resuelven hacer un bono de devolución, que luego tengo que pedir se abone en mi cuenta.

He perdido la cuenta del número de llamadas, mensajes, viajes al transportista, …

Router

Estaba estudiando la compra de un Router el domingo por la noche. Lo añadí a la cesta (como suelo hacer siempre) para llegar al paso donde puedo ver el resumen con los portes, puntos que tengo, … y si me parece correcto completar los datos de pago y hacer el pedido. Para mi sorpresa el pedido se completó sin solicitar ninguna información de pago y el importe fue cargado en el acto en mi tarjeta.

Entro a mi área de cliente para cancelar el pedido y adivinan… ¡no es posible!. Llamo a atención al cliente y está fuera de horario. Pongo un mensaje para que lo cancelen de forma urgente y no pasa nada. A las 9.00, en cuanto abre atención al cliente llamo para que lo cancelen y me indican que ya ha sido preparado para envío y que no se puede tocar. Que el pedido se completa de forma automática por algo que no soy consciente de haber activado.

Pueden adivinar el resto: tal y como llegó el paquete le cambié la pegatina por una de devolución y la broma me ha costado 10 euros de portes, mensajes y llamadas.

Me parece increíble que no sea posible eliminar un pedido desde el área cliente en el acto y que como no hay posibilidad de contacto tengas que terminar devolviéndolo. Cuanto menos deberían hacerse cargo ellos de los portes, ya que el pedido ha sido hecho con un sistema que varió el comportamiento respecto a otras veces y he intentado por todos los medios cancelarlo.

VirtualBox – Gestionando máquinas virtuales con el API SOAP Java

VirtualBox es un sistema de virtualización de fácil manejo, gratuito y Open Source. Muchos lo usamos a diario y normalmente con la interfaz de usuario que proporciona podemos realizar todas las operaciones necesarias sobre las máquinas virtuales.

Interfaz de usuario de VirtualBox

Interfaz de usuario de VirtualBox

No obstante, en algunos casos queremos hacer operaciones no contempladas en el interfaz o integrar las máquinas virtuales en otros programas, por lo que VirtualBox posee varios puntos de integración: APIs que hacen uso de COM o XPCOM (dependiendo de la plataforma) y un servicio SOAP que puede ser consumido en cualquier sistema. En mi caso, haré uso del servicio SOAP mediante el API Java que facilitan. La instrucciones de este artículo son bajo Windows pero deberían tener equivalentes en el resto de sistemas.

Lo primero que vamos a hacer para facilitar las pruebas es deshabilitar la autenticación del servicio. De esta manera nos será más sencilla la primera conexión; ya habrá tiempo para habilitarla de nuevo si lo consideramos necesario. Para ello, desde el directorio de instalación de VirtualBox ejecutamos:

VBoxManage setproperty websrvauthlibrary null

Con la autenticación deshabilitada el servicio aceptara cualquier credencial como válida.

Como VirtualBox no levanta el servicio web junto con el interfaz, tendremos que levantarlo cada vez que deseemos usarlo mediante el ejecutable VBoxWebSrv , que se encuentra en el directorio de instalación:



C:\Program Files\Oracle\VirtualBox>VBoxWebSrv
Oracle VM VirtualBox web service Version 4.3.16
(C) 2007-2014 Oracle Corporation
All rights reserved.
VirtualBox web service 4.3.16 r95972 win.amd64 (Sep 9 2014 17:22:20) release log
00:00:00.000974 main Log opened 2014-10-23T16:31:03.759382100Z
00:00:00.000974 main Build Type: release
00:00:00.000974 main OS Product: Windows 8.1
00:00:00.000974 main OS Release: 6.3.9600
00:00:00.000974 main OS Service Pack:
00:00:00.015539 main DMI Product Name: SVF1521W1EB
00:00:00.021406 main DMI Product Version: C10H9VL3
00:00:00.021406 main Host RAM: 8070MB total, 3246MB available
00:00:00.021406 main Executable: C:\Program Files\Oracle\VirtualBox\VBoxWebSrv.exe
00:00:00.021406 main Process ID: 5680
00:00:00.021406 main Package type: WINDOWS_64BITS_GENERIC
00:00:00.126037 SQPmp Socket connection successful: host = default (localhost), port = 18083, master socket = 656

Con el servicio levantado ya podemos acceder al WSDL en la URL que nos muestra el log de inicio, en mi caso http://localhost:18083/?wsdl .

Habiendo verificado que el servicio responde podemos crear un proyecto de prueba en nuestro editor preferido. Para las dependencias recomiendo usar Maven, concretamente:

		<dependency>
			<groupId>org.virtualbox</groupId>
			<artifactId>vboxjws</artifactId>
			<version>4.2.8</version>
		</dependency>

que nos facilitará todas las clases necesarias para interactuar con el servicio.

La primera parte de nuestro código será crear la conexión con el servicio de VirtualBox:

VirtualBoxManager mgr = VirtualBoxManager.createInstance(null); 
String url = "http://localhost:18083/";
String user = "daniel.fernandez";
String passwd = "";

mgr.connect(url, user, passwd);

Una vez conectados disponemos de numerosas operaciones en el VirtualBoxManager para consultar o gestionar las máquinas virtuales.

Por ejemplo, para consultar el estado y la IP de cada una de ellas podríamos usar:

IVirtualBox vbox = mgr.getVBox(); 
List<IMachine> machines = vbox.getMachines();
System.out.println("VMs: " + machines.size());
 
for (IMachine machine : machines) {
    System.out.println(machine.getName() + " - " + machine.getState().toString());
    System.out.println("\t" + machine.getGuestPropertyValue("/VirtualBox/GuestInfo/Net/0/V4/IP"));
}

lo que en mi sistema devuelve:

VMs: 4
Windows 10 Enterprise - PoweredOff
 
WAS8 - PoweredOff
    192.168.14.99
XpSp3Office2K3 - PoweredOff
 
ConversionServer - Running
    192.168.1.18

Por último deberíamos cerrar la sesión con:

mgr.disconnect();

Este ejemplo es muy simple, pero creo que puede ser un buen punto de partida.

Recomiendo echarle un ojo a la guía de referencia facilitada por VirtualBox: http://download.virtualbox.org/virtualbox/SDKRef.pdf .

Alfresco – Desactivar la invitación de usuarios externos

La creación de usuarios en Alfresco está limitada a los administradores del sistema, pero hay un punto el que el usuario administrador de un Site puede invitar a cualquier usuario externo. Este punto se encuentra en la pantalla de invitación de usuarios, en la parte inferior:

UsuariosExternos

Invitar a usuarios externos en Alfresco

En la mayor parte de las instalaciones de Alfresco en entornos corporativos donde los usuarios se gestionan con sistemas externos esto supone un problema.

Para poder modificar este comportamiento Alfresco no proporciona una propiedad configurable globalmente en alfresco-global.properties, por lo que hay que seguir la pista de la pantalla para estudiar el mejor modo para realizar la modificación:

  1. Lo primero revisamos la plantilla encargada de generar la página de invitación de usuarios en Share. Se encuentra en ‘WEB-INF\classes\alfresco\templates\org\alfresco\invite.ftl’:
    <#include "include/alfresco-template.ftl" />
    <@templateHeader>
       <@link rel="stylesheet" type="text/css" href="${url.context}/res/templates/invite/invite.css" />
    </@>
    
    <@templateBody>
       <div id="alf-hd">
          <@region id="header" scope="global" />
          <@region id="title" scope="template" />
          <@region id="navigation" scope="template" />
       </div>
    
       <div id="bd">
          <@region id="membersbar" scope="template" />
          <div class="yui-g grid">
             <div class="yui-u first column1">
                <div class="yui-b">
                   <@region id="people-finder" scope="template" />
                </div>
                <div class="yui-b">
                   <@region id="addemail" scope="template" />
                </div>
             </div>
             <div class="yui-u column2">
                <div class="yui-b">
                   <@region id="invitationlist" scope="template" />
                </div>
             </div>
          </div>
       </div>
       <br/>
    </@>
    
    <@templateFooter>
       <div id="alf-ft">
          <@region id="footer" scope="global" />
       </div>
    </@>
    

    Podemos ver que en la columna de la izquierda, el segundo bloque de contenido es ‘addemail’.

  2. Buscamos la plantilla de este bloque y la encontramos en ‘WEB-INF\classes\alfresco\site-webscripts\org\alfresco\components\invite\addemail.get.html.ftl’:
    <#if allowEmailInvite>
    <script type="text/javascript">//<![CDATA[
       new Alfresco.AddEmailInvite("${args.htmlid}").setOptions(
       {
          siteId: "${page.url.templateArgs.site!""}"
       }).setMessages(
          ${messages}
       );
    //]]></script>
    
    <div id="${args.htmlid}-body" class="inviteusersbyemail">
       <div class="title">${msg("addemail.title")}</div>
       <div class="byemailbody"> 
          <table class="byemailuser">
             <tr>
                <td class="elabel"><label for="${args.htmlid}-firstname">${msg("addemail.firstname")}:</label></td>
                <td class="einput"><input type="text" id="${args.htmlid}-firstname" tabindex="0" /></td>
                <td class="byemailadd" colspan="3">
                   <span id="${args.htmlid}-add-email-button" class="yui-button yui-push-button"><span class="first-child"><button tabindex="0">${msg("addemail.add")} &gt;&gt;</button></span></span>
                </td>
             </tr>
             <tr>
                <td class="elabel"><label for="${args.htmlid}-lastname">${msg("addemail.lastname")}:</label></td>
                <td class="einput"><input type="text" id="${args.htmlid}-lastname" tabindex="0" /></td>
             </tr>
             <tr>
                <td class="elabel"><label for="${args.htmlid}-email">${msg("addemail.email")}:</label></td>
                <td class="einput"><input type="text" id="${args.htmlid}-email" tabindex="0" /></td>
             </tr>
          </table>
       </div>
    </div>
    </#if>
    

    En este código vemos que toda la generación de la página es dependiente del valor ‘allowEmailInvite’. Este valor se fija en el JavaScript de servidor que prepara el contenido para la plantilla, ‘WEB-INF\classes\alfresco\site-webscripts\org\alfresco\components\invite\addemail.get.js’:

    // get details of the authentication chain
    var res = remote.call("/api/authentication");
    var json = eval('(' + res + ')');
    
    model.allowEmailInvite = json.data.creationAllowed;
    
  3. Visto el JavaScript anterior, el que se muestre o no la pantalla de invitación de usuarios externos depende del valor de ‘creationAllowed’ que se obtiene del servicio de autenticación. Por desgracia este parámetro es la configuración global del sistema respecto a la creación de usuarios, por lo que si lo cambiamos en algún punto el administrador tampoco podrá crear usuarios. Por consiguiente, la mejor solución es cambiar el script anterior fijando a ‘false’ la propiedad:
    // get details of the authentication chain
    var res = remote.call("/api/authentication");
    var json = eval('(' + res + ')');
    
    model.allowEmailInvite = false;
    

    o mejor todavía, desactivarlo solo para los usuarios que no son administradores del sistema:

    // get details of the authentication chain
    var res = remote.call("/api/authentication");
    var json = eval('(' + res + ')');
    
    model.allowEmailInvite = json.data.creationAllowed && user.isAdmin;;
    

     

Una vez realizada la modificación confirmamos que ya no se muestra el marco de invitación externa de usuarios si no se es administrador del sistema:

UsuariosExternos2

Invitación de usuarios sin opción de externos

Synergy – Compartir teclado y ratón entre varios equipos

Cuando trabajamos con un portatil a diario normalmente usamos teclado y ratón externos porque la ergonomía de los integrados o las posturas de uso no son siempre las mejores. En la oficina no hay problema porque solemos disponer de todos los periféricos y o bien tenemos un ‘dock’ que integre todas las conexiones o los conectamos uno a uno. El problema se presenta cuando trabajamos en gran medida desde casa y queremos utilizar teclado y ratón de nuestro equipo particular.

La primera opción que viene a la mente es desconectar todo de nuestro equipo personal y conectarlo al portatil, pero además de ser un engorro no nos permite usar a la par ambos equipos.

Otra opción es comprar un switch KVM que nos permita conmutar periféricos entre varios equipos. Opción muy utilizada hace tiempo que tiene varios problemas: Desde el lío de cables que se monta en la mesa hasta el coste de estos dispositivos, pasando por los problemas que dan en numerosas ocasiones.

Switch KVM

Switch KVM

Así pues, dejando de lado las soluciones ‘hardware’ podemos optar por software que nos facilite la vida, como por ejemplo uno de acceso remoto desde el ordenador personal al portatil. A priori una solución válida, pero en la práctica no siempre dispondremos de las mismas opciones que si utilizáramos directamente el equipo. Además si los sistemas de ambos equipos son diferentes es probable que no dispongamos del mismo software en ambas las plataformas.

Llegados a este punto podemos dejar de darle más vueltas y usar directamente el portatil o usar Synergy.

SynergyLogo

Synergy es un software que nos permite compartir teclado y ratón de un equipo con otros a través de la conexión de red, independientemente del sistema operativo de cada uno de ellos (soporta Windows, Linux y OSX), siempre que ambos estén conectados en red. Durante un tiempo gratuito, recientemente han decidido cobrar unos simbólicos 4,99$ para poder mantener el proyecto, pero merece la pena con creces.

Synergy

Su uso no podría ser más simple: una vez instalado en los equipos basta con configurar uno como servidor y los demás como clientes, así como la disposición de todos en la mesa; de esta manera cuando movamos el cursor a los extremos de la pantalla pasaremos el control al equipo que hubiéramos configurado en esa posición.

 

Página de Synergy: http://synergy-project.org/

Guía de usuario: http://synergy-project.org/wiki/User_Guide

Videotutorial de su configuración y uso con Windows 8 y OSX: https://www.youtube.com/watch?v=1TR29vxoxno

 

 

Nuevo blog

Llevo tiempo queriendo crear un blog para compartir información sobre todas las cosas curiosas que me voy encontrando y las experiencias que tengo en el mundo de la programación y al fin me he decido a hacerlo!

Espero que las entradas sean interesantes y que el lector disfrute al menos tanto como yo escribiéndolas.