Sei sulla pagina 1di 49

1. INTRODUCCION ............................................................................................

2
2. OBJETIVOS DEL TRABAJO GUIADO .......................................................... 2
3. TEMAS SELECCIONADOS ........................................................................... 2
4. EQUIPOS ........................................................................................................ 3
5. DESARROLLO DEL TRABAJO GUIADO ..................................................... 4
5.1. SEGUIMIENTO AL PROCESO DE DESARROLLO. ................................... 4
5.2. Etapa 1 – Configuraciones SBT .................................................................... 5
5.2.1. Objetivos de la etapa 1 ............................................................................... 5
5.2.2. Base teórica .................................................................................................. 5
5.2.3. Configuraciones SBT .................................................................................. 5
5.3. Etapa 2 – Desarrollo Scala ........................................................................... 10
5.3.1. Objetivos de la etapa 2 ............................................................................. 10
5.3.2. Base teórica ................................................................................................ 10
5.3.3. Desarrollo Scala ......................................................................................... 10
5.3.3.1. Módulo Activos TI ............................................................................... 10
5.3.3.2. Biblioteca BCB .................................................................................... 13
5.3.3.3. Módulo Casa de cambio .................................................................... 16
5.3.3.4. Módulo Interfaz SWIFT ...................................................................... 19
5.4. Etapa 3 – Desarrollo Liftweb ........................................................................ 21
5.4.1. Objetivos de la etapa 3 ............................................................................. 21
5.4.2. Base teórica ................................................................................................ 21
5.4.3. Desarrollo Liftweb ...................................................................................... 21
5.4.3.1. Modulo Activos TI ............................................................................... 22
5.4.3.2. Módulo Bibliotecas BCB .................................................................... 29
5.4.3.3. Modulo Casa de cambio .................................................................... 37
5.4.3.4. Modulo Interfaz SWIFT ...................................................................... 45
6. RESULTADOS ALCANZADOS ................................................................... 48
7. ANEXOS ....................................................................................................... 49

1
1. INTRODUCCION

El trabajo guiado forma parte imprescindible del curso-taller SBT – Scala – Liftweb,
ya que abarca la puesta en práctica del conocimiento impartido durante 2 semanas,
las cuales implicaron un total de 40 horas.

En base a los objetivos del curso, se pretende que el presente documento, junto al
material bibliográfico constituyan una fuente de consulta para el desarrollo futuro
de aplicaciones web con las tecnologías SBT, Scala y Liftweb.

El trabajo guiado consistió en la elaboración de una aplicación web, dividida a su


vez en 4 módulos independientes con objetivos similares y dividido en 4 equipos
de personas quienes fueron guiados a través del desarrollo de la aplicación.

2. OBJETIVOS DEL TRABAJO GUIADO

 Realizar la configuración de un proyecto Scala, basado en SBT, con sus


respectivos módulos .
 Diseñar y armar la arquitectura del proyecto basado en SBT.
 Realizar las configuraciones del proyecto y sus módulos
 Programar Clases y Companion objects en Scala que representen los
modulos
 Realizar la configuracion Boot del modulo con Liftweb
 Armar de opciones de menu con Liftweb
 Programar Snippets que representen CRUDs .
 Realizar conexiones a bases de datos Informix o PostgreSQL
 Aplicacion de un ORM para guardado en bases de datos con la tecnologia
Scala-Liftweb.

3. TEMAS SELECCIONADOS

Se propusieron un conjunto de 6 temas seleccionados, de los cuales, los 4 equipos


debian elegir o proponer uno en base a las neccesidades del BCB y que debían
estar en el contexto y alcance de los objetivos del trabajo guiado. A continuación
se describe los temas seleccionados.

 Activos de TI
Actualmente el departamento de TI del BCB gestiona sus activos a traves
de documentos de Excel. Sin embargo, en los últimos meses se procedió a
armar una base de datos Informix. El objetivo del módulo se enmarcó en
crear una aplicación web con conexión a base de datos Informix (que sería
una copia respecto a la estrucutura de la base de datos en producción)
donde se aplique la creación de CRUDs de Activos TI .
2
 Biblioteca BCB
Actualmente la biblioteca del BCB cuenta con un sistema obsoleto, basado
en tecnologia DOS. El objetivo del módulo se enmarcó en crear un sistema
web de fácil acceso que gestione el registro de libros, Cds o material
interactivo y préstamos para la biblioteca BCB.

 Interfaz SWIFT
Actualmente el BCB cuenta con archivos con extension .dos que contienen
la informacion de depositos internacionales. El objetivo del modulo se
enmarcó en crear una aplicación web que sea capaz de leer esos archivos,
mostrarlos en formato comprensible al usuario final a traves de un
documentos PDF y crear un CRUD de representacion SWIFT.

 Casa de cambio
El objetivo del módulo se enmarcó en crear un sistema web para las
actividades de una casa de cambio, donde debía identificarse a un cliente,
realizar el registro del mismo, crear monedas y tipos de cambio asociados
y finalmente, guardar las transacciones de cambio de moneda.

 BCB Master
El objetivo de la aplicación web, es brindar los enlaces de conexión
necesarios para acceder a los módulos previamente descritos. Fué
desarrollado como un módulo adicional, con el único fin de interconectar el
resto de los módulos.

4. EQUIPOS

Los equipos fueron conformados por 2 a 4 personas bajo los criterios de afinidad
y perfil profesional. A continuación se describe los nombres de equipos,
integrantes y proyecto desarrollado.

 Equipo: Amigos de Scala


Integrantes:
Alvarez Castro Jesus Marco Antonio
Garcia Perez Carola Sara
Módulo: Activos TI

3
 Equipo: Fusion
Integrantes:
Chuquimia Arratia Vania Mercedes
Coaquira Quisberth Lizeth Jimena
Garcia Limchs Ana Maria
Mamani Quisberth Reymi Veronica
Módulo: Biblioteca BCB

 Equipo: Internacionales
Integrantes:
Illanes Burgoa Gabriel Mauricio
Quispe Catacora Hugo
Tejeda Perez Richard Paolo
Módulo: Interfaz SWIFT

 Equipo: Casa de cambio


Integrantes:
Herrera Flores Wilbert
Leon Pinto Rolando Roger
Módulo: Casa de cambio

5. DESARROLLO DEL TRABAJO GUIADO

Junto a los objetivos planteados, se realizó un seguimiento metódico al desarrollo


del trabajo guiado, el cual se describe en las siguientes subsecciones.

5.1. SEGUIMIENTO AL PROCESO DE DESARROLLO.

Se aplicó el seguimiento de desarrollo ágil de aplicaciones. El que consiste en


definir un objetivo general del proyecto y plantear iteraciones (rangos de tiempo)
donde se forman equipos de 2 o 4 personas, quienes construirán aplicaciones
basadas en las tecnoligias del curso. Cada iteración, tiene a su vez objetivos, los
cuales idealmente deben plantearse en base al tiempo de la iteracion (30 a 40
minutos) y lo que se espera alcanzar.

El enfoque práctico, basado en iteraciones permite:


 Definir un tiempo establecido, el cuál se conoce como una iteración (30 a 40
minutos).
 Identificar objetivos claramente definidos, los cuales deben cumplirse en una
iteración.
 Contar con funcionarios comprometidos a cumplir los objetivos en una
iteración, ya que son ellos mismos quienes determinan sus objetivos, con el
apoyo de la capacitadora.

4
Durante cada iteración, la capacitadora, realiza la revisión de los objetivos, antes
de iniciarla. Se registra la hora de inicio de la iteración y se realiza un seguimiento
entre los 15 a 20 minutos de iniciada, para identificar posibles problemas,
desvio de objetivos o soporte.

Al finalizar la hora de culminación de una iteración, se revisan los objetivos, se


registran los culminados y se inicia una nueva iteración, donde los objetivos no
terminados pasan a formar parte de la nueva iteración o se plantean nuevos
objetivos. Se realiza una retrospectiva para identificar los problemas que no
permitieron culminar un objetivo.

5.2. Etapa 1 – Configuraciones SBT

La etapa SBT consistió en la construcción de las configuraciones base para cada


módulo. Cada equipo conformado, inicialmente procedió a la familizarización de
configuraciones SBT de manera individual y posteriormente realizaron la
configuración global del módulo a construir.

5.2.1. Objetivos de la etapa 1

 Armar la arquitectura del módulo SBT


 Realizar la configuración del archivo build.sbt
 Asegurar la ejecución correcta de la configuración a través de SBT.

5.2.2. Base teórica

La base teórica se encuentra respaldada en el material bibliográfico Programacion


con Sbt, Scala, Liftweb correspondiente al capítulo 1 – SBT Scala Build Tool.

5.2.3. Configuraciones SBT

Cada módulo presenta su respectivo archico de configuración que se presenta a


continuación

Nro de iteraciones totales : 1


Fecha: 28 de Junio de 2019.
Tiempo total invertido : 40 minutos por equipo.

5
build.sbt de Activos TI
name := "Activos TI"

version := "1.0.0"

organization := "net.liftweb"

scalaVersion := "2.11.2"

resolvers ++= Seq(


"snapshots" at
"https://oss.sonatype.org/content/repositories/snapshots",
"staging" at
"https://oss.sonatype.org/content/repositories/staging",
"releases" at
"https://oss.sonatype.org/content/repositories/releases",
"JBoss repository" at
"https://repository.jboss.org/nexus/content/groups/public/"
)
enablePlugins(JettyPlugin)
unmanagedResourceDirectories in Test <+= (baseDirectory) { _ /
"src/main/webapp" }
scalacOptions ++= Seq("-deprecation", "-unchecked")
libraryDependencies ++= {
val liftVersion = "2.6.3"
Seq(
"net.liftweb" %% "lift-webkit" % liftVersion %
"compile",
"net.liftmodules" %% "lift-jquery-module_3.0" % "2.10",
"net.liftweb" %% "lift-jpa" % liftVersion % "compile"
withSources(),
"ch.qos.logback" % "logback-classic" % "1.2.3",
"org.specs2" %% "specs2-core" % "3.9.4"
% "test",
"org.hibernate" % "hibernate-entitymanager" % "4.2.0.Final",
"org.hibernate" % "hibernate-core" % "4.2.0.Final",
"org.hibernate" % "hibernate-validator" % "4.2.0.Final",
"net.sf.jasperreports" % "jasperreports" % "5.5.0",
"com.lowagie" % "itext" % "2.1.7",
"com.ibm.informix" % "jdbc" % "4.10.8.1",
"javax.servlet" % "javax.servlet-api" % "3.0.1"
% "provided",
"org.slf4j" % "slf4j-api" % "1.6.1",
"org.slf4j" % "slf4j-log4j12" % "1.6.1",
"log4j" % "log4j" % "1.2.16"
)
}
scalacOptions in Test ++= Seq("-Yrangepos")
Figura 1 – build.sbt del módulo Activos TI

6
build.sbt de Biblioteca BCB
name := "Proyecto Biblioteca"

version := "0.1.0"

organization := "bcb.gob.bo"

scalaVersion := "2.11.2"

