Browse Source

Primeira versão usável

pull/10/head
Adler Neves 4 years ago
parent
commit
6228816278
  1. 10
      old/pmdsys/src/app/app.component.ts
  2. 14
      old/pmdsys/src/app/app.module.ts
  3. 4
      old/pmdsys/src/app/main.ts
  4. 8
      old/pmdsys/src/pages/about/about.ts
  5. 8
      old/pmdsys/src/pages/contact/contact.ts
  6. 8
      old/pmdsys/src/pages/home/home.ts
  7. 10
      old/pmdsys/src/pages/tabs/tabs.ts
  8. 1
      package.json
  9. 4
      src/app/app.module.ts
  10. 7
      src/app/app.scss
  11. 29
      src/pages/RelatorioEscolhe/main.html
  12. 33
      src/pages/RelatorioEscolhe/main.scss
  13. 5
      src/pages/RelatorioEscolhe/main.spec.ts
  14. 52
      src/pages/RelatorioEscolhe/main.ts
  15. 22
      src/pages/RelatorioExibe/main.spec.ts
  16. 129
      src/pages/RelatorioExibe/main.ts
  17. 2
      src/pages/generico_lista/main.html
  18. 13
      src/pages/generico_lista/main.scss
  19. 4
      src/pages/generico_lista/main.ts
  20. 20
      src/pages/generico_lista_colapsavel/main.ts
  21. 9
      src/persistence/OrmDatabase.service.ts
  22. 120
      src/providers/Relatorios.service.ts
  23. 2
      src/test.ts

10
old/pmdsys/src/app/app.component.ts

