diff --git a/old/pmdsys/src/app/app.component.ts b/old/pmdsys/src/app/app.component.ts index f410c64..e2de314 100644 --- a/old/pmdsys/src/app/app.component.ts +++ b/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; diff --git a/old/pmdsys/src/app/app.module.ts b/old/pmdsys/src/app/app.module.ts index 3064473..5baae09 100644 --- a/old/pmdsys/src/app/app.module.ts +++ b/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: [ diff --git a/old/pmdsys/src/app/main.ts b/old/pmdsys/src/app/main.ts index 6af7a5b..9c5532a 100644 --- a/old/pmdsys/src/app/main.ts +++ b/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); diff --git a/old/pmdsys/src/pages/about/about.ts b/old/pmdsys/src/pages/about/about.ts index 1b4c5ad..0c46cff 100644 --- a/old/pmdsys/src/pages/about/about.ts +++ b/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 { diff --git a/old/pmdsys/src/pages/contact/contact.ts b/old/pmdsys/src/pages/contact/contact.ts index a344720..a5c40de 100644 --- a/old/pmdsys/src/pages/contact/contact.ts +++ b/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 { diff --git a/old/pmdsys/src/pages/home/home.ts b/old/pmdsys/src/pages/home/home.ts index e9f7e6a..5d93db4 100644 --- a/old/pmdsys/src/pages/home/home.ts +++ b/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 { diff --git a/old/pmdsys/src/pages/tabs/tabs.ts b/old/pmdsys/src/pages/tabs/tabs.ts index a95cdf4..032c8d0 100644 --- a/old/pmdsys/src/pages/tabs/tabs.ts +++ b/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 diff --git a/package.json b/package.json index 4a9185a..d0fcfc8 100644 --- a/package.json +++ b/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", diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 9f45ab8..1957da9 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -21,6 +21,10 @@ import { PageListaCompras } from '../pages/ListaCompras/main'; import { PageFormCompras } from '../pages/FormCompras/main'; import { PageListaItensCompra } from '../pages/ListaItensCompra/main'; 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'; @@ -45,6 +49,10 @@ import { CrudSupermercado } from '../providers/CrudSupermercado.service'; PageFormCompras, PageListaItensCompra, PageFormItensCompra, + PageListaPrecos, + PageFormPrecos, + PageRelatorioEscolhe, + PageRelatorioExibe, ], imports: [ BrowserModule, @@ -67,6 +75,10 @@ import { CrudSupermercado } from '../providers/CrudSupermercado.service'; PageFormCompras, PageListaItensCompra, PageFormItensCompra, + PageListaPrecos, + PageFormPrecos, + PageRelatorioEscolhe, + PageRelatorioExibe, ], providers: [ StatusBar, @@ -82,6 +94,7 @@ import { CrudSupermercado } from '../providers/CrudSupermercado.service'; CrudNecessidade, CrudPlanejamento, CrudSupermercado, + PageRelatorioExibe, ] }) export class AppModule { } diff --git a/src/app/app.scss b/src/app/app.scss index a967d6f..bf7ab2c 100644 --- a/src/app/app.scss +++ b/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 element in the app. + +.deleteToast{ + color: #cc3333 !important; +} +.cancelToast{ + color: #387ef5 !important; +} diff --git a/src/entities/_entidadeAbstrata.ts b/src/entities/_entidadeAbstrata.ts index 357bac5..c4d19f9 100644 --- a/src/entities/_entidadeAbstrata.ts +++ b/src/entities/_entidadeAbstrata.ts @@ -1 +1,3 @@ -export abstract class EntidadeAbstrata {} +export abstract class EntidadeAbstrata { + abstract id: number; +} diff --git a/src/pages/FormPrecos/main.spec.ts b/src/pages/FormPrecos/main.spec.ts new file mode 100644 index 0000000..293864c --- /dev/null +++ b/src/pages/FormPrecos/main.spec.ts @@ -0,0 +1,22 @@ +import { ComponentFixture, async } from '@angular/core/testing'; +import { TestUtils } from '../../test'; +import { PageFormPrecos } from './main'; + +let fixture: ComponentFixture = null; +let instance: any = null; + +declare var describe: any; +declare var it: any; +declare var expect: any; +declare var beforeEach: any; + +describe('Pages: Forms: Precos', () => { + beforeEach(async(() => TestUtils.beforeEachCompiler([PageFormPrecos]).then(compiled => { + fixture = compiled.fixture; + instance = compiled.instance; + }))); + + it('should create the page', async(() => { + expect(instance).toBeTruthy(); + })); +}); diff --git a/src/pages/FormPrecos/main.ts b/src/pages/FormPrecos/main.ts new file mode 100644 index 0000000..cd0a12c --- /dev/null +++ b/src/pages/FormPrecos/main.ts @@ -0,0 +1,32 @@ +import { Component } from '@angular/core'; +import { NavController } from 'ionic-angular'; +import { NavParams } from 'ionic-angular'; +import { ToastController } from 'ionic-angular'; +import { PageForm } from '../generico_form/main'; +import { Consulta } from '../../entities/Consulta'; + +@Component({ + selector: 'page-form', + templateUrl: '../generico_form/main.html' +}) +export class PageFormPrecos extends PageForm { + constructor( + public navCtrl: NavController, + public navParams: NavParams, + public toastCtrl: ToastController, + ){ + super(navCtrl, navParams, toastCtrl); + console.log(this.editing) + this.postSuper(); + } + public textOption(field: string, item: any): string{ return ''; }; + public titulo: string = "preço"; + public fields: object[] = [ + { + type: 'number', + label: 'Preco unitário', + entity: 'preco', + verifywith: 'gtz' + }, + ]; +} diff --git a/src/pages/ListaCompras/main.ts b/src/pages/ListaCompras/main.ts index e9b2e46..8f0520a 100644 --- a/src/pages/ListaCompras/main.ts +++ b/src/pages/ListaCompras/main.ts @@ -10,6 +10,8 @@ import { CrudSupermercado } from '../../providers/CrudSupermercado.service'; import { PageLista } from '../generico_lista/main'; import { PageFormCompras } from '../FormCompras/main'; import { PageListaItensCompra } from '../ListaItensCompra/main'; +import { PageListaPrecos } from '../ListaPrecos/main'; +import { PageRelatorioEscolhe } from '../RelatorioEscolhe/main'; @Component({ selector: 'page-lista', @@ -48,7 +50,9 @@ export class PageListaCompras extends PageLista { role: 'manage', icon: 'cash', handler: () => { - this.navCtrl.setRoot(PageListaCompras) + this.navCtrl.push(PageListaPrecos,{ + 'sujeito': this.getClicado() + }) } }) this.contextoExibe['personalizado'].push({ @@ -56,7 +60,9 @@ export class PageListaCompras extends PageLista { role: 'manage', icon: 'cart', handler: () => { - this.navCtrl.setRoot(PageListaCompras) + this.navCtrl.push(PageRelatorioEscolhe,{ + 'sujeito': this.getClicado() + }) } }) } diff --git a/src/pages/ListaPrecos/main.spec.ts b/src/pages/ListaPrecos/main.spec.ts new file mode 100644 index 0000000..2347d0f --- /dev/null +++ b/src/pages/ListaPrecos/main.spec.ts @@ -0,0 +1,22 @@ +import { ComponentFixture, async } from '@angular/core/testing'; +import { TestUtils } from '../../test'; +import { PageListaPrecos } from './main'; + +let fixture: ComponentFixture = null; +let instance: any = null; + +declare var describe: any; +declare var it: any; +declare var expect: any; +declare var beforeEach: any; + +describe('Pages: Listas: Precos', () => { + beforeEach(async(() => TestUtils.beforeEachCompiler([PageListaPrecos]).then(compiled => { + fixture = compiled.fixture; + instance = compiled.instance; + }))); + + it('should create the page', async(() => { + expect(instance).toBeTruthy(); + })); +}); diff --git a/src/pages/ListaPrecos/main.ts b/src/pages/ListaPrecos/main.ts new file mode 100644 index 0000000..d188fb3 --- /dev/null +++ b/src/pages/ListaPrecos/main.ts @@ -0,0 +1,146 @@ +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 { Necessidade } from '../../entities/Necessidade'; +import { Planejamento } from '../../entities/Planejamento'; +import { Consulta } from '../../entities/Consulta'; +import { CrudNecessidade } from '../../providers/CrudNecessidade.service'; +import { CrudPlanejamento } from '../../providers/CrudPlanejamento.service'; +import { CrudSupermercado } from '../../providers/CrudSupermercado.service'; +import { CrudConsulta } from '../../providers/CrudConsulta.service'; +import { PageListacolapsavel } from '../generico_lista_colapsavel/main'; +import { PageFormPrecos } from '../FormPrecos/main'; + +@Component({ + selector: 'page-lista', + templateUrl: '../generico_lista_colapsavel/main.html' +}) +export class PageListaPrecos extends PageListacolapsavel { + constructor( + public navCtrl: NavController, + public navParams: NavParams, + public actionSheetCtrl: ActionSheetController, + public alert: AlertController, + public toast: Toast, + public loadingCtrl: LoadingController, + public necessidadeCrud: CrudNecessidade, + public consultaCrud: CrudConsulta, + public planejamentoCrud: CrudPlanejamento, + public supermercadoCrud: CrudSupermercado, + ){ + super( + navCtrl, + navParams, + actionSheetCtrl, + alert, + toast, + loadingCtrl, + necessidadeCrud, + consultaCrud, + ); + this.planejamento = navParams.get('sujeito') + this.externosMonitorados = (this.planejamento).necessidades + } + public planejamento: Planejamento; + public textos: object = { + "titulo": "Anotar preços", + }; + public iconeI: string = 'cart'; + public itemField: string = 'consultas'; + public textoExterno(item: Necessidade):string{ + return (item.produto || {nome:''}).nome + } + public textoInterno(item: Consulta):string{ + return (item.supermercado || {nome:''}).nome + } + public posTextoExterno(item: Necessidade):string{ + let consultas: number = 0 + for(let consulta of item.consultas){ + if(consulta.preco>0){ + consultas+=1 + } + } + return consultas+' de '+item.consultas.length+' consultas' + } + public posTextoInterno(item: Consulta):string{ + return ((item.necessidade || {quantidade:'???'}).quantidade)+' \u00d7 '+String((item.preco || '???')) + } + public ordenaExibicaoInterno(items: Consulta[]):Consulta[]{ + items.sort((a, b) => { + if ((a.supermercado || {nome:''}).nome > (b.supermercado || {nome:''}).nome) { return 1; } + if ((a.supermercado || {nome:''}).nome < (b.supermercado || {nome:''}).nome) { return -1; } + return 0; + }) + return items; + } + public ordenaExibicaoExterno(items: Necessidade[]):Necessidade[]{ + items.sort((a, b) => { + if ((a.produto || {nome:''}).nome > (b.produto || {nome:''}).nome) { return 1; } + if ((a.produto || {nome:''}).nome < (b.produto || {nome:''}).nome) { return -1; } + if (a.quantidade > b.quantidade) { return 1; } + if (a.quantidade < b.quantidade) { return -1; } + return 0; + }) + return items; + } + public clickInterno(item: Consulta){ + this.navCtrl.push( + PageFormPrecos, + { + sujeito: item, + crud: this.crudInterno, + selecionaveis: {}, + }, + ) + } + beforeRefreshList():Promise{ + return new Promise((resolve, reject)=>{ + this.planejamentoCrud.recarregarUm(this.planejamento).then(planejamento=>{ + this.planejamento = planejamento + this.necessidadeCrud.recarregarAlguns(planejamento.necessidades).then(necessidades => { + this.items = necessidades + let consultas: Consulta[] = [] + for(let necessidade of necessidades){ + for(let consulta of necessidade.consultas){ + consultas.push(consulta) + } + } + this.consultaCrud.recarregarAlguns(consultas).then(consultas => { + let consultasId: {[id: number]: Array;} = {} + for(let consulta of consultas){ + if(typeof(consultasId[(consulta.necessidade || {id:0}).id])==='undefined'){ + consultasId[(consulta.necessidade || {id:0}).id]=[] + } + consultasId[(consulta.necessidade || {id:0}).id].push( + (consulta.supermercado || {id:0}).id + ) + } + this.supermercadoCrud.recarregarAlguns(this.planejamento.supermercados).then(supermercados=>{ + let promises: Promise[] = [] + for(let necessidade of necessidades){ + for(let supermercado of supermercados){ + if( + typeof(consultasId[necessidade.id])==='undefined' + || + consultasId[necessidade.id].indexOf(supermercado.id)===-1 + ){ + let consulta: Consulta = this.consultaCrud.criar() + consulta.necessidade = necessidade + consulta.supermercado = supermercado + consulta.preco = 0 + promises.push(this.consultaCrud.salvar(consulta)) + } + } + } + Promise.all(promises).then(resolve,reject) + },reject) + },reject) + },reject) + },reject) + }) + } +} diff --git a/src/pages/RelatorioEscolhe/main.html b/src/pages/RelatorioEscolhe/main.html new file mode 100644 index 0000000..93a7956 --- /dev/null +++ b/src/pages/RelatorioEscolhe/main.html @@ -0,0 +1,28 @@ + + + + Ir às compras + + + + + + + + + ...no menor preço... + + + + + + + + + diff --git a/src/pages/RelatorioEscolhe/main.scss b/src/pages/RelatorioEscolhe/main.scss new file mode 100644 index 0000000..bdff159 --- /dev/null +++ b/src/pages/RelatorioEscolhe/main.scss @@ -0,0 +1,17 @@ +page-inicio { + .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; + } + .noHSpace{ + padding-left: 0px !important; + padding-right: 0px !important; + margin-left: 0px !important; + margin-right: 0px !important; + } +} diff --git a/src/pages/RelatorioEscolhe/main.spec.ts b/src/pages/RelatorioEscolhe/main.spec.ts new file mode 100644 index 0000000..a45fa80 --- /dev/null +++ b/src/pages/RelatorioEscolhe/main.spec.ts @@ -0,0 +1,24 @@ +import { ComponentFixture, async } from '@angular/core/testing'; +import { TestUtils } from '../../test'; +import { PageRelatorioEscolhe } from './main'; + +let fixture: ComponentFixture = null; +let instance: any = null; + +declare var describe: any; +declare var it: any; +declare var expect: any; +declare var beforeEach: any; + +describe('Pages: Relatorio: Escolhe', () => { + + beforeEach(async(() => TestUtils.beforeEachCompiler([PageRelatorioEscolhe]).then(compiled => { + fixture = compiled.fixture; + instance = compiled.instance; + }))); + + it('should create the start page', async(() => { + expect(instance).toBeTruthy(); + })); + +}); diff --git a/src/pages/RelatorioEscolhe/main.ts b/src/pages/RelatorioEscolhe/main.ts new file mode 100644 index 0000000..0a45f5b --- /dev/null +++ b/src/pages/RelatorioEscolhe/main.ts @@ -0,0 +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 { PageRelatorioExibe } from '../RelatorioExibe/main' + +@Component({ + selector: 'page-inicio', + templateUrl: 'main.html' +}) +export class PageRelatorioEscolhe { + 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, + }) + } + ) + } +} diff --git a/src/pages/RelatorioExibe/main.spec.ts b/src/pages/RelatorioExibe/main.spec.ts new file mode 100644 index 0000000..40a0016 --- /dev/null +++ b/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 = 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(); + })); +}); diff --git a/src/pages/RelatorioExibe/main.ts b/src/pages/RelatorioExibe/main.ts new file mode 100644 index 0000000..473f729 --- /dev/null +++ b/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 { + 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: ''}).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; + } +} diff --git a/src/pages/generico_lista/main.html b/src/pages/generico_lista/main.html index d5eff27..531a287 100644 --- a/src/pages/generico_lista/main.html +++ b/src/pages/generico_lista/main.html @@ -20,7 +20,7 @@ {{ posTexto(item) }}   - + {{ texto(item) }} diff --git a/src/pages/generico_lista/main.scss b/src/pages/generico_lista/main.scss index eefd22c..0bf00a1 100644 --- a/src/pages/generico_lista/main.scss +++ b/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; + } } diff --git a/src/pages/generico_lista/main.ts b/src/pages/generico_lista/main.ts index b7379b1..4b3f6c6 100644 --- a/src/pages/generico_lista/main.ts +++ b/src/pages/generico_lista/main.ts @@ -39,6 +39,7 @@ export abstract class PageLista { 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 { 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:', diff --git a/src/pages/generico_lista_colapsavel/main.html b/src/pages/generico_lista_colapsavel/main.html new file mode 100644 index 0000000..f0fe1bc --- /dev/null +++ b/src/pages/generico_lista_colapsavel/main.html @@ -0,0 +1,33 @@ + + + + {{ textos.titulo }} + + + + + + + + + + + {{ posTextoInterno(subitem) }} + +   + + {{ textoInterno(subitem) }} + + + + + diff --git a/src/pages/generico_lista_colapsavel/main.scss b/src/pages/generico_lista_colapsavel/main.scss new file mode 100644 index 0000000..f0ec424 --- /dev/null +++ b/src/pages/generico_lista_colapsavel/main.scss @@ -0,0 +1,42 @@ +page-lista { + .text-end{ + display: relative; + float: right; + } + .text-muted{ + opacity: 0.5; + } + .collapsible button:first-of-type ion-icon:first-of-type{ + transition: transform 200ms ease-in-out; + } + .collapsible:not(.collapsed) button:first-of-type ion-icon:first-of-type{ + transform: rotate(90deg); + } + .collapsible>ion-list{ + transition: all 300ms ease-in-out; + transform: scaleY(1); + opacity: 1; + } + .collapsible.collapsed>ion-list{ + transform: scaleY(0); + opacity: 0; + margin-top: 0; + margin-bottom: 0; + padding-top: 0; + padding-bottom: 0; + } + .collapsible>ion-list ion-item{ + transition: all 300ms ease-in-out; + max-height: 4.4rem; + } + .collapsible.collapsed>ion-list ion-item{ + max-height: 0rem; + min-height: 0rem; + } +} +.deleteToast{ + color: #cc3333 !important; +} +.cancelToast{ + color: #387ef5 !important; +} diff --git a/src/pages/generico_lista_colapsavel/main.ts b/src/pages/generico_lista_colapsavel/main.ts new file mode 100644 index 0000000..d85f6d7 --- /dev/null +++ b/src/pages/generico_lista_colapsavel/main.ts @@ -0,0 +1,103 @@ +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 { Loading } from 'ionic-angular'; +import { Toast } from "@ionic-native/toast"; +import { CrudService } from '../../providers/_crudService'; + +export abstract class PageListacolapsavel{ + constructor( + public navCtrl: NavController, + public navParams: NavParams, + public actionSheetCtrl: ActionSheetController, + public alert: AlertController, + public toast: Toast, + public loadingCtrl: LoadingController, + public crudExterno: CrudService, + public crudInterno: CrudService, + ){ + } + public mostraCarregando(){ + this.initialLoad = this.loadingCtrl.create({ content: 'Carregando...' }); this.initialLoad.present(); + } + public escondeCarregando(){ + this.initialLoad.dismiss() + } + public contextoExibe: object = { + excluir: true, + editar: true, + personalizado: [], + }; + ionViewWillEnter(){ + this.refreshList(); + } + externosMonitorados: E[] = []; + abstract beforeRefreshList():Promise; + refreshList(){ + this.mostraCarregando(); + this.beforeRefreshList().then(()=>{ + let externoLista: Promise; + if(this.externosMonitorados.length==0){ + externoLista = this.crudExterno.listar(); + }else{ + externoLista = this.crudExterno.recarregarAlguns(this.externosMonitorados) + } + externoLista.then( + (lista: E[]) => { + let recuperar: I[] = new Array() + for(let item of lista){ + for(let interno of item[this.itemField]){ + recuperar.push(interno) + } + } + this.crudInterno.recarregarAlguns(recuperar).then( (internos: I[]) => { + for(let indiceExterno in lista){ + for(let indiceInterno in lista[indiceExterno][this.itemField]){ + for(let interno of internos){ + if (lista[indiceExterno][this.itemField][indiceInterno]['id'] == interno['id']){ + lista[indiceExterno][this.itemField][indiceInterno] = interno + } + } + } + } + this.items = this.ordenaExibicaoExterno(lista); + for(let indiceExterno in this.items){ + if(this.items[indiceExterno]['id']>0){ + this.items[indiceExterno][this.itemField] = this.ordenaExibicaoInterno(this.items[indiceExterno][this.itemField]); + } + } + this.escondeCarregando() + }) + } + ); + }); + } + public items: Array; + public initialLoad: Loading; + public abstract textos: object; + 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 ordenaExibicaoExterno(items: E[]):E[]; + public abstract ordenaExibicaoInterno(items: I[]):I[]; + public collapsed: number[] = []; + public collapse(item: E):void{ + if(this.isCollapsed(item)){ + this.collapsed.splice(this.collapsed.indexOf(item['id']),1) + }else{ + this.collapsed.push(item['id']) + } + }; + public isCollapsed(item: E):boolean{ + return this.collapsed.indexOf(item['id']) != -1 + } + public abstract clickInterno(item: I):void; + public getSubitems(item: E):I[]{ + return item[this.itemField] + } +} diff --git a/src/persistence/OrmDatabase.service.ts b/src/persistence/OrmDatabase.service.ts index 1d67dfe..ffc391c 100644 --- a/src/persistence/OrmDatabase.service.ts +++ b/src/persistence/OrmDatabase.service.ts @@ -79,4 +79,13 @@ export class OrmDatabase{ } }) } + dropDatabase(){ + return new Promise((resolve, reject) => { + this.getConnection().then(connection =>{ + connection.dropDatabase().then(()=>{ + connection.close().then(resolve,reject) + }, reject) + },reject) + }) + } } diff --git a/src/providers/Relatorios.service.ts b/src/providers/Relatorios.service.ts index c5d9be7..83f3833 100644 --- a/src/providers/Relatorios.service.ts +++ b/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{ - return + _menorUm(planejamento: Planejamento, orderBy: string):Promise{ + return new Promise((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>{ - return + menorPrecoMedio(planejamento: Planejamento):Promise{ + return this._menorUm(planejamento, "SUM(tbl.preco)/COUNT(*)") } - menorPrecoEmTodosSupermercados(planejamento: Planejamento):Promise>{ - return + menorPrecoEmUmSupermercado(planejamento: Planejamento):Promise{ + return this._menorUm(planejamento, "SUM(tbl.preco*necessidade.quantidade)") + } + menorPrecoEmTodosSupermercados(planejamento: Planejamento):Promise{ + return new Promise((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) + }) } } diff --git a/src/test.ts b/src/test.ts index ce857c8..8a24ab5 100644 --- a/src/test.ts +++ b/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,