resolvers ++= Seq(


"snapshots" at
"https://oss.sonatype.org/content/repositories/snapshots",
"staging" at
"https://oss.sonatype.org/content/repositories/staging",
"releases" at
"https://oss.sonatype.org/content/repositories/releases",
"JBoss repository" at
"https://repository.jboss.org/nexus/content/groups/public/"
)

enablePlugins(JettyPlugin)

unmanagedResourceDirectories in Test <+= (baseDirectory) { _ /


"src/main/webapp" }

scalacOptions ++= Seq("-deprecation", "-unchecked")

libraryDependencies ++= {
val liftVersion = "2.6.3"
Seq(
"net.liftweb" %% "lift-webkit" % liftVersion %
"compile",
"net.liftmodules" %% "lift-jquery-module_3.0" % "2.10",
"net.liftweb" %% "lift-jpa" % liftVersion % "compile"
withSources(),
"ch.qos.logback" % "logback-classic" % "1.2.3",
"org.specs2" %% "specs2-core" % "3.9.4"
% "test",
"org.hibernate" % "hibernate-entitymanager" % "4.2.0.Final",
"org.hibernate" % "hibernate-core" % "4.2.0.Final",
"org.hibernate" % "hibernate-validator" % "4.2.0.Final",
"org.postgresql" % "postgresql" % "42.2.5",
"net.sf.jasperreports" % "jasperreports" % "5.5.0",
"com.lowagie" % "itext" % "2.1.7",
"javax.servlet" % "javax.servlet-api" % "3.0.1"
% "provided",
"org.slf4j" % "slf4j-api" % "1.6.1",
"org.slf4j" % "slf4j-log4j12" % "1.6.1",
"log4j" % "log4j" % "1.2.16"
)
}

scalacOptions in Test ++= Seq("-Yrangepos")


Figura 2 – build.sbt del módulo Biblioteca BCB

7
build.sbt de Casa de cambio
name := "LiftBasicoHQuispe3.0"

version := "0.1.0"

organization := "net.liftweb"

scalaVersion := "2.11.2"

resolvers ++= Seq(


"snapshots" at
"https://oss.sonatype.org/content/repositories/snapshots",
"staging" at
"https://oss.sonatype.org/content/repositories/staging",
"releases" at
"https://oss.sonatype.org/content/repositories/releases",
"JBoss repository" at
"https://repository.jboss.org/nexus/content/groups/public/"
)

enablePlugins(JettyPlugin)

unmanagedResourceDirectories in Test <+= (baseDirectory) { _ /


"src/main/webapp" }

scalacOptions ++= Seq("-deprecation", "-unchecked")

libraryDependencies ++= {
val liftVersion = "2.6.3"
Seq(
"net.liftweb" %% "lift-webkit" % liftVersion %
"compile",
"net.liftmodules" %% "lift-jquery-module_3.0" % "2.10",
"net.liftweb" %% "lift-jpa" % liftVersion % "compile"
withSources(),
"ch.qos.logback" % "logback-classic" % "1.2.3",
"org.specs2" %% "specs2-core" % "3.9.4"
% "test",
"org.hibernate" % "hibernate-entitymanager" % "4.2.0.Final",
"org.hibernate" % "hibernate-core" % "4.2.0.Final",
"org.hibernate" % "hibernate-validator" % "4.2.0.Final",
"org.postgresql" % "postgresql" % "42.2.5",
"javax.servlet" % "javax.servlet-api" % "3.0.1"
% "provided",
"org.slf4j" % "slf4j-api" % "1.6.1",
"org.slf4j" % "slf4j-log4j12" % "1.6.1",
"log4j" % "log4j" % "1.2.16"
)
}

scalacOptions in Test ++= Seq("-Yrangepos")


Figura 3 – build.sbt del módulo Casa de cambio

8
build.sbt de Interfaz SWIFT
name := "Lift 3.0 starter template"

version := "0.1.0"

organization := "net.liftweb"

scalaVersion := "2.11.2"

resolvers ++= Seq(


"snapshots" at
"https://oss.sonatype.org/content/repositories/snapshots",
"staging" at
"https://oss.sonatype.org/content/repositories/staging",
"releases" at
"https://oss.sonatype.org/content/repositories/releases",
"JBoss repository" at
"https://repository.jboss.org/nexus/content/groups/public/"
)

enablePlugins(JettyPlugin)

// unmanagedResourceDirectories in Test <+= (baseDirectory) { _ /


"src/main/webapp" }

scalacOptions ++= Seq("-deprecation", "-unchecked")

libraryDependencies ++= {
val liftVersion = "2.6.3"
Seq(
"net.liftweb" %% "lift-webkit" % liftVersion %
"compile",
"net.liftmodules" %% "lift-jquery-module_3.0" % "2.10",
"net.liftweb" %% "lift-jpa" % liftVersion % "compile"
withSources(),
"ch.qos.logback" % "logback-classic" % "1.2.3",
"org.specs2" %% "specs2-core" % "3.9.4"
% "test",
"org.hibernate" % "hibernate-entitymanager" % "4.2.0.Final",
"org.hibernate" % "hibernate-core" % "4.2.0.Final",
"org.hibernate" % "hibernate-validator" % "4.2.0.Final",
"com.ibm." % "jdbc" % "4.10.8.1",
"net.sf.jasperreports" % "jasperreports" % "5.5.0",
"com.lowagie" % "itext" % "2.1.7",
"javax.servlet" % "javax.servlet-api" % "3.0.1"
% "provided",
"org.slf4j" % "slf4j-api" % "1.6.1",
"org.slf4j" % "slf4j-log4j12" % "1.6.1",
"log4j" % "log4j" % "1.2.16",
"org.apache.httpcomponents" % "httpclient" %
"4.5.6",
"org.apache.commons" % "commons-lang3" %
"3.7",
"com.fasterxml.jackson.core" % "jackson-core" % "2.6.6",
"com.fasterxml.jackson.core" % "jackson-databind" % "2.6.6"
)
}

scalacOptions in Test ++= Seq("-Yrangepos")


containerPort in Jetty := 8090
Figura 4 – build.sbt del módulo Interfaz SWIFT.
9
5.3. Etapa 2 – Desarrollo Scala

La etapa Scala consistió en programar las clases necesarias involucradas en el


módulo.

5.3.1. Objetivos de la etapa 2

A continuación se describe las tareas especificas realizadas:

 Construir las clases en Scala.


 Implementar funciones generales de aplicación para cada clase. Por
ejemplo: crear nuevo, mostrar, listar elementos.
 Elegir la conexión de base de datos Orm.
 Asociar las dependencias respectivas al proyecto, en base a la conexión
de base de datos y orm elegidos.
 Asociar las clases previamente construidas al modelo de base de datos.
 Construir el objeto principal AppScala, a través del cual se simule la
ejecución de creacion de clases, consulta y eliminación.

5.3.2. Base teórica

La base teórica se encuentra respaldada en el material bibliográfico Programacion


con Sbt, Scala, Liftweb correspondiente al capítulo 2 – Programando en Scala

5.3.3. Desarrollo Scala

Cada equipo procedió al desarrollo de clases Scala en base a los objetivos de la


Etapa 2.

5.3.3.1. Módulo Activos TI

Nro de iteraciones totales : 4


Fecha: 29 de Junio al 31 de Junio de 2019.
Tiempo total invertido : 2 Hrs con 40 minutos aprox..

10
package code
package model

//import net.liftweb.mapper._
import net.liftweb.util._
import net.liftweb.common._

import javax.persistence._
import javax.validation._
import javax.validation.constraints._
import org.hibernate.validator.constraints._
import scala.collection.JavaConversions._

@Entity
@Table(name = "lenguaje_programacion")
class Lenguaje_programacion {

@Id
@NotBlank
var id_lenguaje : Int = _

@NotBlank
@Size(max=60)
var nom_lenguaje: String = ""

@Size(max=2)
var cve_framework : String = ""
}

object Lenguaje_programacion {
def findPage(pageNumber: Int, pageSize: Int): List[Lenguaje_programacion]
= {

JPAUtility.findAll[Lenguaje_programacion]("AllLenguajeProgramacion").toList
}

def find(id: String): Box[Lenguaje_programacion] = {


for {
id <- Helpers.asLong(id)
org <- JPAUtility.find(classOf[Lenguaje_programacion], id)
} yield org
}

def save(lenguaje_programacion: Lenguaje_programacion):


Option[Lenguaje_programacion] = {
Some(JPAUtility.mergeAndFlush(lenguaje_programacion))
}
}
Figura 5 . Clase Lenguaje programación del módulo Activos TI

11
package code.model
//import net.liftweb.mapper._
import net.liftweb.util._
import net.liftweb.common._

import javax.persistence._
import javax.validation._
import javax.validation.constraints._
import org.hibernate.validator.constraints._
import scala.collection.JavaConversions._

@Entity
@Table(name = "servidores")
class Servidores {
@Id
@NotBlank
//@GeneratedValue(generator="id_lenguaje")
var id_servidores : Int = _

//@Column(nullable=false)
@NotBlank
@Size(max=60)
var nom_servidores: String = ""
}

object Servidores {
def findPage(pageNumber: Int, pageSize: Int): List[Servidores] = {
JPAUtility.findAll[Servidores]("AllServidores").toList
}

def find(id: String): Box[Servidores] = {


for {
id <- Helpers.asLong(id)
org <- JPAUtility.find(classOf[Servidores], id)
} yield org
}

def save(servidores: Servidores): Option[Servidores] = {


Some(JPAUtility.mergeAndFlush(servidores))
}
}
Figura 6 – Clase Servidores del módulo Activos TI

12
5.3.3.2. Biblioteca BCB

Nro de iteraciones totales : 4


Fecha: 29 de Junio al 31 de Junio de 2019.
Tiempo total invertido : 2 Hrs con 40 minutos aprox..

package code.model

//import net.liftweb.mapper._
import net.liftweb.util._
import net.liftweb.common._

import javax.persistence._
import javax.validation._
import javax.validation.constraints._
import org.hibernate.validator.constraints._
import scala.collection.JavaConversions._

