Prechádzať zdrojové kódy

sincronizacion de subida para el modulo de productos

robert2206 8 rokov pred
rodič
commit
65d523b275

+ 2 - 1
src/app/app.component.ts

@@ -103,7 +103,8 @@ export class MyApp {
 
     initializeApp() {
         this.platform.ready().then(() => {
-            StatusBar.styleDefault();
+            // StatusBar.styleDefault();
+            StatusBar.backgroundColorByHexString("#364499");
         });
     }
 

+ 17 - 62
src/models/product.ts

@@ -1,66 +1,21 @@
 
 export class Product {
 
-    constructor(
-        private _id: number,
-        private _name: string,
-        private _displayName: string,
-        private _price: number
-    ) {}
-
-    /**
-     *
-     */
-    get id(): number {
-        return this._id;
-    }
-
-    /**
-     *
-     */
-    get name(): string {
-        return this._name;
-    }
-
-    /**
-     *
-     */
-    get displayName(): string {
-        return this._displayName;
-    }
-
-    /**
-     *
-     */
-    get price(): number {
-        return this._price;
-    }
-
-    /**
-     *
-     */
-    set id(_id: number) {
-        this._id = _id;
-    }
-
-    /**
-     *
-     */
-    set name(_name: string) {
-        this._name = _name;
-    }
-
-    /**
-     *
-     */
-    set displayName(_displayName: string) {
-        this._displayName = _displayName;
-    }
-
-    /**
-     *
-     */
-    set price(_price: number) {
-        this._price = _price;
-    }
+    company_id: number = 0;
+    default_code: string = null;
+    description: string = null;
+    ean13: string = null;
+    image_medium: string = null;
+    image_small: string = null;
+    name: string = null;
+    list_price: number = 0;
+    purchase_ok: boolean =  true;
+    qty_available: number = 0;
+    rental: boolean = false;
+    sale_ok: boolean = true;
+    standard_price: number = 0;
+    type: number = 0;
+    doc_state: string = "created";
+
+    constructor() {}
 }

+ 7 - 12
src/pages/product-details/product-details.html

@@ -36,15 +36,15 @@
         <ion-item>
             <ion-label stacked>Tipo de producto</ion-label>
             <ion-select [(ngModel)]="product.type">
-                <ion-option value="0">Almacenable</ion-option>
-                <ion-option value="1">Consumible</ion-option>
-                <ion-option value="2">Servicio</ion-option>
+                <ion-option value="product">Almacenable</ion-option>
+                <ion-option value="consu">Consumible</ion-option>
+                <ion-option value="service">Servicio</ion-option>
             </ion-select>
         </ion-item>
 
         <ion-item>
             <ion-label stacked>Precio de venta</ion-label>
-            <ion-input type="number" [(ngModel)]="product.salePrice"></ion-input>
+            <ion-input type="number" [(ngModel)]="product.list_price"></ion-input>
         </ion-item>
 
         <ion-item>
@@ -54,24 +54,19 @@
 
         <ion-item>
             <ion-label stacked>Referencia Interna</ion-label>
-            <ion-input type="text" [(ngModel)]="product.reference"></ion-input>
+            <ion-input type="text" [(ngModel)]="product.default_code"></ion-input>
         </ion-item>
 
         <ion-list-header color="light">Abastecimientos e inventario</ion-list-header>
 
         <ion-item>
             <ion-label stacked>Precio de costo</ion-label>
-            <ion-input type="number" [(ngModel)]="product.costPrice"></ion-input>
+            <ion-input type="number" [(ngModel)]="product.standard_price"></ion-input>
         </ion-item>
 
         <ion-item>
             <ion-label stacked>Cantidad a mano</ion-label>
-            <ion-input type="number" [(ngModel)]="product.quantity"></ion-input>
-        </ion-item>
-
-        <ion-item>
-            <ion-label stacked>Activo</ion-label>
-            <ion-toggle [(ngModel)]="product.active"></ion-toggle>
+            <ion-input type="number" [(ngModel)]="product.qty_available"></ion-input>
         </ion-item>
 
     </ion-list>

+ 19 - 11
src/pages/product-details/product-details.ts

@@ -12,16 +12,22 @@ import { CameraProvider } from '../../providers/camera-provider';
 export class ProductDetailsPage {
 
     product = {
-        name: "",
-        type: 0,
-        salePrice: 0,
-        ean13: "",
-        reference: "",
-        costPrice: 0,
-        quantity: 0,
-        salesCount: 0,
-        image: null,
-        active: true
+        company_id: null,
+        default_code: false,
+        description: false,
+        ean13: false,
+        image_medium: null,
+        image_small: null,
+        name: null,
+        list_price: 0,
+        purchase_ok: true,
+        qty_available: 0,
+        rental: false,
+        sale_ok: true,
+        standard_price: 0,
+        type: "product",
+        remote_id: 0,
+        doc_state: "created"
     }
 
     constructor(
@@ -40,6 +46,7 @@ export class ProductDetailsPage {
     private initialize() {
         if (!(this.params.data instanceof Array)) {
             this.product = this.params.data;
+            this.product.doc_state = "updated";
         }
     }
 
@@ -88,7 +95,8 @@ export class ProductDetailsPage {
      */
     takePicture(source: string): void {
         this.cameraProvider.getPicture(source).then(i => {
-            this.product.image = i; 
+            this.product.image_medium = i;
+            this.product.image_small = i;
         }).catch(e => {
             console.log(e);                    
         });

+ 10 - 4
src/pages/product-list/product-list.html

@@ -33,7 +33,7 @@
     </ion-buttons>
 
     <ion-buttons end>
-        <button ion-button (click)="removeItem()">
+        <button ion-button (click)="askIfRemoveItem()">
             <ion-icon name="trash"></ion-icon>
         </button>
     </ion-buttons>
@@ -44,15 +44,21 @@
     <ion-card *ngFor="let p of list(); let i = index;" (tap)="openItem(i)" (press)="toggleDelete(i)">
         <button ion-item>
             <ion-avatar item-left>
-                <img src="./assets/images/product.png" *ngIf="!p.image"/>
-                <img src="data:image/jpeg;base64,{{ p.image }}" *ngIf="p.image"/>
+                <img src="./assets/images/product.png" *ngIf="!p.image_medium"/>
+                <img src="data:image/jpeg;base64,{{ p.image }}" *ngIf="p.image_medium"/>
             </ion-avatar>
 
             <h2>{{ p.name }}</h2>
 
             <p>
                 <strong>Precio:</strong>
-                {{ p.salePrice }}
+                {{ p.list_price || 0 }}
+            </p>
+
+
+            <p>
+                <strong>Cantidad:</strong>
+                {{ p.qty_available || 0 }}
             </p>
 
             <ion-icon name="checkmark-circle" color="primary" item-right *ngIf="i == _selectedIndex"></ion-icon>

+ 20 - 12
src/pages/product-list/product-list.ts

@@ -48,7 +48,7 @@ export class ProductListPage extends DefaultListable<Product> implements INaviga
     /**
      *
      */
-    removeItem() {
+    askIfRemoveItem(): void {
         this.alertCtrl.create({
             title: "Confirmar",
             message: "Desea borrar este producto?",
@@ -62,20 +62,28 @@ export class ProductListPage extends DefaultListable<Product> implements INaviga
                 {
                     text: "Aceptar",
                     handler: () => {
-                        let item = this.elements[this.selectedIndex];
-                        this.toggleDelete(-1);
-
-                        this.dataProvider.delete("product", item).then(result => {
-                            this.elements.splice(this.selectedIndex, 1);
-                        }).catch(() => {
-                            this.toastCtrl.create({
-                                message: "No se pudo eliminar el producto",
-                                duration: 1000
-                            }).present();
-                        });
+                        this.removeItem();
                     }
                 }
             ]
         }).present();
     }
+
+    /**
+     *
+     */
+    removeItem() {
+        let item = this.elements[this.selectedIndex];
+        item.doc_state = "deleted";
+        this.toggleDelete(-1);
+        
+        this.dataProvider.delete("product", item).then(result => {
+            this.elements.splice(this.selectedIndex, 1);
+        }).catch(() => {
+            this.toastCtrl.create({
+                message: "No se pudo eliminar el producto",
+                duration: 1000
+            }).present();
+        });
+    }
 }

+ 1 - 1
src/pages/tools/tools.html

@@ -20,7 +20,7 @@
     </ion-card>
 
     <ion-card>
-        <button ion-item (click)="deleteAccount()">
+        <button ion-item (click)="askIfDeleteAccount()">
             <ion-icon name="walk" color="primary" item-left></ion-icon>
             <h2>Eliminar cuenta</h2>
             <p>Eliminar su cuenta de Odoo guardada en la aplicación incluyendo la base de datos</p>

+ 36 - 10
src/pages/tools/tools.ts

@@ -56,12 +56,18 @@ export class ToolsPage {
 
         this.syncProvider.doSync().then(r => {
             loader.dismiss();
+
+            this.toastCtrl.create({
+                message: "Datos actualizados correctamente",
+                duration: 3000
+            }).present();
         }).catch(e => {
+            console.log(e);
             loader.dismiss();
 
             this.toastCtrl.create({
                 message: "No se pudo actualizar los datos",
-                duration: 1000
+                duration: 3000
             }).present();
         });
     }
@@ -69,8 +75,8 @@ export class ToolsPage {
     /**
      *
      */
-    deleteAccount() {
-        this.alertCtrl.create({
+    askIfDeleteAccount() {
+         this.alertCtrl.create({
             title: "Confirmar",
             message: "Desea borrar su cuenta?",
             buttons: [
@@ -80,16 +86,36 @@ export class ToolsPage {
                 {
                     text: "Aceptar",
                     handler: () => {
-                        this.dataProvider.dropDatabase().then(r => {
-                            localStorage.clear();
-                            this.navCtrl.setRoot(LoginPage);
-                        }).catch(e => {
-                            console.log(e);
-                        });
-                        
+                        this.deleteAccount();
                     }
                 }
             ]
         }).present();
     }
+
+    /**
+     *
+     */
+    deleteAccount() {
+        let loader = this.loadingCtrl.create({
+            content: "Eliminando cuenta, espere..."
+        });
+
+        loader.present();
+
+        this.dataProvider.dropDatabase().then(r => {
+            localStorage.clear();
+            this.navCtrl.setRoot(LoginPage);
+
+            loader.dismiss();
+        }).catch(e => {
+            console.log(e);
+            loader.dismiss();
+
+            this.toastCtrl.create({
+                message: "No se pudo eliminar su cuenta",
+                duration: 3000
+            }).present();
+        });
+    }
 }

+ 3 - 1
src/providers/data-provider.ts

@@ -79,6 +79,8 @@ export class DataProvider {
      *
      */
     save(type: string, data: any): any {
+        console.log(data);
+        
         return new Promise((resolve, reject) => {
             resolve(this.data.rel.save(type, data));
         });
@@ -89,7 +91,7 @@ export class DataProvider {
      */
     delete(type: string, data: any): any {
         return new Promise((resolve, reject) => {
-            resolve(this.data.rel.del(type, data));
+            resolve(data.remote_id ? this.data.rel.del(type, data) : this.save(type, data));
         });
     }
 

+ 21 - 3
src/providers/odoo-provider.ts

@@ -3,6 +3,7 @@ import { Http, Headers, Response, RequestOptions } from '@angular/http';
 import { Observable } from 'rxjs/Observable';
 import { PreferencesProvider } from './preferences-provider';
 
+import 'rxjs/add/operator/toPromise'
 import 'rxjs/add/operator/map';
 import 'rxjs/add/operator/catch';
 import 'rxjs/add/observable/throw'
@@ -26,18 +27,35 @@ export class OdooProvider {
     private normalizeUrl(): void {
         this.url = (this.url.startsWith('http://') ? this.url : 'http://' + this.url) + '/api/';
     }
+
+    /**
+     * 
+     */
+    post(resource: string, data: Array<any>): Array<Promise<any>> {
+        let headers = new Headers({
+            'Authorization': 'JWT ' + this.preferencesProvider.getToken()
+        });
+        let options = new RequestOptions({ headers: headers });
+
+        let promises: Array<Promise<any>> = [];
+        for (let i = 0; i < data.length; i++) {
+            promises.push(this.http.post(this.url + resource, null, options).toPromise());
+        }
+
+        return promises;
+    }
     
     /**
      *
      */
-    get(resource: string): Observable<Response> {
+    get(resource: string): Observable<Array<any>> {
         this.url = this.url + resource;
 
         let headers = new Headers({
             'Authorization': 'JWT ' + this.preferencesProvider.getToken()
         });
         let options = new RequestOptions({ headers: headers });
-
+ 
         return this.http.get(this.url, options).map(this.extractData).catch(this.handleError);
     }
 
@@ -59,7 +77,7 @@ export class OdooProvider {
      *
      */
     private extractData(response: Response): any {
-        return response.json();
+        return response.json() || [];
     }
 
     /**

+ 67 - 13
src/providers/sync-provider.ts

@@ -2,6 +2,7 @@ import { Injectable } from '@angular/core';
 import { DataProvider } from './data-provider';
 import { OdooProvider } from './odoo-provider';
 import { NetworkProvider } from './network-provider'
+import * as Async from 'async-each';
 
 @Injectable()    
 export class SyncProvider {
@@ -9,41 +10,94 @@ export class SyncProvider {
     constructor(
         public dataProvider: DataProvider,
         public odooProvider: OdooProvider
-    ) { }
+    ) { 
+        console.log(Async);
+    }
 
     /**
      *
      */
     doSync(): Promise<any> {
         return new Promise((resolve, reject) => {
-            // this.getProductsForUpdate().then(p => {
-            //     console.log(p);
+            // this.odooProvider.get("products").subscribe(data => {
+            
+            //     data.forEach(item => { 
+            //         this.dataProvider.save("product", item);
+            //     });
+                
             //     resolve();
-            // }).catch(e => {
-            //     console.log(e);
-            //     reject(e);
+            // }, err => {
+            //     reject();
             // });
-            this.odooProvider.get("products").subscribe(data => {
-                console.log(data);
+            Promise.all([
+                this.pushCreatedProducts()
+            ]).then(r => {
+                console.log(r);
                 resolve();
-            }, err => {
-                reject();
-            });
+            }).catch(e => {
+                console.log(e);
+                reject(e);
+                });
         });
     }
 
     /**
      *
      */
-    private getProductsForUpdate(): Promise<any> {
+    private pushCreatedProducts(): any {
+        this.getCreatedProducts().then(p => {
+            return this.odooProvider.post("products", p);
+
+        }).then(p => {
+
+            console.log(p);
+            
+            return Promise.resolve();
+        });
+    }
+
+    /**
+     *
+     */
+    private getCreatedProducts(): Promise<any> {
         return new Promise((resolve, reject) => {
             this.dataProvider.getAll("product").then(r => {
                 resolve(r.products.filter(item => {
-                    return item;
+                    return item.doc_state === "created";
                 }));
             }).catch(e => {
                 reject(e);
             });
         });
     }
+
+    /**
+     *
+     */
+    private getUpdatedProducts(): Promise<any> {
+        return new Promise((resolve, reject) => {
+            this.dataProvider.getAll("product").then(r => { 
+                resolve(r.products.filter(item => {
+                    return item.doc_state === "updated" && item.remote_id != 0;
+                 }));
+            }).catch(e => {
+                reject(e);
+            });
+        });
+    }
+
+    /**
+     *
+     */
+    private getDeletedProducts(): Promise<any> {
+        return new Promise((resolve, reject) => { 
+            this.dataProvider.getAll("product").then(r => { 
+                resolve(r.products.filter(item => {
+                    return item.doc_state === "deleted";
+                }));
+            }).catch(e => { 
+                reject(e);
+            });
+        });
+    }
 }

+ 1 - 1
src/providers/token-service.ts

@@ -13,7 +13,7 @@ export class TokenService {
 
     username: string = 'admin';
     password: string = 'admin';
-    url: string = '127.0.0.1:8069';
+    url: string = '192.168.88.123:8069';
 
     constructor(
         public http: Http,