@ -1,12 +1,12 @@
import { Component } from '@angular/core';
import { Platform } from 'ionic-angular';
import { StatusBar, Splashscreen } from 'ionic-native';
import { Component } from "@angular/core";
import { Platform } from "ionic-angular";
import { StatusBar, Splashscreen } from "ionic-native";
import { TabsPage } from '../pages/tabs/tabs';
import { TabsPage } from "../pages/tabs/tabs";
@Component({
templateUrl: 'app.html'
templateUrl: "app.html"
})
export class MyApp {
rootPage = TabsPage;

14
old/pmdsys/src/app/app.module.ts

@ -1,10 +1,10 @@
import { NgModule, ErrorHandler } from '@angular/core';
import { IonicApp, IonicModule, IonicErrorHandler } from 'ionic-angular';
import { MyApp } from './app.component';
import { AboutPage } from '../pages/about/about';
import { ContactPage } from '../pages/contact/contact';
import { HomePage } from '../pages/home/home';
import { TabsPage } from '../pages/tabs/tabs';
import { NgModule, ErrorHandler } from "@angular/core";
import { IonicApp, IonicModule, IonicErrorHandler } from "ionic-angular";
import { MyApp } from "./app.component";
import { AboutPage } from "../pages/about/about";
import { ContactPage } from "../pages/contact/contact";
import { HomePage } from "../pages/home/home";
import { TabsPage } from "../pages/tabs/tabs";
@NgModule({
declarations: [

4
old/pmdsys/src/app/main.ts

@ -1,5 +1,5 @@
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { platformBrowserDynamic } from "@angular/platform-browser-dynamic";
import { AppModule } from './app.module';
import { AppModule } from "./app.module";
platformBrowserDynamic().bootstrapModule(AppModule);

8
old/pmdsys/src/pages/about/about.ts

@ -1,10 +1,10 @@
import { Component } from '@angular/core';
import { Component } from "@angular/core";
import { NavController } from 'ionic-angular';
import { NavController } from "ionic-angular";
@Component({
selector: 'page-about',
templateUrl: 'about.html'
selector: "page-about",
templateUrl: "about.html"
})
export class AboutPage {

8
old/pmdsys/src/pages/contact/contact.ts

@ -1,10 +1,10 @@
import { Component } from '@angular/core';
import { Component } from "@angular/core";
import { NavController } from 'ionic-angular';
import { NavController } from "ionic-angular";
@Component({
selector: 'page-contact',
templateUrl: 'contact.html'
selector: "page-contact",
templateUrl: "contact.html"
})
export class ContactPage {

8
old/pmdsys/src/pages/home/home.ts

@ -1,10 +1,10 @@
import { Component } from '@angular/core';
import { Component } from "@angular/core";
import { NavController } from 'ionic-angular';
import { NavController } from "ionic-angular";
@Component({
selector: 'page-home',
templateUrl: 'home.html'
selector: "page-home",
templateUrl: "home.html"
})
export class HomePage {

10
old/pmdsys/src/pages/tabs/tabs.ts

@ -1,11 +1,11 @@
import { Component } from '@angular/core';
import { Component } from "@angular/core";
import { HomePage } from '../home/home';
import { AboutPage } from '../about/about';
import { ContactPage } from '../contact/contact';
import { HomePage } from "../home/home";
import { AboutPage } from "../about/about";
import { ContactPage } from "../contact/contact";
@Component({
templateUrl: 'tabs.html'
templateUrl: "tabs.html"
})
export class TabsPage {
// this tells the tabs component which Pages

1
package.json

@ -31,6 +31,7 @@
"@ionic-native/toast": "^3.6.1",
"@ionic/storage": "^2.0.1",
"@types/node": "^7.0.18",
"chart.js": "^2.6.0",
"ionic-angular": "^3.2.1",
"ionic-orm": "0.0.5",
"ionic-typeorm": "^0.0.15",

4
src/app/app.module.ts

@ -24,6 +24,7 @@ import { PageFormItensCompra } from '../pages/FormItensCompra/main';
import { PageListaPrecos } from '../pages/ListaPrecos/main';
import { PageFormPrecos } from '../pages/FormPrecos/main';
import { PageRelatorioEscolhe } from '../pages/RelatorioEscolhe/main';
import { PageRelatorioExibe } from '../pages/RelatorioExibe/main';
import { OrmDatabase } from '../persistence/OrmDatabase.service';
import { Relatorios } from '../providers/Relatorios.service';
@ -51,6 +52,7 @@ import { CrudSupermercado } from '../providers/CrudSupermercado.service';
PageListaPrecos,
PageFormPrecos,
PageRelatorioEscolhe,
PageRelatorioExibe,
],
imports: [
BrowserModule,
@ -76,6 +78,7 @@ import { CrudSupermercado } from '../providers/CrudSupermercado.service';
PageListaPrecos,
PageFormPrecos,
PageRelatorioEscolhe,
PageRelatorioExibe,
],
providers: [
StatusBar,
@ -91,6 +94,7 @@ import { CrudSupermercado } from '../providers/CrudSupermercado.service';
CrudNecessidade,
CrudPlanejamento,
CrudSupermercado,
PageRelatorioExibe,
]
})
export class AppModule { }

7
src/app/app.scss

@ -14,3 +14,10 @@
// To declare rules for a specific mode, create a child rule
// for the .md, .ios, or .wp mode classes. The mode class is
// automatically applied to the <body> element in the app.
.deleteToast{
color: #cc3333 !important;
}
.cancelToast{
color: #387ef5 !important;
}

29
src/pages/RelatorioEscolhe/main.html

@ -1,21 +1,28 @@
<ion-header>
<ion-navbar color="logotipoCesta">
<ion-title>
Relatorios
Ir às compras
</ion-title>
</ion-navbar>
</ion-header>
<ion-content>
<ion-list>
<ion-item>
Item 1
</ion-item>
<ion-item>
Item 2
</ion-item>
<ion-item>
Item 3
</ion-item>
<ion-list class="noHSpace">
<ion-list ion-item class="noHSpace">
<ion-item class="fundoEspecial">
...no menor preço...
</ion-item>
<ion-list ion-item>
<button ion-item (click)="menorPrecoTodos()">
...visitando todos os supermercados
</button>
<button ion-item (click)="menorPrecoUm()">
...visitando um único supermercado
</button>
<button ion-item (click)="menorPrecoMedio()">
...médio
</button>
</ion-list>
</ion-list>
</ion-list>
</ion-content>

33
src/pages/RelatorioEscolhe/main.scss

@ -1,24 +1,17 @@
page-inicio {
.btnhome {
padding:5%;
.fundoEspecial{
background: color($colors, logotipoFundo, secondary);
background: linear-gradient(to right, color($colors, logotipoFundo, secondary), $background-color);
border-width: 1pt;
border-style: solid;
border-image: linear-gradient(to right, color($colors, logotipoFundoEscuroEscuro, secondary), $background-color) 100% 1;
border-left-style: none;
border-right-style: none;
}
.h1home{
font-size:16vw;
text-align: center;
}
.h3home{
text-align: center;
margin-bottom: 10vh;
}
.cont{
display: flex;
align-content: space-around;
align-items: center;
width: 100%;
height: 100%;
}
.el{
display: block;
width: 100%;
.noHSpace{
padding-left: 0px !important;
padding-right: 0px !important;
margin-left: 0px !important;
margin-right: 0px !important;
}
}

5
src/pages/RelatorioEscolhe/main.spec.ts

@ -20,8 +20,5 @@ describe('Pages: Relatorio: Escolhe', () => {
it('should create the start page', async(() => {
expect(instance).toBeTruthy();
}));
it('should have a clickable button to another page', async(() => {
expect(instance.openPage()).toBeTruthy();
}));
});

52
src/pages/RelatorioEscolhe/main.ts

@ -1,15 +1,59 @@
import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';
import { NavParams } from 'ionic-angular';
import { Consulta } from '../../entities/Consulta';
import { Planejamento } from '../../entities/Planejamento';
import { Relatorios } from '../../providers/Relatorios.service';
import { PageListaCompras } from '../ListaCompras/main'
import { PageRelatorioExibe } from '../RelatorioExibe/main'
@Component({
selector: 'page-inicio',
templateUrl: 'main.html'
})
export class PageRelatorioEscolhe {
constructor(public navCtrl: NavController){}
openPage() {
return this.navCtrl.setRoot(PageListaCompras);
constructor(
public navCtrl: NavController,
public navParams: NavParams,
public relatorioService: Relatorios,
){
this.planejamento = this.navParams.get('sujeito')
}
planejamento: Planejamento;
menorPrecoMedio(){
this.relatorioService.menorPrecoMedio(
this.planejamento
).then(
(consultas:Consulta[]) => {
this.navCtrl.push(PageRelatorioExibe,{
titulo: 'O menor preço médio',
consultas: consultas,
})
}
)
}
menorPrecoUm(){
this.relatorioService.menorPrecoEmUmSupermercado(
this.planejamento
).then(
(consultas:Consulta[]) => {
this.navCtrl.push(PageRelatorioExibe,{
titulo: 'O mais barato',
consultas: consultas,
})
}
)
}
menorPrecoTodos(){
this.relatorioService.menorPrecoEmTodosSupermercados(
this.planejamento
).then(
(consultas:Consulta[]) => {
this.navCtrl.push(PageRelatorioExibe,{
titulo: 'O menor orçamento',
consultas: consultas,
})
}
)
}
}

22
src/pages/RelatorioExibe/main.spec.ts

@ -0,0 +1,22 @@
import { ComponentFixture, async } from '@angular/core/testing';
import { TestUtils } from '../../test';
import { PageRelatorioExibe } from './main';
let fixture: ComponentFixture<PageRelatorioExibe> = null;
let instance: any = null;
declare var describe: any;
declare var it: any;
declare var expect: any;
declare var beforeEach: any;
describe('Pages: Relatorios: Exibe', () => {
beforeEach(async(() => TestUtils.beforeEachCompiler([PageRelatorioExibe]).then(compiled => {
fixture = compiled.fixture;
instance = compiled.instance;
})));
it('should create the page', async(() => {
expect(instance).toBeTruthy();
}));
});

129
src/pages/RelatorioExibe/main.ts

@ -0,0 +1,129 @@
import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';
import { NavParams } from 'ionic-angular';
import { ActionSheetController } from 'ionic-angular';
import { AlertController } from 'ionic-angular';
import { LoadingController } from 'ionic-angular';
import { Toast } from "@ionic-native/toast";
import { Consulta } from '../../entities/Consulta';
import { Necessidade } from '../../entities/Necessidade';
import { CrudProduto } from '../../providers/CrudProduto.service';
import { CrudConsulta } from '../../providers/CrudConsulta.service';
import { CrudNecessidade } from '../../providers/CrudNecessidade.service';
import { PageLista } from '../generico_lista/main';
@Component({
selector: 'page-lista',
templateUrl: '../generico_lista/main.html'
})
export class PageRelatorioExibe extends PageLista<Consulta> {
constructor(
public navCtrl: NavController,
public navParams: NavParams,
public actionSheetCtrl: ActionSheetController,
public alert: AlertController,
public toast: Toast,
public loadingCtrl: LoadingController,
public consultaCrud: CrudConsulta,
public necessidadeCrud: CrudNecessidade,
public produtoCrud: CrudProduto,
){
super(
navCtrl,
actionSheetCtrl,
alert,
toast,
loadingCtrl,
consultaCrud
);
this.contextoExibe['excluir'] = false
this.contextoExibe['editar'] = false
this.textos['titulo'] = this.navParams.get('titulo')
this.items = this.navParams.get('consultas')
}
refreshList(){
this.mostraCarregando();
this.consultaCrud.recarregarAlguns(this.items).then( consultas => {
this.items = consultas
let necessidades: Necessidade[] = []
for(let consulta of consultas){
necessidades.push(consulta.necessidade)
}
this.necessidadeCrud.recarregarAlguns(necessidades).then(necessidades => {
this.produtoCrud.listar().then(produtos => {
for(let necessidade in necessidades){
for(let produto of produtos){
if(
necessidades[necessidade].produto
&&
necessidades[necessidade].produto.id == produto.id
){
necessidades[necessidade].produto = produto
}
}
}
for(let consulta in consultas){
for(let necessidade of necessidades){
if(
consultas[consulta].necessidade
&&
consultas[consulta].necessidade.id === necessidade.id
){
consultas[consulta].necessidade = necessidade
break
}
}
}
this.items = this.ordenaExibicao(consultas);
this.escondeCarregando()
})
});
})
}
public items: Consulta[] = new Array();
public icone: string = "arrow-dropright";
public textos: object = {
"titulo": "",
"adicionar": "",
"entidadeGenero": "",
"artigoentidade": "",
"capitalEntidade": "",
};
public texto(item: Consulta):string{
return ''+
((item.necessidade || {produto:null}).produto || {nome: '<deletado>'}).nome
+' ('
+((item.necessidade || {quantidade:'???'}).quantidade)
+' '
+((((item.necessidade || {produto:null}).produto || {unidadeMedida:null}).unidadeMedida || {nome:'iten'}).nome)
+(((item.necessidade || {quantidade:0}).quantidade)>1 ? 's' : '')
+')';
};
public posTexto(item: Consulta):string{ return item.supermercado.nome; };
public classesPara(item: Consulta):string{
return item.necessidade.satisfeita?'tickado':''
}
public add():void{return}
public abreEdicao(item: Consulta):void{return}
public click(item: Consulta):void{
item.necessidade.satisfeita = !item.necessidade.satisfeita
this.necessidadeCrud.recarregarUm(item.necessidade).then(necessidade => {
necessidade.satisfeita = item.necessidade.satisfeita
this.necessidadeCrud.salvar(necessidade)
})
};
public ordenaExibicao(items: Consulta[]):Consulta[]{
items.sort((a, b) => {
if (a.supermercado.nome > b.supermercado.nome) { return 1; }
if (a.supermercado.nome < b.supermercado.nome) { return -1; }
if (a.necessidade.produto.nome > b.necessidade.produto.nome) { return 1; }
if (a.necessidade.produto.nome < b.necessidade.produto.nome) { return -1; }
if (a.preco > b.preco) { return 1; }
if (a.preco < b.preco) { return -1; }
if (a.necessidade.id > b.necessidade.id) { return 1; }
if (a.necessidade.id < b.necessidade.id) { return -1; }
return 0;
})
return items;
}
}

2
src/pages/generico_lista/main.html

@ -20,7 +20,7 @@
{{ posTexto(item) }}
</span>
&nbsp;
<span>
<span class="text-main {{ classesPara(item) }}">
{{ texto(item) }}
</span>
</button>

13
src/pages/generico_lista/main.scss

@ -6,10 +6,11 @@ page-lista {
.text-muted{
opacity: 0.5;
}
}
.deleteToast{
color: #cc3333 !important;
}
.cancelToast{
color: #387ef5 !important;
.text-main{
transition: all 200ms ease-in-out;
}
.tickado{
text-decoration: line-through;
opacity: 0.5;
}
}

4
src/pages/generico_lista/main.ts

@ -39,6 +39,7 @@ export abstract class PageLista<T> {
public abstract posTexto(item: T):string;
public abstract abreEdicao(item: T):void;
public abstract ordenaExibicao(items: T[]):T[];
public classesPara(item: T):string{return ''}
public add():void{
this.abreEdicao(this.crud.criar());
};
@ -105,6 +106,9 @@ export abstract class PageLista<T> {
if(this.contextoExibe['editar']){ botoes.push(botaoEditar) };
for(let personalizado of this.contextoExibe['personalizado']){ botoes.push(personalizado) };
if(this.contextoExibe['excluir']){ botoes.push(botaoExcluir) };
if(botoes.length == 0){
return
}
botoes.push(botaoCancelar)
let actionSheet = this.actionSheetCtrl.create({
title: 'Escolha uma das opções abaixo:',

20
src/pages/generico_lista_colapsavel/main.ts

@ -77,30 +77,14 @@ export abstract class PageListacolapsavel<E,I>{
public items: Array<E>;
public initialLoad: Loading;
public abstract textos: object;
// public abstract iconeE: string;
public abstract iconeI: string;
public abstract itemField: string;
public abstract textoExterno(item: E):string;
public abstract textoInterno(item: I):string;
public abstract posTextoExterno(item: E):string;
public abstract posTextoInterno(item: I):string;
// public abstract abreEdicaoExterno(item: E):void;
// public abstract abreEdicaoInterno(item: I):void;
public abstract ordenaExibicaoExterno(items: E[]):E[];
public abstract ordenaExibicaoInterno(items: I[]):I[];
// public addE():void{
// this.abreEdicaoExterno(this.crudExterno.criar());
// };
// public addI():void{
// this.abreEdicaoInterno(this.crudInterno.criar());
// };
// public getClicadoExterno():E{
// return this.clicadoExterno;
// }
// public clicadoExterno: E;
// public clickExterno(item: E):void{
// return;
// };
public collapsed: number[] = [];
public collapse(item: E):void{
if(this.isCollapsed(item)){
@ -112,10 +96,6 @@ export abstract class PageListacolapsavel<E,I>{
public isCollapsed(item: E):boolean{
return this.collapsed.indexOf(item['id']) != -1
}
// public getClicadoInterno():I{
// return this.clicadoInterno;
// }
// public clicadoInterno: I;
public abstract clickInterno(item: I):void;
public getSubitems(item: E):I[]{
return item[this.itemField]

9
src/persistence/OrmDatabase.service.ts

@ -79,4 +79,13 @@ export class OrmDatabase{
}
})
}
dropDatabase(){
return new Promise<void>((resolve, reject) => {
this.getConnection().then(connection =>{
connection.dropDatabase().then(()=>{
connection.close().then(resolve,reject)
}, reject)
},reject)
})
}
}

120
src/providers/Relatorios.service.ts

@ -1,24 +1,130 @@
import { Injectable } from '@angular/core';
import { OrmDatabase } from '../persistence/OrmDatabase.service';
import { CrudConsulta } from './CrudConsulta.service';
import { CrudSupermercado } from './CrudSupermercado.service';
import { CrudNecessidade } from './CrudNecessidade.service';
import { CrudPlanejamento } from './CrudPlanejamento.service';
import { Planejamento } from '../entities/Planejamento';
import { Supermercado } from '../entities/Supermercado';
import { Necessidade } from '../entities/Necessidade';
import { Consulta } from '../entities/Consulta';
@Injectable()
export class Relatorios{
constructor(
public ormDatabase: OrmDatabase
public ormDatabase: OrmDatabase,
public consultaCrud: CrudConsulta,
public supermercadoCrud: CrudSupermercado,
public necessidadeCrud: CrudNecessidade,
public planejamentoCrud: CrudPlanejamento,
){
return
}
menorPrecoMedio(planejamento: Planejamento):Promise<Supermercado>{
return
_menorUm(planejamento: Planejamento, orderBy: string):Promise<Consulta[]>{
return new Promise<Consulta[]>((resolve, reject) => {
this.planejamentoCrud.recarregarUm(planejamento).then(planejamento => {
this.ormDatabase.getConnection().then(connection =>{
this.consultaCrud._seleciona(connection.getRepository(Consulta))
.leftJoinAndSelect("necessidade.planejamento", "planejamento")
.where("tbl.preco <> 0")
.andWhere("planejamento.id = "+planejamento.id)
.addGroupBy("tbl.supermercado")
.orderBy(orderBy)
.having("SUM(tbl.preco) > 0")
.getMany()
.then((consultas:Consulta[])=>{
/* nota: esta consulta apenas contem os supermercados com o
/* preco medio em ordem crescente, foi decisao de codificacao
/* visando melhorar a performance desta consulta, que esta
/* O(nlogn), e seria pelo menos O(n2) caso feito da outra
/* forma; em contrapartida, virao mais queries a seguir,
/* menos complexas.
/**/
if(consultas.length <= 0){
reject('Preços não foram pesquisados')
}else{
let supermercado: Supermercado = consultas[0].supermercado
this.necessidadeCrud.recarregarAlguns(planejamento.necessidades)
.then(
(necessidades: Necessidade[]) => {
let consultasARecarregar: Consulta[] = []
for(let necessidade of necessidades){
for(let consulta of necessidade.consultas){
consultasARecarregar.push(consulta)
}
}
this.consultaCrud.recarregarAlguns(consultasARecarregar).then(
(consultas:Consulta[])=>{
let selecionadas: Consulta[] = []
for(let consulta of consultas){
if(supermercado.id == consulta.supermercado.id){
selecionadas.push(consulta)
}
}
resolve(selecionadas)
},reject
)
},reject
)
}
},reject)
},reject)
})
})
}
menorPrecoEmUmSupermercado(planejamento: Planejamento):Promise<Array<Consulta>>{
return
menorPrecoMedio(planejamento: Planejamento):Promise<Consulta[]>{
return this._menorUm(planejamento, "SUM(tbl.preco)/COUNT(*)")
}
menorPrecoEmTodosSupermercados(planejamento: Planejamento):Promise<Array<Consulta>>{
return
menorPrecoEmUmSupermercado(planejamento: Planejamento):Promise<Consulta[]>{
return this._menorUm(planejamento, "SUM(tbl.preco*necessidade.quantidade)")
}
menorPrecoEmTodosSupermercados(planejamento: Planejamento):Promise<Consulta[]>{
return new Promise<Consulta[]>((resolve, reject) => {
this.planejamentoCrud.recarregarUm(planejamento).then((planejamento:Planejamento) => {
this.necessidadeCrud.recarregarAlguns(planejamento.necessidades).then((necessidades:Necessidade[])=>{
let consultasARecarregar: Consulta[] = []
for(let necessidade of necessidades){
for(let consulta of necessidade.consultas){
consultasARecarregar.push(consulta)
}
}
this.consultaCrud.recarregarAlguns(consultasARecarregar).then((consultas:Consulta[])=>{
let menorPreco: {[id:number]: {consulta:Consulta,preco:number};} = {}
for(let necessidade of necessidades){
menorPreco[necessidade.id] = {
consulta: null,
preco: 0,
}
}
for(let consulta of consultas){
if(
menorPreco[consulta.necessidade.id].consulta==null
||
(
menorPreco[consulta.necessidade.id].preco > consulta.preco * consulta.necessidade.quantidade
&&
consulta.preco > 0
)
){
menorPreco[consulta.necessidade.id].consulta = consulta
menorPreco[consulta.necessidade.id].preco = consulta.preco * consulta.necessidade.quantidade
}
}
let comprar: Consulta[] = []
for(let necessidade of necessidades){
comprar.push(menorPreco[necessidade.id].consulta)
if(menorPreco[necessidade.id].consulta === null){
reject('Preços não foram pesquisados')
return
}
}
resolve(comprar)
},reject)
},reject)
},reject)
})
}
}

2
src/test.ts

@ -26,6 +26,7 @@ import { CrudNecessidade } from './providers/CrudNecessidade.service';
import { CrudPlanejamento } from './providers/CrudPlanejamento.service';
import { CrudSupermercado } from './providers/CrudSupermercado.service';
import { OrmDatabase } from './persistence/OrmDatabase.service'
import { Relatorios } from './providers/Relatorios.service';
// Unfortunately there's no typing for the `__karma__` variable. Just declare it as any.
declare var __karma__: any;
@ -90,6 +91,7 @@ export class TestUtils {
CrudNecessidade,
CrudPlanejamento,
CrudSupermercado,
Relatorios,
],
imports: [
FormsModule,

Loading…
Cancel
Save