@Entity
@Table(name="lector")
class Lector {

@Id
@GeneratedValue(generator = "LectorIdSeq")
var idLector: Long = -1

@Column(nullable = false)
@NotBlank
var nombres: String = ""

@Column(nullable = false)
@NotBlank
var paterno: String = ""

@Column(nullable = false)
@NotBlank
var materno: String = ""

@Column(nullable = false)
@NotBlank
@Size(max = 3)
var cveTipoLector: String = ""

@Column(nullable = false)
@Size(max = 5)
var codEmpleado: String = ""

@Column(nullable = false)
var direccion: String = ""

@Column(nullable = false)
@Size(max = 10)
var telefono: String = ""

@Column(nullable = false)

13
var estado: String = ""

@Column(nullable = false)
@Temporal(TemporalType.DATE)
var fechaRegistro: java.util.Date = null

object Lector {
def findPage(pageNumber: Int, pageSize: Int): List[Lector] = {
JPAUtility
.createNamedQuery("AllLector")
.setFirstResult((pageNumber-1) * pageSize)
.setMaxResults(pageSize)
.findAll
.toList
}

def find(id: String): Box[Lector] = {


for {
id <- Helpers.asLong(id)
org <- JPAUtility.find(classOf[Lector], id)
} yield org
}

def save(lector: Lector): Option[Lector] = {


val saved = JPAUtility.merge(lector)
JPAUtility.flush()
Some(saved)
}

def findAll(): List[Lector] = {


JPAUtility
.createNamedQuery("AllLector")
.findAll
.toList
}
}
Figura 7 – Clase Lector del módulo Biblioteca BCB

14
package code.model

import javax.persistence._
import javax.validation._
import javax.validation.constraints._
import net.liftweb.common.Box
import net.liftweb.util.Helpers
import org.hibernate.validator.constraints._
import scala.collection.JavaConversions._

@Entity
@Table(name="prestamo")
class Prestamo {

@Id
@GeneratedValue(generator = "PrestamoIdSeq")
var idPrestamo : Long = _

@Temporal(TemporalType.DATE)
var fechaPrestamo : java.util.Date =
java.util.Calendar.getInstance().getTime

@Temporal(TemporalType.DATE)
var fechaDevolucion : java.util.Date =
java.util.Calendar.getInstance().getTime

@Column(nullable=false)
var cveTipoPrestamo: String = ""

@Column(nullable=false)
var estado: String = ""
}

object Prestamo {

def findPage(pageNumber: Int, pageSize: Int): List[Prestamo] = {


JPAUtility
.createNamedQuery("AllPrestamo")
.setFirstResult((pageNumber-1) * pageSize)
.setMaxResults(pageSize)
.findAll
.toList
}

def find(id: String): Box[Prestamo] = {


for {
id <- Helpers.asLong(id)
org <- JPAUtility.find(classOf[Prestamo], id)
} yield org
}

def save(prestamo: Prestamo): Option[Prestamo] = {


val saved = JPAUtility.merge(prestamo)
JPAUtility.flush()
Some(saved)
}

}
Figura 8 – Clase Prestamo del módulo Biblioteca BCB

15
Figura 9 – Ejemplo de ejecución de simulación módulo Biblioteca BCB.

5.3.3.3. Módulo Casa de cambio

Nro de iteraciones totales : 4


Fecha: 29 de Junio al 31 de Junio de 2019.
Tiempo total invertido : 2 Hrs con 40 minutos aprox..

package code
package model

//import net.liftweb.mapper._
import net.liftweb.util._
import net.liftweb.common._

import javax.persistence._
import javax.validation._
import javax.validation.constraints._
import org.hibernate.validator.constraints._
import scala.collection.JavaConversions._

@Entity
class Moneda {

@Id
@GeneratedValue(generator="MonedaIdSeq")
var id : Long = _

@Column(nullable=false)
@NotBlank
@Size(max=3)
var codmoneda : String = ""

@Column(nullable=false)
@NotBlank
@Size(max=30)
var nommoneda : String = ""

@Column(nullable=false, precision=10, scale=2)


var tc : java.math.BigDecimal = new java.math.BigDecimal("0.0")

override def toString = codmoneda+"-"+nommoneda

16
}

object Moneda {
def findPage(pageNumber: Int, pageSize: Int): List[Moneda] = {
JPAUtility
.createNamedQuery("AllMoneda")
.setFirstResult((pageNumber-1) * pageSize)
.setMaxResults(pageSize)
.findAll
.toList
}

def findAll(): List[Moneda] = {


JPAUtility
.createNamedQuery("AllMoneda")
.findAll
.toList
}

def find(id: String): Box[Moneda] = {


for {
id <- Helpers.asLong(id)
org <- JPAUtility.find(classOf[Moneda], id)
} yield org
}
}
Figura 10 – Clase Moneda del módulo Casa de cambio.

17
package code
package model

//import net.liftweb.mapper._
import net.liftweb.util._
import net.liftweb.common._

import javax.persistence._
import javax.validation._
import javax.validation.constraints._
import org.hibernate.validator.constraints._
import scala.collection.JavaConversions._

@Entity
class Transaccion {

@Id
@GeneratedValue(generator="TransaccionIdSeq")
var id : Long = _

@Column(nullable=false)
@Temporal(TemporalType.DATE)
var fecha_trans : java.util.Date = new java.util.Date()

@ManyToOne(optional=false)
var cliente : Cliente = _

@Column(nullable=false)
@NotBlank
@Size(max=80)
var concepto : String = ""
}

object Transaccion {
def findPage(pageNumber: Int, pageSize: Int): List[Transaccion] = {
JPAUtility
.createNamedQuery("AllTransaccion")
.setFirstResult((pageNumber-1) * pageSize)
.setMaxResults(pageSize)
.findAll
.toList
}

def find(id: String): Box[Transaccion] = {


for {
id <- Helpers.asLong(id)
org <- JPAUtility.find(classOf[Transaccion], id)
} yield org
}
}
Figura 11 - Clase Transaccion del módulo casa de cambio.

18
5.3.3.4. Módulo Interfaz SWIFT

Nro de iteraciones totales : 4


Fecha: 29 de Junio al 31 de Junio de 2019.
Tiempo total invertido : 2 Hrs con 40 minutos aprox..

package code.model

import javax.persistence.{Entity, Id}


import javax.validation.constraints.Size
import net.liftweb.common.Box
import net.liftweb.util.Helpers

@Entity
class Swiftcurso {
@Id
var id : Long = _

@Size(max=32)
var estado : String = ""

@Size(max=500)
var plano : String = ""
}

object Swiftcurso {
def getAll(): List[Swiftcurso] = {
JPAUtility.findAll[Swiftcurso]("AllSwiftcurso").toList
}
def find(id: String): Box[Swiftcurso] = {
for {
id <- Helpers.asLong(id)
org <- JPAUtility.find(classOf[Swiftcurso], id)
} yield org
}

}
Figura 12 - Clase SWIFT del módulo interfaz SWIFT

package dk.nscp.rest_server

import akka.util.Timeout
import scala.concurrent.duration._
import akka.pattern.ask
import akka.actor.ActorSystem
import akka.http.scaladsl.Http
import akka.http.scaladsl.model.StatusCodes
import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.server.Route
import akka.stream.ActorMaterializer

import scala.io.StdIn
import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport
import bcb.cursoscala.servicio.ReporteSwiftServiceRest
import gob.bcb.core.utils.UtilsFile
import spray.json._
import slick.driver.SQLiteDriver.api._
19
import org.sqlite.JDBC

trait JsonSupport extends SprayJsonSupport with DefaultJsonProtocol {


implicit val healthFormat = jsonFormat2(Health)
implicit val personFormat = jsonFormat3(Person)
implicit val partialPersonFormat = jsonFormat2(PartialPerson)
implicit val personLisFormat = jsonFormat1(PersonList)
implicit val dataSwift = jsonFormat1(ReportSwift)
}

object Main extends App with JsonSupport {

val host = "localhost"


val port = 9000

implicit val system = ActorSystem()


implicit val materializer = ActorMaterializer()
implicit val executionContext = system.dispatcher
implicit val timeout = Timeout(20.seconds)

val requestHandler = system.actorOf(RequestHandler.props(),


"requesthandler")

val route: Route = {


get {
path("personas") {
onSuccess(PersonsDAO.allPersons) {
case persons: Seq[Person] =>{

val archSwift = "e:/tmp/swf_conlau.dos"


println("====generarReportePDFFromPlanoTestOut===== ")
val menPlano = UtilsFile.readFileAsString2(archSwift)
println(menPlano)

val reporteSwiftServiceRest = new ReporteSwiftServiceRest()


val data = reporteSwiftServiceRest.obtenerReporte(menPlano)
println("reporteSwiftServiceRest " + data.length)
complete(ReportSwift(data))
}
case _ =>
complete(StatusCodes.InternalServerError)
}
} ~
path("personas"/IntNumber) { id =>
onSuccess(PersonsDAO.singlePerson(id)) {
case Some(person) => complete(person)
case None => complete("No such person!")
}
}
}
}

val bindingFuture = Http().bindAndHandle(route, host, port)


println(s"\nServer running on $host:$port\nhit RETURN to terminate")
StdIn.readLine()

bindingFuture.flatMap(_.unbind())
system.terminate()
}
Figura 13 – Clase Principal donde se ejecuta la lectura de un archivo SWIFT

20
5.4. Etapa 3 – Desarrollo Liftweb

La etapa Liftweb consistió en programar las pantallas web necesarias para cada
módulo. Conocer la arquitectura y beneficios de la biblioteca de Liftweb para el
manejo correcto.

5.4.1. Objetivos de la etapa 3

A continuación se describe los objetivos específicos de la etapa 3.

 Integrar el proyecto de la etapa 2, con la arquitectura Liftweb.


 Construir Snippets y pantallas html para representar CRUDs en la
aplicación web.
 Armar menús de entrada aplicando SiteMap para la apreciación de los
CRUDs
 Agregar una página inicial donde se aprecie, el nombre del proyecto,
objetivos e integrantes.
 Modificar los templates de la arquitectura Liftweb para la persoalización del
proyecto un Logo en la cabecera, nombre del proyecto al pie de página y la
fecha actual.
 Aplicar LiftRules proceder a armar una URL asociada a la exportación de
un reporte en PDF.
 Desarrollar una pantalla dinamica de cálculo y actualización,
opcionalmente aplicando Wiring.
 Elaborar un documento que describa el desarrollo del módulo
 Elaborar un video de al menos 1 minuto donde se aprecie la ejecución del
módulo.

5.4.2. Base teórica

La base teórica se encuentra respaldada en el material bibliográfico Programacion


con Sbt, Scala, Liftweb correspondiente al capítulo 3 – Framework Liftweb.

5.4.3. Desarrollo Liftweb

Iniciada la parte teórica, cada equipo, se centró en desarrollar los objetovos en


Scala y Liftweb.

21
5.4.3.1. Modulo Activos TI

Nro de iteraciones totales : 7


Fecha: 04 de Junio al 07 de Junio de 2019.
Tiempo total invertido : 4 Hrs con 40 minutos aprox..

package code.snippet

import code.lib.MainMenu
import code.lib.menu.MenuServidor
import code.model.{Servidor, JPAUtility}
import net.liftweb.util.CssSel
import net.liftweb.common.Full
import net.liftweb.http.SHtml
import javax.persistence.EntityManager
import net.liftweb.http.js.JsCmds.RedirectTo
import scala.xml.NodeSeq
import net.liftweb.util.Helpers._

object ServidorSnippet {
def list: CssSel = {
def pageItems = Servidor.findPage(1, 10)
def count = 1 //
JPAUtility.createNativeQuery[java.math.BigInteger]("select count(*)
from customer;").getSingleResult().intValue

"data-name=list *" #> pageItems.map(servidor => {


"data-name=code *" #> servidor.id_servidor&
"data-name=name *" #> s"${servidor.nom_servidor} " &
"data-name=name1 *" #> s"${servidor.so_servidor} " &
"data-name=name2 *" #> s"${servidor.desc_servidor} " &
"data-name=name3 *" #> s"${servidor.id_log_auditoria} " &
"data-name=name4 *" #> s"${servidor.cve_estado} " &
"data-name=view [href]" #>
MenuServidor.locView.calcHref(servidor) &
"data-name=edit [href]" #>
MenuServidor.locEdit.calcHref(servidor) &
"data-name=delete [href]" #>
MenuServidor.locDelete.calcHref(servidor)
}) &
"data-name=add-servidor [href]" #>
MenuServidor.menuAdd.loc.calcDefaultHref
}

def add: CssSel = {


val servidor = new Servidor

val format = new java.text.SimpleDateFormat("dd/MM/yyyy")

//"data-name=id_servidor" #> SHtml.text("", fn =>


servidor.id_servidor = fn.toInt) &
"data-name=nom_servidor" #> SHtml.text("", ln =>
servidor.nom_servidor = ln) &
"data-name=so_servidor" #> SHtml.text("", lo =>
servidor.so_servidor = lo)&
"data-name=desc_servidor" #> SHtml.textarea("", ds =>
servidor.desc_servidor = ds)&

