Proyecto TPV. Este proyecto es un apoyo docente de la asignatura. Es una aplicación completa realizada con un Front-end con Angular, dos Back-ends con Spring y un Back-end con Python. El Back-end-user se desarrolla con programación síncrona y Postgresql. El Back-end-core se realiza con programación reactiva y MongoDB. El Back-end-customer-support con programación síncrona y MongoDB
Java
Maven
Spring-Boot
Reactor
Python
Angular
MondoDB
JPA
SQL
GitHub
Travis-CI
Sonarcloud
Better Code Hub
Heroku
Proyecto | GitHub - CI | Sonarcloud |
---|---|---|
Front-end-angular | ||
Back-end-user | ||
Back-end-core | ||
Back-end-customer-support |
- Clonar repositorios, mediante consola:
- betca-tpv-angular
> cd <folder path>
> git clone https://github.com/miw-upm/betca-tpv-angular
> cd betca-tpv-angular
betca-tpv-angular> npm install
- betca-tpv-user
> cd <folder path>
> git clone https://github.com/miw-upm/betca-tpv-user
- betca-tpv-core
> cd <folder path>
> git clone https://github.com/miw-upm/betca-tpv-core
- betca-tpv-customer-support
> cd <folder path>
> git clone https://github.com/miw-upm/betca-tpv-customer-support
> cd betca-tpv-customer-support
> venv\Scripts\activate.bat
(venv) > pip install -r requirements.txt
- Importar el proyecto
betca-tpv-angular
mediante WebStorm- Open, y seleccionar la carpeta del proyecto.
- Importar los proyectos
betca-tpv-user
&betca-tpv-core
mediante IntelliJ- Import Project, y seleccionar la carpeta del proyecto.
- Marcar Create Project from external model, elegir Maven.
- Next … Finish.
- Importar el proyecto
betca-tpv-customer-support
mediante PyCharm- Open, y seleccionar la carpeta del proyecto.
- Ejecución
- Ejecución de test: se utiliza MongoDB embebido y H2 embebido
- Ejecución en local:
- BBDD. Se debe tener arrancado el motor de MongoDB:
mongodb://localhost:27017/tpv
&mongodb://localhost:27017/tpv2
, y el motor de Postgresql:spring.datasource.url=jdbc:postgresql://localhost:5432/tpv
- Spring. Ejecutar mediante linea de comando en ambos proyectos:
> mvn clean spring-boot:run
- Python. Ejecutar mediante linea de comando:
> uvicorn src.main:app --reload
- Angular. Ejecutar mediante linea de comand:
> ng serve
- BBDD. Se debe tener arrancado el motor de MongoDB:
Este proyecto es la práctica TPV desarrollada de forma colaborativa por todos los alumnos. Se parte de la versión
core
, ya implementada, y se pretende ampliar con un conjunto de mejoras. Un Terminal Punto de Venta es un sistema informático que gestiona el proceso de venta mediante una interfaz accesible para los vendedores o compradores. Permite la creación e impresión del recibo ticket o factura de venta —con los detalles de las referencias y precios— de los artículos vendidos, actualiza los cambios en el nivel de existencias de mercancías (STOCK) en la base de datos... Además tiene la parte de venta on-line.
Se plantea en dos procesos:
En primer lugar, se debe conseguir un API Key o token de tipo Json Web Token (JWT), accediendo al end-point POST /users/token
mediante Basic Auth. Para ello se envía en la cabecera las credenciales (Authorization).
Un token JWT está formado por tres partes:
- Header. Se define el tipo.
- Payload. Se establecen los datos que queramos que queden almacenados en el token, como el proveedor, el usuario, fecha de expiración… y los privilegios, o en nuestro caso, el rol del usuario. Esta información va codificada y firmada, pero no encriptada, y por lo tanto es una información pública y visible.
- Signature. Es la firma, que depende de una clave secreta, para saber si el contenido de Payload es válido.
Authorization = Basic <user>:<pass>Base64
Authorization = Bearer <header>Base64 .<payload>Base64 .<signature>Base64
Justo abajo os presentamos un token válido:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYmYiOjE2MDc0NDk2NzYsInJvbGUiOiJBRE1JTiIsImlzcyI6Im1pdy5qd3QuaXNzdWVyIiwibmFtZSI6ImFkbWluIiwiZXhwIjoxNjA3NDUzMjc2LCJpYXQiOjE2MDc0NDk2NzYsInVzZXIiOiI2In0.iFeIfrslgdwA53dv7-vg27GT7bcEINnqSKJsQJNB4rc
Tenéis más documentación de JWT (https://jwt.io).
Para su tratamiento utilizaremos la librerías de auth0 (https://auth0.com) para Angular.
Se han desarrollado dos clases, AuthService, que nos realiza el login, y nos facilita métodos para conocer el alcance de privilegios del usuario, además de guardar el token. Y también tenemos TokenInterceptor, que añade automáticamente en cabecera el token, siempre que exista. Ambas clases se encuentran en el módulo core.
Hemos decidido realizar carga perezosa de los módulos, y para ello se delega al módulo de rutas la carga de los sub-módulos, en el momento que el usuario elige una sub-ruta.
Para la seguridad, se ha implementado uno genérico (RoleGuardService), se configura en el propio enrutamiento los roles permitidos, y este a través de servicio de autenticación (AuthService) comprueba el rol actual del usuario, remitiendo a la página principal si este no tuviera el rol requerido.
const routes: Routes = [
{path: '', pathMatch: 'full', redirectTo: 'home'},
{path: 'home', loadChildren: () => import('./home/home.module').then(module => module.HomeModule)},
{path: 'shop', loadChildren: () => import('./shop/shop.module').then(module => module.ShopModule)}
// {path: 'home', component: HomeComponent}, // eager load
// {path: 'shop', component: ShopComponent} // eager load
];
@NgModule({imports: [RouterModule.forRoot(routes)],exports: [RouterModule]})
export class AppRoutingModule {}
const routes: Routes = [
{path: '', component: HomeComponent, children: []}
];
@NgModule({imports: [RouterModule.forChild(routes)],exports: [RouterModule]})
export class HomeRoutingModule {}
const routes: Routes = [
{
path: '', // 'shop' to forRoot
component: ShopComponent,
canActivate: [RoleGuardService],
data: {roles: [Role.ADMIN, Role.MANAGER, Role.OPERATOR]},
children: [ // or path: shop/articles
{path: 'articles', component: ArticlesComponent},
{path: 'cashier-closed', component: CashierClosedComponent},
{path: 'cashier-opened', component: CashierOpenedComponent},
{path: 'providers', component: ProvidersComponent},
{path: 'tickets', component: TicketsComponent},
]
}
];
@NgModule({imports: [RouterModule.forChild(routes)], exports: [RouterModule]})
export class ShopRoutingModule {}
<p><button mat-raised-button (click)=requestSync() >Sync </button> {{sync}}</p>
<p><button mat-raised-button (click)=requestAsync()>Async</button> {{asyn | async}}</p>
export class InputOverviewExample {
sync: string;
asyn: Observable<string>;
requestSync(): void {
this.serviceMock()
.subscribe(item => this.sync = item);
}
requestAsync(): void {
this.asyn = this.serviceMock();
}
serviceMock(): Observable<string> {
return of('Result');
}
}
<app-crud (create)="create()" (read)="read($event)" (update)="update($event)"
[data]="articles" [deleteAction]="false" [title]="title"></app-crud>
export class ArticlesComponent {
title = 'Articles management';
articles = of([]);
create(): void {
this.dialog.open(ArticleCreationUpdatingDialogComponent);
}
read(article: Article): void {
this.dialog.open(ReadDetailDialogComponent, {
data: {
title: 'Article Details',
object: this.articleService.read(article.barcode)
}
});
}
update(article: Article): void {
this.articleService.read(article.barcode)
.subscribe(fullArticle => this.dialog.open(ArticleCreationUpdatingDialogComponent, {data: fullArticle}));
}
}
-
Desinstalar node & borrado de carpetas, si procede:
- C:\Users*\AppData\Roaming\npm
- C:\Users*\AppData\Roaming\npm-cache
-
Instalar Node, todo estándar
- node --version ?
v14.15.0
- npm –version ?
6.14.8
- npm list ?muestra todas las dependencias instaladas
- npm list <dependence> ?muestra la dependencia especificada
- npm update –g
- node --version ?
-
Instalar Angular CLI
- npm install -g @angular/cli
- ng –-version ?
11.0.1
-
Crear una nueva aplicación
- ng new <app>
-
Ejecutar aplicación:
- cd <app>
- ng serve
- Navegador: http://localhost:4200/
-
Instalar express:
- npm i express ?i:install
- npm list express ?
4.17.1
- Crear el fichero
server.js
- ng build --prod
- node server.js ?arrancar sobre express
-
Instalar Material + Flex
- ng add @angular/material ?(Indigo/Pink, Yes & Yes)
- npm i @angular/flex-layout
- npm list @angular/material ?
11.0.0
- npm list @angular/flex-layout ?
11.0.0-beta.33
-
Instalar Jwt
- npm i @auth0/angular-jwt
- npm list @auth0/angular-jwt ?
5.0.1
Otros comandos
>ng serve
for a dev server. Navigate tohttp://localhost:4200/
. The app will automatically reload if you change any of the source files.>ng build
to build the project. The build artifacts will be stored in thedist/
directory. Use the--prod
flag for a production build.>ng test
to execute the unit tests via Karma.>ng e2e
to execute the end-to-end tests via Protractor.>ng help
or go check out the Angular CLI Overview and Command Reference page.
{
"name": "betca-tpv-angular",
"version": "4.1.0-SNAPSHOT",
}
~: versión mas cercana posible, ^: versión compatible mas alta
En el fichero tsconfig
, habilitar las opciones de compilación siguientes, esto nos permite importar valores de los ficheros *.json.
{
"compilerOptions": {
"resolveJsonModule": true
}
}
enviroments.ts
import {name, version} from '../../package.json';
export const environment = {
production: false,
NAME: name,
VERSION: version,
REST_USER: 'http://localhost:8081',
REST_CORE: 'http://localhost:8082'
};
enviroments.prod.ts
import {name, version} from '../../package.json';
export const environment = {
production: true,
NAME: name,
VERSION: version,
REST_USER: 'https://betca-tpv-user.herokuapp.com',
REST_CORE: 'https://betca-tpv-core.herokuapp.com'
En el fichero tsconfig
, habilitar las opciones de compilación:
{
"compilerOptions": {
"baseUrl": "src",
"paths": {
"@env": ["environments/environment"],
"@shared/*": ["app/shared/*"],
"@core/*": ["app/core/*"]
}
}
}
{
"scripts": {
"heroku-postbuild": "ng build --prod",
"build-prod": "ng build --prod",
"start": "node server.js"
}
}
Se establecen los workflows en la carpeta: .github/workflows/*.yml
Conexión con Sonarcloud:
-
Se debe crear el proyecto en sonarcloud:
Administration/Projects Management
, botónCreate Project
. -
Configurar la rama por defecto, renombrar
master
si esta no es la rama por defecto:Administración/Branches and Pull Requests
. Renombrar laslong living branch: (master|develop|release-).*
-
Se deben establecer la contraseña:
secrets.SONAR_TOKEN
en en proyecto de GitHub,settings/Secrets
ParaSonarcloud
, se debe crear el fichero:sonar-project.properties
.
Conexión con Heroku:
- Crear la aplicación en Heroku.
- Se deben establecer la contraseña:
secrets.HEROKU_API_KEY
en en proyecto de GitHub. - Deben existir los scripts para construcción y arranque con
express
:
{
"scripts": {
"heroku-postbuild": "ng build --prod",
"start": "node server.js"
}
}