22
"data-name=id_log_auditoria" #> SHtml.text("", la =>
servidor.id_log_auditoria = la.toInt)&
"data-name=cve_estado" #> SHtml.text("", cs =>
servidor.cve_estado = cs)&
"type=submit" #>SHtml.ajaxSubmit("Guardar", () => {
JPAUtility.mergeAndFlush(servidor)
RedirectTo( MainMenu.servidor.loc.calcDefaultHref)
})
}

def edit: CssSel = {


(for {
servidor <- MenuServidor.menuEdit.currentValue
} yield {
val format = new java.text.SimpleDateFormat("dd/MM/yyyy")
"data-name=id_servidor"
#>SHtml.text(servidor.id_servidor.toString, si => servidor.id_servidor
= si.toInt,"disabled" -> "disabled") &
"data-name=nom_servidor" #>SHtml.text(servidor.nom_servidor, sn
=> servidor.nom_servidor = sn, "enable" -> "enable") &
"data-name=so_servidor" #>SHtml.text(servidor.so_servidor, so =>
servidor.so_servidor = so, "enable" -> "enable")&
"data-name=desc_servidor"
#>SHtml.textarea(servidor.desc_servidor, so => servidor.desc_servidor =
so, "enable" -> "enable")&
"data-name=id_log_auditoria"
#>SHtml.text(servidor.id_log_auditoria.toString, sa =>
servidor.id_log_auditoria = sa.toInt,"disabled" -> "disabled") &
"data-name=cve_estado" #> SHtml.text(servidor.cve_estado, ce =>
servidor.cve_estado = ce, "enable" -> "enable")&
"type=submit" #>SHtml.ajaxSubmit("Actualizar", () => {
JPAUtility.mergeAndFlush(servidor)
RedirectTo(MainMenu.servidor.loc.calcDefaultHref)
})
}).openOr("*" #> NodeSeq.Empty)
}

def delete: CssSel = {


(for {
servidor <- MenuServidor.menuDelete.currentValue
} yield {
val format = new java.text.SimpleDateFormat("dd/MM/yyyy")

"data-name=id_servidor" #>
SHtml.text(servidor.id_servidor.toString, fn =>(), "disabled" ->
"disabled") &
"data-name=nom_servidor" #> SHtml.text(servidor.nom_servidor,
ln => (), "disabled" -> "disabled") &
"data-name=so_servidor" #> SHtml.text(servidor.so_servidor, lo
=> (), "disabled" -> "disabled")&
"data-name=id_log_auditoria" #>
SHtml.text(servidor.id_log_auditoria.toString, ds => (), "disabled" ->
"disabled")&
"data-name=desc_servidor" #>
SHtml.textarea(servidor.desc_servidor, ds => (), "disabled" ->
"disabled")&
"data-name=cve_estado" #> SHtml.text(servidor.cve_estado, cs =>
(), "disabled" -> "disabled")&
"type=submit" #>SHtml.ajaxSubmit("Eliminar", () => {

23
// ToDo - delete
val removeCustomer = JPAUtility.merge(servidor)
JPAUtility.removeAndFlush(removeCustomer)
RedirectTo(MainMenu.servidor.loc.calcDefaultHref)
})

}).openOr("*" #> NodeSeq.Empty)


}

def view: CssSel = {


(for {
servidor <- MenuServidor.menuView.currentValue
} yield {
val format = new java.text.SimpleDateFormat("dd/MM/yyyy")
"data-name=id_servidor" #>
SHtml.text(servidor.id_servidor.toString, fn => servidor.id_servidor =
fn.toInt, "disabled" -> "disabled") &
"data-name=nom_servidor" #> SHtml.text(servidor.nom_servidor, ln
=> servidor.nom_servidor = ln, "disabled" -> "disabled") &
"data-name=so_servidor" #> SHtml.text(servidor.so_servidor, lo =>
servidor.so_servidor = lo, "disabled" -> "disabled")&
"data-name=desc_servidor" #>
SHtml.textarea(servidor.desc_servidor, ds => servidor.desc_servidor =
ds, "disabled" -> "disabled")&
"data-name=id_log_auditoria" #>
SHtml.text(servidor.id_log_auditoria.toString, la =>
servidor.id_log_auditoria = la.toInt, "disabled" -> "disabled") &
"data-name=cve_estado" #> SHtml.text(servidor.cve_estado, cs =>
servidor.cve_estado = cs, "disabled" -> "disabled") &
"type=submit" #>SHtml.ajaxSubmit("Atras", () => {
// ToDo - delete
JPAUtility.mergeAndFlush(servidor)
RedirectTo(MainMenu.servidor.loc.calcDefaultHref)
})

}).openOr("*" #> NodeSeq.Empty)


}
}
Figura 14 – Snippet Servidor – Módulo Activos TI

24
package code.lib.menu

import code.model.Servidor
import net.liftweb.common.{Box, Full}
import net.liftweb.http.{S, Templates}
import net.liftweb.sitemap.Loc.{LocGroup, Template}
import net.liftweb.sitemap.Menu
import scala.xml.NodeSeq

object MenuServidor {
lazy val menuAdd: Menu = Menu("Add Servidor", S ? "Adicionar
Servidor") / "crud" / "servidor" / "add" // >> LocGroup("servidor") //
>> Hidden

lazy val menuView: net.liftweb.sitemap.Menu.ParamMenuable[Servidor] =


Menu.param[Servidor]("View servidor", S ? "View.servidor",
c => getServidor(c), pc => pc.id_servidor.toString) /
"crud" / "servidor" / "view" >> LocGroup("servidor") >> Template(()
=> Templates("crud" :: "servidor" :: "view" :: Nil) openOr
NodeSeq.Empty) // >> Hidden

lazy val locView = menuView.toLoc

lazy val menuEdit: net.liftweb.sitemap.Menu.ParamMenuable[Servidor]


= Menu.param[Servidor]("Edit servidor category", S ?
"Edit.servidor.category",
c => getServidor(c), pc => pc.id_servidor.toString) /
"crud" / "servidor" / "edit" >> LocGroup("servidor") >> Template(()
=> Templates("crud" :: "servidor" :: "edit" :: Nil) openOr
NodeSeq.Empty) // >> Hidden

lazy val locEdit = menuEdit.toLoc

lazy val menuDelete:


net.liftweb.sitemap.Menu.ParamMenuable[Servidor] =
Menu.param[Servidor]("Delete servidor category",
S ? "Delete.servidor.category", c => getServidor(c), pc =>
pc.id_servidor.toString) /
"crud" / "servidor" / "delete" >> LocGroup("servidor") >>
Template(() => Templates("crud" :: "servidor" :: "delete" :: Nil)
openOr NodeSeq.Empty) // >> Hidden

lazy val locDelete = menuDelete.toLoc

def getServidor(id: String): Box[Servidor] = Servidor.find(id)


}
Figura 15 – Armado de menu Snippet – Módulo Activos TI

25
package report

import java.util

import code.model.Servidor
import net.liftweb.common.Box
import net.liftweb.http.LiftRules
import net.sf.jasperreports.engine._
import net.sf.jasperreports.engine.data.JRTableModelDataSource
import net.sf.jasperreports.engine.export.{JRCsvExporter, JRPdfExporter,
JRXhtmlExporter}
import net.sf.jasperreports.engine.export.ooxml.JRXlsxExporter
import net.sf.jasperreports.engine.fill.JRFileVirtualizer

import collection.JavaConverters

trait ServidorReport {

val list = List(ServidorSample.customer1,ServidorSample.customer2,


ServidorSample.customer3,ServidorSample.customer4
)

val dataSource= new ServidorSource(list)

lazy val parameters: java.util.Map[String, AnyRef] = {


val p: java.util.Map[String, AnyRef] = new java.util.HashMap
p.put(JRParameter.REPORT_VIRTUALIZER, fileVirtualizer)
p
}

val temporalPath:String = System.getProperty("user.home") +


java.io.File.separator + "tmp"
val temporalDir:java.io.File = new java.io.File(temporalPath)
if (!temporalDir.exists() || !temporalDir.isDirectory()) {
temporalDir.mkdir()
}

lazy val fileVirtualizer: JRFileVirtualizer = new JRFileVirtualizer(3,


temporalDir.getAbsolutePath )
}

class DownloadReportServidor() extends ServidorReport {


def downloadReport(reportType: String) = {
generateReport(dataSource, parameters, reportType)
}

private def generateReport(source: ServidorSource,


parameters: util.Map[String, AnyRef],
reportType: String) = {

val report: JasperReport =


JasperCompileManager.compileReport("src/main/resources/reports/servidor.jrxml")
val jasperPrint: JasperPrint = JasperFillManager.fillReport(report,
parameters
,dataSource)

val exporter: JRExporter = reportType match {


case "pdf" => new JRPdfExporter
case "xlsx" => new JRXlsxExporter
case "csv" => new JRCsvExporter
case _ => new JRXhtmlExporter

26
}

val out: java.io.ByteArrayOutputStream = new


java.io.ByteArrayOutputStream()

exporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint)
exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, out)

exporter.exportReport()
out
}
}

object ServidorSample {
val customer1 = new Servidor
customer1.id_servidor = 1
customer1.nom_servidor = "Power Builder"
customer1.so_servidor = "AIX 7"
customer1.desc_servidor = "IP-Pub:10.2.11.32 - IP-Int:11.1.11.4 - Puerto:1527
"
customer1.id_log_auditoria = 1
customer1.cve_estado = "N"
val customer2 = new Servidor
customer2.id_servidor = 2
customer2.nom_servidor = "GSIS"
customer2.so_servidor = "AIX 6"
customer2.desc_servidor = "IP-Pub:10.2.11.32 - IP-Int:100.10.20.10 -
Puerto:1527 "
customer2.id_log_auditoria = 1
customer2.cve_estado = "V"
val customer3 = new Servidor
customer3.id_servidor = 3
customer3.nom_servidor = "DDS"
customer3.so_servidor = "AIX 7"
customer3.desc_servidor = "IP-Pub:10.11.0.0 - IP-Int:11.1.11.4 - }

class ServidorSource(val lsBonos: List[Servidor]) extends JRDataSource{


var indiceActual: Int = -1

def getFieldValue(jrField: JRField) = jrField.getName match {


case "id_servidor" => lsBonos(indiceActual).id_servidor
case "nom_servidor" => lsBonos(indiceActual).nom_servidor
case "so_servidor" => lsBonos(indiceActual).so_servidor
case "desc_servidor" => lsBonos(indiceActual).desc_servidor
case "id_log_auditoria" => lsBonos(indiceActual).id_log_auditoria
case "cve_estado" => lsBonos(indiceActual).cve_estado
}

def next():Boolean = {
indiceActual = indiceActual + 1
indiceActual < lsBonos.size
}

}
Figura 16 – Reporte de Servidores – Módulo Activos TI

27
package bootstrap.liftweb

import net.liftweb._
import util._
import Helpers._
import common._
import http._
import js.jquery.JQueryArtifacts
import sitemap._
import Loc._
import code.lib.MainMenu
import code.lib.report.ReportRules
import code.model._
import net.liftmodules.JQueryModule

class Boot {
def boot {
LiftRules.addToPackages("code")

def sitemap = SiteMap(


(Menu.i("Inicio") / "index"),
Menu(Loc("Static", Link(List("static"), true, "/static/index"),
"Objetivo")),
MainMenu.customers,
MainMenu.servidor
)

LiftRules.setSiteMapFunc(() => sitemap)

JQueryModule.InitParam.JQuery=JQueryModule.JQuery1113
JQueryModule.init()

LiftRules.ajaxStart =
Full(() => LiftRules.jsArtifacts.show("ajax-loader").cmd)

LiftRules.ajaxEnd =
Full(() => LiftRules.jsArtifacts.hide("ajax-loader").cmd)

LiftRules.early.append(_.setCharacterEncoding("UTF-8"))

LiftRules.htmlProperties.default.set((r: Req) =>


new Html5Properties(r.userAgent))

ReportRules.appendDispatchRules
ReportRules.appendDispatchRules1
}
}
Figura 17 – Configuración del Boot.scala – Módulo Activos TI

28
5.4.3.2. Módulo Bibliotecas BCB

Nro de iteraciones totales : 7


Fecha: 04 de Junio al 07 de Junio de 2019.
Tiempo total invertido : 4 Hrs con 40 minutos aprox..

package code.snippet

import java.util.Locale

import code.lib.MainMenu
import code.lib.menu.MenuLector
import code.model.{Lector, JPAUtility}
import net.liftweb.common.Full
import net.liftweb.http.SHtml
import net.liftweb.http.js.JsCmds.RedirectTo
import net.liftweb.util.CssSel
import net.liftweb.util.Helpers._

import scala.xml.NodeSeq

object LectorSnippet {

def list: CssSel = {


def pageItems = Lector.findPage(1, 10)
def count =
JPAUtility.createNativeQuery[java.math.BigInteger]("select count(*)
from lector").getSingleResult().intValue

"data-name=list *" #> pageItems.map(lector => {


"data-name=codigo *" #> lector.idLector &
"data-name=nombre *" #> s"${lector.nombres} ${lector.paterno}
${lector.materno}" &
"data-name=view [href]" #> MenuLector.locView.calcHref(lector) &
"data-name=edit [href]" #> MenuLector.locEdit.calcHref(lector) &
"data-name=delete [href]" #>
MenuLector.locDelete.calcHref(lector)
}) &
"data-name=add-customer [href]" #>
MenuLector.menuAdd.loc.calcDefaultHref
}

def add: CssSel = {


val lector = new Lector

val format = new java.text.SimpleDateFormat("dd/MM/yyyy")

"data-name=nombres" #> SHtml.text("", nombres => lector.nombres =


nombres) &
"data-name=paterno" #> SHtml.text("", paterno => lector.paterno =
paterno) &
"data-name=materno" #> SHtml.text("", materno => lector.materno =
materno) &
"data-name=codigo" #> SHtml.text("", codigo => lector.codEmpleado =
codigo) &
"data-name=fono" #> SHtml.text("", fono => lector.telefono = fono)
&
"data-name=direccion" #> SHtml.text("", direccion =>
lector.direccion = direccion) &

29
"data-name=tipo" #> SHtml.text("", tipo => lector.cveTipoLector =
tipo) &
"data-name=estado" #> SHtml.text("", estado => lector.estado =
estado) &
"data-name=fecha" #> SHtml.text("", fecha => lector.fechaRegistro =
format.parse(fecha)) &
"type=submit" #>SHtml.ajaxSubmit("Save", () => {
JPAUtility.mergeAndFlush(lector)
RedirectTo( MainMenu.lectores.loc.calcDefaultHref)
})
"type=button" #>SHtml.ajaxButton("Cancelar", () => {
RedirectTo( MainMenu.lectores.loc.calcDefaultHref)
})
}

def edit: CssSel = {


(for {
lector <- MenuLector.menuEdit.currentValue
} yield {
val format = new java.text.SimpleDateFormat("dd/MM/yyyy")
"data-name=codigo" #> SHtml.text(lector.codEmpleado, codigo =>
lector.codEmpleado= codigo) &
"data-name=nombres" #> SHtml.text(lector.nombres, nombres =>
lector.nombres = nombres) &
"data-name=paterno" #> SHtml.text(lector.paterno, paterno =>
lector.paterno = paterno) &
"data-name=materno" #> SHtml.text(lector.materno, materno =>
lector.materno = materno) &
"data-name=direccion" #> SHtml.text(lector.direccion, direccion
=> lector.direccion = direccion) &
"data-name=tipo" #> SHtml.text(lector.cveTipoLector, tipo =>
lector.cveTipoLector = tipo) &
"data-name=fono" #> SHtml.text(lector.telefono, fono =>
lector.telefono = fono) &
"data-name=estado" #> SHtml.text(lector.estado, estado =>
lector.estado = estado) &
"data-name=fecha" #>
SHtml.text(format.format(lector.fechaRegistro), fecha =>
lector.fechaRegistro = format.parse(fecha)) &
"type=submit" #>SHtml.ajaxSubmit("Update", () => {
JPAUtility.mergeAndFlush(lector)
RedirectTo(MainMenu.lectores.loc.calcDefaultHref)
})
}).openOr("*" #> NodeSeq.Empty)
}

def delete: CssSel = {


(for {
lector <- MenuLector.menuDelete.currentValue
} yield {
val format = new java.text.SimpleDateFormat("dd/MM/yyyy")
"data-name=codigo" #> SHtml.text(lector.codEmpleado, codigo
=> lector.codEmpleado= codigo) &
"data-name=nombres" #> SHtml.text(lector.nombres, nombres
=> lector.nombres = nombres) &
"data-name=paterno" #> SHtml.text(lector.paterno, paterno
=> lector.paterno = paterno) &
"data-name=materno" #> SHtml.text(lector.materno, materno
=> lector.materno = materno) &
"data-name=direccion" #> SHtml.text(lector.direccion,
direccion => lector.direccion = direccion) &

30
"data-name=tipo" #> SHtml.text(lector.cveTipoLector, tipo
=> lector.cveTipoLector = tipo) &
"data-name=fono" #> SHtml.text(lector.telefono, fono =>
lector.telefono = fono) &
"data-name=estado" #> SHtml.text(lector.estado, estado =>
lector.estado = estado) &
"data-name=fecha" #>
SHtml.text(format.format(lector.fechaRegistro), fecha =>
lector.fechaRegistro = format.parse(fecha)) &
"type=submit" #>SHtml.ajaxSubmit("Delete", () => {
// ToDo - delete
val removeLector = JPAUtility.merge(lector)
JPAUtility.removeAndFlush(removeLector)
RedirectTo(MainMenu.lectores.loc.calcDefaultHref)
})
}).openOr("*" #> NodeSeq.Empty)
}

def view: CssSel = {


(for {
lector <- MenuLector.menuView.currentValue
} yield {
val format = new java.text.SimpleDateFormat("dd/MM/yyyy")
"data-name=nombres" #> SHtml.text(lector.nombres, nombres =>(),
"disabled" -> "disabled") &
"data-name=paterno" #> SHtml.text(lector.paterno, paterno => (),
"disabled" -> "disabled") &
"data-name=materno" #> SHtml.text(lector.materno, materno => (),
"disabled" -> "disabled") &
"data-name=direccion" #> SHtml.text(lector.direccion, direccion
=> (), "disabled" -> "disabled") &
"data-name=estado" #> SHtml.text(lector.estado, estado => (),
"disabled" -> "disabled") &
"data-name=tipo" #> SHtml.text(lector.cveTipoLector, tipo => (),
"disabled" -> "disabled") &
"data-name=codigo" #> SHtml.text(lector.codEmpleado, codigo =>
(), "disabled" -> "disabled") &
"data-name=fono" #> SHtml.text(lector.telefono, fono => (),
"disabled" -> "disabled") &
"data-name=fecha" #>
SHtml.text(format.format(lector.fechaRegistro), fecha => (), "disabled"
-> "disabled") &
"type=submit" #>SHtml.ajaxSubmit("Return", () => {
// ToDo - delete
// JPAUtility.mergeAndFlush(lector)
RedirectTo(MainMenu.lectores.loc.calcDefaultHref)
})
}).openOr("*" #> NodeSeq.Empty)
}

}
Figura 18 – Snippet Lector – Módulo Bblioteca BCB

31
package code.snippet

import java.util.{Date, Locale}


import code.lib.MainMenu
import code.lib.menu.{MenuCustomer, MenuPrestamo}
import code.model.{JPAUtility, Prestamo}
import net.liftweb.util.CssSel
import net.liftweb.common.Full
import net.liftweb.http.SHtml
import javax.persistence.EntityManager
import net.liftweb.http.js.JsCmds.RedirectTo
import scala.xml.NodeSeq
import net.liftweb.util.Helpers._

object PrestamoSnippet{
def list: CssSel = {
def pageItems = Prestamo.findPage(1, 10)
def count =
JPAUtility.createNativeQuery[java.math.BigInteger]("select count(*)
from prestamo").getSingleResult().intValue
"data-name=list *" #> pageItems.map(prestamo => {
"data-name=code *" #> prestamo.idPrestamo &
"data-name=fechaprestamo *" #> s"${prestamo.fechaPrestamo}" &
"data-name=fechadevolucion *" #> s"${prestamo.fechaDevolucion}" &
"data-name=tipo *" #> s"${prestamo.cveTipoPrestamo}" &
"data-name=estado *" #> s"${prestamo.estado}" &
"data-name=edit [href]" #> MenuPrestamo.locEdit.calcHref(prestamo) &
"data-name=view [href]" #> MenuPrestamo.locView.calcHref(prestamo) &
"data-name=delete [href]" #>
MenuPrestamo.locDelete.calcHref(prestamo)
})
}
def add: CssSel = {
val prestamo = new Prestamo
val format = new java.text.SimpleDateFormat("dd/MM/yyyy")
case class Estado(id: String, descripcion: String) {
override def toString: String = descripcion }
val estados = List(Estado("P","Prestado"),Estado("D","Devuelto"))

"data-name=fechaprestamo" #> SHtml.text("", fechaPrestamo =>


prestamo.fechaPrestamo = format.parse(fechaPrestamo)) &
"data-name=fechadevolucion" #> SHtml.text("", fechaDevolucion =>
prestamo.fechaDevolucion = format.parse(fechaDevolucion)) &
"data-name=tipo" #> SHtml.text("", fn => prestamo.cveTipoPrestamo =
fn) &
"data-name=estado" #> SHtml.selectElem(estados, Full(estados.head))
(estado => prestamo.estado = estado.descripcion)&
"type=submit" #>SHtml.ajaxSubmit("Save", () => {
JPAUtility.mergeAndFlush(prestamo)
RedirectTo( MainMenu.prestamos.loc.calcDefaultHref)
})
}
def edit: CssSel = {
(for {
prestamo <- MenuPrestamo.menuEdit.currentValue
} yield {
val format = new java.text.SimpleDateFormat("dd/MM/yyyy")
"data-name=fecha_prestamo" #>
SHtml.text(format.format(prestamo.fechaPrestamo), fechap =>
prestamo.fechaPrestamo = format.parse(fechap)) &

32
"data-name=fecha_devolucion" #> SHtml.text("", fechaDevolucion =>
prestamo.fechaDevolucion = format.parse(fechaDevolucion)) &
"data-name=tipo" #> SHtml.text(prestamo.cveTipoPrestamo, fn =>
prestamo.cveTipoPrestamo = fn) &
"data-name=estado" #> SHtml.text(prestamo.estado, ln =>
prestamo.estado = ln) &
"data-name=fecha_devolucion" #>
SHtml.text(format.format(prestamo.fechaDevolucion), fechap =>
prestamo.fechaDevolucion = format.parse(fechap)) &
"type=submit" #>SHtml.ajaxSubmit("Update", () => {
JPAUtility.mergeAndFlush(prestamo)
RedirectTo(MainMenu.prestamos.loc.calcDefaultHref)
})
}).openOr("*" #> NodeSeq.Empty)
}
def view: CssSel = {
(for {
prestamo <- MenuPrestamo.menuView.currentValue
} yield {
val format = new java.text.SimpleDateFormat("dd/MM/yyyy")
"data-name=fecha_prestamo" #>
SHtml.text(format.format(prestamo.fechaPrestamo), fechaPrestamo => (),
"disabled" -> "disabled") &
"data-name=tipo" #> SHtml.text(prestamo.cveTipoPrestamo, fn =>(),
"disabled" -> "disabled") &
"data-name=estado" #> SHtml.text(prestamo.estado, ln => (),
"disabled" -> "disabled") &
"data-name=fecha_devolucion" #>
SHtml.text(format.format(prestamo.fechaDevolucion), fechaDevolucion =>
(), "disabled" -> "disabled") &
"type=submit" #>SHtml.ajaxSubmit("Return", () => {
RedirectTo(MainMenu.prestamos.loc.calcDefaultHref)
})
}).openOr("*" #> NodeSeq.Empty)
}
def delete: CssSel = {
(for {
prestamo <- MenuPrestamo.menuDelete.currentValue
} yield {
val format = new java.text.SimpleDateFormat("dd/MM/yyyy")
"data-name=fecha_prestamo" #>
SHtml.text(format.format(prestamo.fechaPrestamo), fechaPrestamo => (),
"disabled" -> "disabled") &
"data-name=tipo" #> SHtml.text(prestamo.cveTipoPrestamo, fn
=>(), "disabled" -> "disabled") &
"data-name=estado" #> SHtml.text(prestamo.estado, ln => (),
"disabled" -> "disabled") &
"data-name=fecha_devolucion" #>
SHtml.text(format.format(prestamo.fechaDevolucion), fechaDevolucion =>
(), "disabled" -> "disabled") &
"type=submit" #>SHtml.ajaxSubmit("Delete", () => {
// ToDo - delete
val removePrestamo = JPAUtility.merge(prestamo)
JPAUtility.removeAndFlush(removePrestamo)
RedirectTo(MainMenu.prestamos.loc.calcDefaultHref)
})
}).openOr("*" #> NodeSeq.Empty)
}
}
Figura 19 – Snippet Prestamo – Módulo Boblioteca BCB

33
package report

import java.util

import code.model.Customer
import net.liftweb.common.Box
import net.liftweb.http.LiftRules
import net.sf.jasperreports.engine._
import net.sf.jasperreports.engine.data.JRTableModelDataSource
import net.sf.jasperreports.engine.export.{JRCsvExporter, JRPdfExporter,
JRXhtmlExporter}
import net.sf.jasperreports.engine.export.ooxml.JRXlsxExporter
import net.sf.jasperreports.engine.fill.JRFileVirtualizer

import collection.JavaConverters

trait PrestamoReport {

val list = List(CustomerSample.customer1,


CustomerSample.customer2,
CustomerSample.customer3,
CustomerSample.customer4)

val dataSource= new CustomerSource(list)

lazy val parameters: java.util.Map[String, AnyRef] = {


val p: java.util.Map[String, AnyRef] = new java.util.HashMap
p.put(JRParameter.REPORT_VIRTUALIZER, fileVirtualizer)
p
}

val temporalPath:String = System.getProperty("user.home") +


java.io.File.separator + "tmp"
val temporalDir:java.io.File = new java.io.File(temporalPath)
if (!temporalDir.exists() || !temporalDir.isDirectory()) {
temporalDir.mkdir()
}

lazy val fileVirtualizer: JRFileVirtualizer = new JRFileVirtualizer(3,


temporalDir.getAbsolutePath )
}

class DownloadReportCustomer() extends PrestamoReport {


def downloadReport(reportType: String) = {
generateReport(dataSource, parameters, reportType)
}

private def generateReport(source: CustomerSource,


parameters: util.Map[String, AnyRef],
reportType: String) = {

val report: JasperReport =


JasperCompileManager.compileReport("src/main/resources/reports/prestamo.jrxml")
val jasperPrint: JasperPrint = JasperFillManager.fillReport(report,
parameters
,dataSource)

val exporter: JRExporter = reportType match {


case "pdf" => new JRPdfExporter
case "xlsx" => new JRXlsxExporter
case "csv" => new JRCsvExporter

34
case _ => new JRXhtmlExporter
}

val out: java.io.ByteArrayOutputStream = new


java.io.ByteArrayOutputStream()

exporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint)
exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, out)

exporter.exportReport()
out
}
}

object CustomerSample {
val customer1 = new Customer
customer1.firstname = "Cuentos para niños"
customer1.lastname = "EN SALA"
customer1.email = "PRESTADO"
customer1.birthday = java.util.Calendar.getInstance().getTime

val customer2 = new Customer


customer2.firstname = "Leyendas de La Paz"
customer1.lastname = "EN SALA"
customer1.email = "PRESTADO"
customer2.birthday = java.util.Calendar.getInstance().getTime

val customer3 = new Customer


customer3.firstname = "La noche de brujas"
customer1.lastname = "EN SALA"
customer1.email = "PRESTADO"
customer3.birthday = java.util.Calendar.getInstance().getTime

val customer4 = new Customer


customer4.firstname = "Matematica TOMO 1"
customer1.lastname = "EN SALA"
customer1.email = "PRESTADO"
customer4.birthday = java.util.Calendar.getInstance().getTime
}

class CustomerSource(val lsBonos: List[Customer]) extends JRDataSource{


var indiceActual: Int = -1

def getFieldValue(jrField: JRField) = jrField.getName match {


case "LIBRO" => lsBonos(indiceActual).firstname
case "TIPOPRESTAMO" => lsBonos(indiceActual).lastname
case "ESTADO" => lsBonos(indiceActual).email
case "FECHAPRESTAMO" => lsBonos(indiceActual).birthday.toString

def next():Boolean = {
indiceActual = indiceActual + 1
indiceActual < lsBonos.size
}

}
Figura 20 – Reporte de préstamos – Módulo Biblioteca BCB

35
package bootstrap.liftweb

import net.liftweb._
import util._
import Helpers._
import common._
import http._
import js.jquery.JQueryArtifacts
import sitemap._
import Loc._
import code.lib
import code.lib.MainMenu
import code.lib.report.ReportRules

import code.model._
import net.liftmodules.JQueryModule

class Boot {
def boot {
LiftRules.addToPackages("code")

// Build SiteMap
def sitemap = SiteMap(
(Menu.i("Inicio") / "index"),
Menu(Loc("Static", Link(List("static"), true, "/static/index"),
"Busqueda")),
MainMenu.lectores,
MainMenu.prestamos,
MainMenu.clasificacion,
MainMenu.catalogo,
MainMenu.editorial
)

LiftRules.setSiteMapFunc(() => sitemap)

JQueryModule.InitParam.JQuery=JQueryModule.JQuery1113
JQueryModule.init()

LiftRules.ajaxStart =
Full(() => LiftRules.jsArtifacts.show("ajax-loader").cmd)

LiftRules.ajaxEnd =
Full(() => LiftRules.jsArtifacts.hide("ajax-loader").cmd)

LiftRules.early.append(_.setCharacterEncoding("UTF-8"))

LiftRules.htmlProperties.default.set((r: Req) =>


new Html5Properties(r.userAgent))

ReportRules.appendDispatchRules
}
}
Figura 21 – Configuración del Boot.scala – Módulo de Biblioteca BCB

36
5.4.3.3. Modulo Casa de cambio

Nro de iteraciones totales : 7


Fecha: 04 de Junio al 07 de Junio de 2019.
Tiempo total invertido : 4 Hrs con 40 minutos aprox.

package code.snippet

import code.lib.MainMenu
import code.lib.menu.MenuMoneda
import code.model.Moneda
import code.model.{Cliente, Customer, JPAUtility}
import net.liftweb.common.Full
import net.liftweb.http.SHtml
import net.liftweb.http.js.JsCmds.RedirectTo
import net.liftweb.util.CssSel
import net.liftweb.util.Helpers._

import scala.xml.NodeSeq

object MonedaSnippet {

def list: CssSel = {


def pageItems = Moneda.findPage(1, 10)
def count =
JPAUtility.createNativeQuery[java.math.BigInteger]("select count(*)
from moneda").getSingleResult().intValue

"data-name=list *" #> pageItems.map(moneda => {


//"data-name=id *" #> moneda.id &
"data-name=codmoneda *" #> s"${moneda.codmoneda}" &
"data-name=nommoneda *" #> s"${moneda.nommoneda}" &
"data-name=view [href]" #> MenuMoneda.locView.calcHref(moneda) &
"data-name=edit [href]" #> MenuMoneda.locEdit.calcHref(moneda) &
"data-name=delete [href]" #>
MenuMoneda.locDelete.calcHref(moneda)
}) &
"data-name=add-cliente [href]" #>
MenuMoneda.menuAdd.loc.calcDefaultHref
}

def add: CssSel = {


val moneda = new Moneda
//val format = new java.text.SimpleDateFormat("dd/MM/yyyy")
"data-name=codmoneda" #> SHtml.text("", fn => moneda.codmoneda =
fn) &
"data-name=nommoneda" #> SHtml.text("", ln => moneda.nommoneda =
ln) &
"type=submit" #>SHtml.ajaxSubmit("Save", () => {
JPAUtility.mergeAndFlush(moneda)
RedirectTo( MainMenu.moneda.loc.calcDefaultHref)
})
}

def edit: CssSel = {


(for {
moneda <- MenuMoneda.menuEdit.currentValue
} yield {

37
val format = new java.text.SimpleDateFormat("dd/MM/yyyy")
"data-name=codmoneda" #> SHtml.text(moneda.codmoneda, fn =>
moneda.codmoneda = fn) &
"data-name=nommoneda" #> SHtml.text(moneda.nommoneda, ln =>
moneda.nommoneda = ln) &
"type=submit" #>SHtml.ajaxSubmit("Update", () => {
JPAUtility.mergeAndFlush(moneda)
RedirectTo(MainMenu.moneda.loc.calcDefaultHref)
})
}).openOr("*" #> NodeSeq.Empty)
}

def delete: CssSel = {


(for {
moneda <- MenuMoneda.menuDelete.currentValue
} yield {
val format = new java.text.SimpleDateFormat("dd/MM/yyyy")
"data-name=codmoneda" #> SHtml.text(moneda.codmoneda, fn =>(),
"disabled" -> "disabled") &
"data-name=nommoneda" #> SHtml.text(moneda.nommoneda, ln => (),
"disabled" -> "disabled") &
"type=submit" #>SHtml.ajaxSubmit("Delete", () => {
// ToDo - delete
val removeCliente = JPAUtility.merge(moneda)
JPAUtility.removeAndFlush(removeCliente)
RedirectTo(MainMenu.moneda.loc.calcDefaultHref)
})
}).openOr("*" #> NodeSeq.Empty)
}

def view: CssSel = {


(for {
moneda <- MenuMoneda.menuView.currentValue
} yield {
//val format = new java.text.SimpleDateFormat("dd/MM/yyyy")
//"data-name=id" #> SHtml.text(moneda.id, fn =>(), "disabled" ->
"disabled") &
"data-name=codmoneda" #> SHtml.text(moneda.codmoneda, fn => (),
"disabled" -> "disabled") &
"data-name=nommoneda" #> SHtml.text(moneda.nommoneda, ln => (),
"disabled" -> "disabled") &
"type=submit" #>SHtml.ajaxSubmit("Return", () => {
// ToDo - delete
// JPAUtility.mergeAndFlush(customer)
RedirectTo(MainMenu.moneda.loc.calcDefaultHref)
})
}).openOr("*" #> NodeSeq.Empty)
}

}
Figura 22 - Snippet Moneda - Módulo Casa de cambio

38
package code.snippet

import java.util.{Date, Locale}


import code.lib.MainMenu
import code.lib.menu.MenuTipocambio
import code.model.{Tipocambio, JPAUtility, Moneda}
import net.liftweb.util.CssSel
import net.liftweb.common.Full
import net.liftweb.http.SHtml
import javax.persistence.EntityManager
import net.liftweb.http.js.JsCmds.RedirectTo
import scala.xml.NodeSeq
import net.liftweb.util.Helpers._

object TipoCambioSnippet {
def list: CssSel = {
def pageItems = Tipocambio.findPage(1, 10)
def count =
JPAUtility.createNativeQuery[java.math.BigInteger]("select count(*)
from tipocambio").getSingleResult().intValue
"data-name=list *" #> pageItems.map(tipocambio => {
"data-name=moneda_id *" #> tipocambio.moneda.toString &
"data-name=fecha *" #> s"${tipocambio.fecha} " &
"data-name=factor_oficial *" #>
s"${tipocambio.factor_oficial.toString } " &
"data-name=factor_compra *" #>
s"${tipocambio.factor_compra.toString } " &
"data-name=factor_oficial *" #>
s"${tipocambio.factor_venta.toString } " &
"data-name=view [href]" #>
MenuTipocambio.locView.calcHref(tipocambio) &
"data-name=edit [href]" #>
MenuTipocambio.locEdit.calcHref(tipocambio) &
"data-name=delete [href]" #>
MenuTipocambio.locDelete.calcHref(tipocambio)
}) &
"data-name=add-tipocambio [href]" #>
MenuTipocambio.menuAdd.loc.calcDefaultHref
}
def sumF (a: java.math.BigDecimal, b: java.math.BigDecimal):
java.math.BigDecimal = {
return a.add(b)
}
def add: CssSel = {
val tipocambio = new Tipocambio
val format = new java.text.SimpleDateFormat("dd/MM/yyyy")
val monedas = Moneda.findAll()
var tfc = tipocambio.factor_oficial.add(tipocambio.factor_compra)

"data-name=moneda_id" #> SHtml.selectElem[Moneda](monedas,


Full(monedas.head))(moneda => tipocambio.moneda = moneda) &
"data-name=fecha" #> SHtml.text("", fecha => tipocambio.fecha =
format.parse(fecha)) &
"data-name=factor_oficial" #> SHtml.ajaxText("", fo => {
tipocambio.factor_oficial = (new
java.math.BigDecimal(fo))
tfc = sumF(tipocambio.factor_oficial,
tipocambio.factor_compra)
}) &
"data-name=factor_compra" #> SHtml.ajaxText("", fc => {
tipocambio.factor_compra = (new java.math.BigDecimal(fc))

39
tfc = sumF(tipocambio.factor_oficial, tipocambio.factor_compra)
}) &
"data-name=factor_venta" #> SHtml.ajaxText(tfc.toString,fc => ()) &
"type=submit" #>SHtml.ajaxSubmit("Save", () => {
JPAUtility.mergeAndFlush(tipocambio)
RedirectTo( MainMenu.tipocambio.loc.calcDefaultHref)
})
}
def edit: CssSel = {
(for {
tipocambio <- MenuTipocambio.menuEdit.currentValue
} yield {
val monedas = Moneda.findAll()
val format = new java.text.SimpleDateFormat("dd/MM/yyyy")

"data-name=moneda_id" #> SHtml.selectElem[Moneda](monedas,


Full(monedas.head))(moneda => tipocambio.moneda= moneda) &
"data-name=fecha" #> SHtml.text(format.format(tipocambio.fecha),
fecha => tipocambio.fecha = format.parse(fecha)) &
"type=submit" #>SHtml.ajaxSubmit("Update", () => {
JPAUtility.mergeAndFlush(tipocambio)
RedirectTo(MainMenu.tipocambio.loc.calcDefaultHref)
})
}).openOr("*" #> NodeSeq.Empty)
}
def delete: CssSel = {
(for {
tipocambio <- MenuTipocambio.menuDelete.currentValue
} yield {
val format = new java.text.SimpleDateFormat("dd/MM/yyyy")
"data-name=moneda_id" #> SHtml.text(tipocambio.moneda.toString,
mid =>(), "disabled" -> "disabled") &
"data-name=fecha" #>
SHtml.text(format.format(tipocambio.fecha), fecha => (), "disabled" ->
"disabled") &
"type=submit" #>SHtml.ajaxSubmit("Delete", () => {
// ToDo - delete
val removeTipocambio = JPAUtility.merge(tipocambio)
JPAUtility.removeAndFlush(removeTipocambio)
RedirectTo(MainMenu.tipocambio.loc.calcDefaultHref)
})
}).openOr("*" #> NodeSeq.Empty)
}
def view: CssSel = {
(for {
tipocambio <- MenuTipocambio.menuView.currentValue
} yield {
val format = new java.text.SimpleDateFormat("dd/MM/yyyy")

"data-name=moneda_id" #> SHtml.text(tipocambio.moneda.toString,


mid =>(), "disabled" -> "disabled") &
"data-name=fecha" #> SHtml.text(format.format(tipocambio.fecha),
fecha => (), "disabled" -> "disabled") &
"type=submit" #>SHtml.ajaxSubmit("Return", () => {
RedirectTo(MainMenu.tipocambio.loc.calcDefaultHref)
})
}).openOr("*" #> NodeSeq.Empty)
}
}
Figura 23 – Snippet TipoCambio - Módulo Casa de cambio

40
package snippet

import net.liftweb._
import http._
import SHtml._
import util._
import Helpers._
import code.model.Moneda
import js._
import js.JsCmds._
import js.jquery._
import net.liftweb.common.Full
import scala.xml.{NodeSeq, Text}

case class Line (guid: String, name: String, price: Double, taxable:
Boolean, descuento: Double)
case class Line (guid: String, name: String, price: Double)
case class NextLine (Canitdad: Double, total: Double)

class InvoiceWiring {
private object Info {
val invoices = ValueCell(List(newLine))
val taxRate = ValueCell(0.50d) // Se define el
valor del TAX
val subtotal = invoices.lift(_.foldLeft(0d)(_ + _.price))
val taxable = invoices.lift(_.filter(_.taxable).
foldLeft(0D)(_ + _.price))

val descuento = invoices.lift(_.filter(_.taxable).


foldLeft(0D)(_ + _.descuento))
val tax = taxRate.lift(taxable) {_ * _}
val total = subtotal.lift(tax) {_ + _}
}

def subtotal = WiringUI.toNode(Info.subtotal)(doubleDraw)


def taxable = WiringUI.toNode(Info.taxable)(doubleDraw)
def tax = WiringUI.toNode(Info.tax, JqWiringSupport.fade)(doubleDraw)
def total = WiringUI.toNode(Info.total,
JqWiringSupport.fade)(doubleDraw)
def des = WiringUI.toNode(Info.descuento,
JqWiringSupport.fade)(doubleDraw)
def taxRate = ajaxText(Info.taxRate.get.toString,
doubleToJsCmd(Info.taxRate.set))

def showLines = "showLines" #>


(Info.invoices.get.flatMap(renderLine): NodeSeq)

def addLine =
"#det [onclick]" #> ajaxInvoke(() =>
// JqJsCmds.AppendHtml("addLine", renderLine(appendLine)))
JqJsCmds.AppendHtml("invoice_lines", renderLine(appendLine)))

private def renderLine(theLine: Line): NodeSeq = {


import theLine._
val monedas = Moneda.findAll()

<div id={guid}>
{ajaxSelectElem(monedas, Full(monedas.head))((monselect:Moneda)
=> { mutateLine(guid) {line => line.copy(name=monselect.id.toString)}}
)}
var

41
{ajaxText(price.toString,
(d: Double) => mutateLine(guid) {_.copy(price = d)})}

{ajaxText (descuento.toString,
(d: Double) => mutateLine(guid) {_.copy(descuento = d)})}

{ajaxCheckbox(theLine.taxable,
b => mutateLine(guid) {_.copy(taxable = b)})}
</div>
}

private def newLine = Line(nextFuncName, "", 6.89, false, 10.0d)


// Se agrega un VALOR de descuento

private def appendLine: Line = {


val ret = newLine
Info.invoices.set(ret :: Info.invoices.get)
ret
}

private def mutateLine(guid: String)(f: Line => Line) {


val all = Info.invoices.get
val head = all.filter(_.guid == guid).map(f)
val rest = all.filter(_.guid != guid)
Info.invoices.set(head ::: rest)
}
// convert a Double to a NodeSeq
private def doubleDraw: (Double, NodeSeq) => NodeSeq =
(d, ns) =>
Text(java.text.NumberFormat.getCurrencyInstance.format(d))

// Some helpful implicit conversions


private implicit def unitToJsCmd(in: Unit): JsCmd = Noop
private implicit def doubleToJsCmd(in: Double => Any): String =>
JsCmd =
str => {asDouble(str).foreach(in)}
}
Figura 24 – Wiring para transacciones - Módulo Casa de cambio

42
package code.snippet

import java.util.{Date, Locale}


import code.lib.MainMenu
import code.lib.menu.MenuTransaccion
import code.model.{Cliente, JPAUtility, Tipocambio, Transaccion}
import net.liftweb.util.CssSel
import net.liftweb.common.Full
import net.liftweb.http.SHtml
import javax.persistence.EntityManager
import net.liftweb.http.js.JsCmds.RedirectTo
import scala.xml.NodeSeq
import net.liftweb.util.Helpers._
import snippet.InvoiceWiring

object TransaccionSnippet {
def list: CssSel = {
def pageItems = Transaccion.findPage(1, 10)
def count =
JPAUtility.createNativeQuery[java.math.BigInteger]("select count(*)
from transaccion").getSingleResult().intValue
"data-name=list *" #> pageItems.map(transaccion => {
"data-name=fecha_trans *" #> transaccion.fecha_trans.toString &
"data-name=cliente_id *" #> s"${transaccion.cliente} " &
"data-name=concepto *" #> s"${transaccion.concepto } " &
"data-name=view [href]" #>
MenuTransaccion.locView.calcHref(transaccion) &
"data-name=edit [href]" #>
MenuTransaccion.locEdit.calcHref(transaccion) &
"data-name=delete [href]" #>
MenuTransaccion.locDelete.calcHref(transaccion)
}) &
"data-name=add-transaccion [href]" #>
MenuTransaccion.menuAdd.loc.calcDefaultHref
}

def add: CssSel = {


val transaccion = new Transaccion
val tipocambio = new Tipocambio
val grid = new InvoiceWiring
val format = new java.text.SimpleDateFormat("dd/MM/yyyy")
val facOficial = Tipocambio.findTipoFocial()
val clientes = Cliente.findAll()

"data-name=fecha_trans" #> SHtml.text("06/06/2019", fec =>


transaccion.fecha_trans = format.parse(fec)) &
"data-name=cliente_id" #> SHtml.selectElem[Cliente](clientes,
Full(clientes.head))(cli => transaccion.cliente = cli) &
"data-name=concepto" #> SHtml.text("", con => transaccion.concepto
= con.trim) &
"data-name=factor_oficial *" #>
facOficial.head.factor_oficial.toString &
grid.addLine &
"type=submit" #>SHtml.ajaxSubmit("Save", () => {
JPAUtility.mergeAndFlush(transaccion)
RedirectTo( MainMenu.transaccion.loc.calcDefaultHref)
}) //grid.showLines
}
def edit: CssSel = {
(for {
transaccion <- MenuTransaccion.menuEdit.currentValue

43
} yield {
val clientes = Cliente.findAll()
val format = new java.text.SimpleDateFormat("dd/MM/yyyy")
"data-name=fecha_trans" #>
SHtml.text(format.format(transaccion.fecha_trans), fecha =>
transaccion.fecha_trans = format.parse(fecha)) &
"data-name=cliente_id" #> SHtml.selectElem[Cliente](clientes,
Full(clientes.head))(cli => transaccion.cliente = cli) &
"data-name=concepto" #> SHtml.text(transaccion.concepto, ad =>
transaccion.concepto = ad.trim) &
"type=submit" #>SHtml.ajaxSubmit("Update", () => {
JPAUtility.mergeAndFlush(transaccion)
RedirectTo(MainMenu.transaccion.loc.calcDefaultHref)
})
}).openOr("*" #> NodeSeq.Empty)
}
def delete: CssSel = {
(for {
transaccion <- MenuTransaccion.menuDelete.currentValue
} yield {
val format = new java.text.SimpleDateFormat("dd/MM/yyyy")
"data-name=fecha_trans" #>
SHtml.text(format.format(transaccion.fecha_trans), fecha => (),
"disabled" -> "disabled") &
"data-name=concepto" #> SHtml.text("", con =>
transaccion.concepto = con) &
"type=submit" #>SHtml.ajaxSubmit("Delete", () => {
// ToDo - delete
val removeTransaccion = JPAUtility.merge(transaccion)
JPAUtility.removeAndFlush(removeTransaccion)
RedirectTo(MainMenu.transaccion.loc.calcDefaultHref)
})
}).openOr("*" #> NodeSeq.Empty)
}

def view: CssSel = {


(for {
transaccion <- MenuTransaccion.menuView.currentValue
} yield {
val format = new java.text.SimpleDateFormat("dd/MM/yyyy")

"data-name=cliente_id" #>
SHtml.text(transaccion.cliente.toString, mid =>(), "disabled" ->
"disabled") &
"data-name=fecha_trans" #>
SHtml.text(format.format(transaccion.fecha_trans), fecha => (),
"disabled" -> "disabled") &
"data-name=concepto" #> SHtml.text(transaccion.concepto, ad =>
(), "disabled" -> "disabled") &
"type=submit" #>SHtml.ajaxSubmit("Return", () => {
// ToDo - delete
// JPAUtility.mergeAndFlush(tipocambio)
RedirectTo(MainMenu.transaccion.loc.calcDefaultHref)
})
}).openOr("*" #> NodeSeq.Empty)
}
}
Figura 25 – Snippet de transacciones con uso de Wiring - Módulo Casa de
cambio

44
5.4.3.4. Modulo Interfaz SWIFT

Nro de iteraciones totales : 7


Fecha: 04 de Junio al 07 de Junio de 2019.
Tiempo total invertido : 4 Hrs con 40 minutos aprox..

package code.snippet

import code.lib.MainMenu
import code.lib.menu.MenuSwift
import code.model.{JPAUtility, Swiftcurso}
import net.liftweb.http.SHtml
import net.liftweb.http.js.JsCmds.RedirectTo
import net.liftweb.util.{CssSel, Html5}
import net.liftweb.util.Helpers._
import report.DownloadReportCustomer
import scala.xml
import scala.xml.NodeSeq

object SwiftSnippet {
def list: CssSel = {
def pageItems = Swiftcurso.getAll()

def count = 1 //
JPAUtility.createNativeQuery[java.math.BigInteger]("select count(*)
from customer;").getSingleResult().intValue

"data-name=list *" #> pageItems.map(swiftcurso => {


"data-name=id *" #> swiftcurso.id &
"data-name=estado *" #> swiftcurso.estado &
"data-name=plano *" #> swiftcurso.plano &
"data-name=view [href]" #>
MenuSwift.locView.calcHref(swiftcurso)&
"data-name=viewpdf [href]" #>
MenuSwift.menuViewPdf.toLoc.calcHref(swiftcurso)
})
}

def showPdf = {
/* (for {
swiftcurso <- MenuSwift.menuView.currentValue
} yield {*/
"#viewpdf" #> {

/*val archSwift = "e:/tmp/swf_conlau.dos"


println("====generarReportePDFFromPlanoTestOut===== ")
val menPlano = UtilsFile.readFileAsString2(archSwift)
println(menPlano)

val reporteSwiftServiceRest = new ReporteSwiftServiceRest()


val data = reporteSwiftServiceRest.obtenerReporte(menPlano)
*/

val customerReport = new DownloadReportCustomer()


val data = customerReport.downloadReport("xhtml")
Html5.parse(data.toString).openOr(<h1>No es posible ver reporte
</h1>) \\ "html" \\ "table"

45
}
// }).openOr("*" #> NodeSeq.Empty)
}

def view : CssSel = {


(for {
swiftcurso <- MenuSwift.menuView.currentValue
} yield {
val format = new java.text.SimpleDateFormat("dd/MM/yyyy")
"data-name=id" #> SHtml.text(swiftcurso.id.toString, fn =>(),
"disabled" -> "disabled") &
"data-name=estado" #> SHtml.text(swiftcurso.estado, fn =>(),
"disabled" -> "disabled") &
"data-name=plano" #> SHtml.text(swiftcurso.plano, ln => (),
"disabled" -> "disabled") &
"type=submit" #>SHtml.ajaxSubmit("Return", () => {
// ToDo - delete
// JPAUtility.mergeAndFlush(customer)
RedirectTo(MainMenu.customers2.loc.calcDefaultHref)
})
}).openOr("*" #> NodeSeq.Empty)
}

def add: CssSel = {


val swiftcurso = new Swiftcurso

val format = new java.text.SimpleDateFormat("dd/MM/yyyy")

"data-name=id" #> SHtml.text("", fn => swiftcurso.id = fn.toLong) &


"data-name=estado" #> SHtml.text("", ln => swiftcurso.estado =
ln) &
"data-name=plano" #> SHtml.email("", (email: String) =>
swiftcurso.plano = email) &
"type=submit" #>SHtml.ajaxSubmit("Guardar", () => {
JPAUtility.mergeAndFlush(swiftcurso)
RedirectTo( MainMenu.customers2.loc.calcDefaultHref)
})
}

}
Figura 26 – Snippet SWIFT – Módulo Interfaz SWIFT

46
package code.lib.menu

import code.model.Swiftcurso
import net.liftweb.common.Box
import net.liftweb.http.{S, Templates}
import net.liftweb.sitemap.Loc.{LocGroup, Template}
import net.liftweb.sitemap.Menu

import scala.xml.NodeSeq

object MenuSwift {

lazy val menuView: net.liftweb.sitemap.Menu.ParamMenuable[Swiftcurso]


= Menu.param[Swiftcurso]("Ver Swift", S ? "Ver Cliente",
c => getSwiftcurso(c), pc => pc.id.toString) /
"crud" / "swift" / "view" >> LocGroup("swiftcurso") >> Template(()
=> Templates("crud" :: "swift" :: "view" :: Nil) openOr NodeSeq.Empty)

lazy val menuViewPdf:


net.liftweb.sitemap.Menu.ParamMenuable[Swiftcurso] =
Menu.param[Swiftcurso]("Ver Swift Pdf", S ? "Ver Swift",
c => getSwiftcurso(c), pc => pc.id.toString) /
"crud" / "swift" / "viewpdf" >> LocGroup("swiftcurso") >>
Template(() => Templates("crud" :: "swift" :: "viewpdf" :: Nil) openOr
NodeSeq.Empty)

lazy val locView = menuView.toLoc

lazy val menuAdd: Menu = Menu("Agregar swift", S ? "Nuevo") / "crud"


/ "swift" / "add"

def getSwiftcurso(id: String): Box[Swiftcurso] = Swiftcurso.find(id)

}
Figura 27 – Armado de Menus – Módulo Interfaz SWIFT

47
6. RESULTADOS ALCANZADOS

En base a los objetivos del trabajo guiado, los cuales se encuentran en el alcance
del objetivo del presente curso-taller. Se obtuvieron los siguientes resultados:

 4 módulos correctamente configurados en base a SBT


 Arquitectura del proyecto plenamente identificada y 4 módulos armados en
base al estandar de SBT.
 2 módulos con conexiones a base de datos PostgreSQL
 2 módulos con conexiones a base de datos Informix
 Al menos 2 CRUDS completos (Crear, Ver, Actualizar, Eliminar)
desarrollados en Scala y Liftweb en cada módulo.
 3 módulos con reportes para ecportación a PDF y/o Excel
 1 módulo con desarrollo de pantalla basado en Wiring de Liftweb
 1 módulo con implementación de soporte para dependencias locales a
través de un archivo .jar
 4 módulos con interfaz personalizada basada en Liftweb.

Es cuanto informo, para los fines consiguientes.

Ing. Tatiana Andrea Moruno Rodriguez


Capacitadora curso-taller SBT – Scala - Liftweb
GENSO S.R.L.

48
7. ANEXOS

49

Potrebbero piacerti anche