Browse Source

generic view list

robert2206 8 years ago
parent
commit
2380ec7cd1
38 changed files with 1095 additions and 86 deletions
  1. 15 3
      src/app/app.component.ts
  2. 2 0
      src/app/app.module.ts
  3. BIN
      src/assets/images/customer.png
  4. BIN
      src/assets/images/product.png
  5. 0 0
      src/base/base-details-view.ts
  6. 116 0
      src/base/base-list-view.ts
  7. 51 0
      src/base/base-view.ts
  8. 1 1
      src/odoo/collections/model-metadata.ts
  9. 31 0
      src/odoo/models/account.tax.code.ts
  10. 49 0
      src/odoo/models/account.tax.ts
  11. 13 0
      src/odoo/models/crm.case.categ.ts
  12. 25 0
      src/odoo/models/crm.case.stage.ts
  13. 103 0
      src/odoo/models/crm.lead.ts
  14. 58 0
      src/odoo/models/crm.phonecall.ts
  15. 0 34
      src/odoo/models/customer.ts
  16. 13 0
      src/odoo/models/product.attribute.line.ts
  17. 19 0
      src/odoo/models/product.attribute.price.ts
  18. 19 0
      src/odoo/models/product.attribute.ts
  19. 28 0
      src/odoo/models/product.attribute.value.ts
  20. 19 0
      src/odoo/models/product.pricelist.ts
  21. 55 0
      src/odoo/models/product.product.ts
  22. 13 10
      src/odoo/models/product.template.ts
  23. 22 0
      src/odoo/models/res.currency.ts
  24. 55 0
      src/odoo/models/res.partner.ts
  25. 58 0
      src/odoo/models/sale.order.line.ts
  26. 61 0
      src/odoo/models/sale.order.ts
  27. 37 0
      src/odoo/models/stock.location.ts
  28. 34 0
      src/odoo/models/stock.quant.ts
  29. 25 0
      src/odoo/models/stock.warehouse.ts
  30. 41 3
      src/odoo/utils/import-models.ts
  31. 25 1
      src/pages/customers/customers.html
  32. 9 14
      src/pages/customers/customers.ts
  33. 32 1
      src/pages/orders/orders.html
  34. 15 13
      src/pages/orders/orders.ts
  35. 21 1
      src/pages/products/products.html
  36. 7 2
      src/pages/products/products.ts
  37. 11 3
      src/pages/tools/tools.ts
  38. 12 0
      src/pipes/image.ts

+ 15 - 3
src/app/app.component.ts

@@ -18,7 +18,7 @@ export class MyApp {
 
     rootPage: any = LoginPage;
     homePage: any = HomePage;
-    entries: Array<{ visible: boolean, title: string, pages: Array<{ visible: boolean, title: string, icon: string, component: any }> }>;
+    entries: Array<{ visible: boolean, title: string, pages: Array<{ visible: boolean, title: string, icon: string, component: any, params?: any }> }>;
 
     pages: Array<{title: string, component: any}>;
 
@@ -40,7 +40,19 @@ export class MyApp {
                         visible: true,
                         title: "Presupuestos",
                         icon: "basket",
-                        component: OrdersPage 
+                        component: OrdersPage,
+                        params: {
+                            filters: [["state", "=", "draft"]]
+                        }
+                    },
+                    {
+                        visible: true,
+                        title: "Ventas",
+                        icon: "basket",
+                        component: OrdersPage,
+                        params: {
+                            filters: [["state", "!=", "draft"]]
+                        }
                     },
                     {
                         visible: true,
@@ -85,6 +97,6 @@ export class MyApp {
      *
      */
     openPage(page) {
-        this.nav.setRoot(page.component);
+        this.nav.setRoot(page.component, page.params);
     }
 }

+ 2 - 0
src/app/app.module.ts

@@ -26,6 +26,7 @@ import { SyncService } from "../services/sync-service";
 
 // Pipes
 import { MenuPipe } from "../pipes/menu";
+import { ImageSanitizerPipe } from "../pipes/image";
 
 // Directives
 import { DoubleTap } from "../directives/double-tap";
@@ -47,6 +48,7 @@ import { DoubleTap } from "../directives/double-tap";
         ODetailHeader,
          // Pipes
         MenuPipe,
+        ImageSanitizerPipe,
         // Directives
         DoubleTap
     ],

BIN
src/assets/images/customer.png


BIN
src/assets/images/product.png


+ 0 - 0
src/base/base-details-view.ts


+ 116 - 0
src/base/base-list-view.ts

@@ -0,0 +1,116 @@
+import { BaseView } from "./base-view";
+
+import { PouchService } from "../services/pouch-service";
+
+export abstract class BaseListView<T> extends BaseView<T>{
+
+    items: T[];
+    filters: Array<[string, string, any]>;
+
+    constructor(c: { new (): T; }, ...filters: Array<[string, string, any]>) {
+        super(c, PouchService);
+
+        this.items = [];
+        this.filters = filters;
+
+        this.initialize();
+    }
+
+    /**
+     * 
+     */
+    initialize() {
+        this.inject(PouchService).getAll(this.getModelName()).subscribe(result => { 
+            let obj = result.docs.shift();
+
+            if (!obj) {
+                return;
+            }
+
+            this.applyFilter(obj.records);
+        }, error => { 
+            console.log(error);
+        });
+    }
+
+    /**
+     * 
+     */
+    applyFilter(records: T[]): void {
+        if (records.length == 0) {
+            return;
+        }
+        
+        if (this.getFilters().length == 0) {
+            this.items = records;
+
+            return;
+        }
+
+        this.items = records.filter(record => {
+            let expressions = this.getFilters().map(filter => {
+                let operator = "===";
+                let leftOperand = "record." + filter[0];
+                let rightOperand = typeof(filter[2]) === "string" ? "'" + filter[2] + "'" : filter[2];
+
+                if (filter[1] === "!=") {
+                    operator = "!==";
+                }
+
+                if (filter[1] === ">") {
+                    operator = ">";
+                }
+
+                if (filter[1] === "<") {
+                    operator = "<";
+                }
+
+                if (filter[1] === ">=") {
+                    operator = "<=";
+                }
+
+                if (filter[1] === "<=") {
+                    operator = "<=";
+                }
+
+                return leftOperand + operator + rightOperand;
+            });
+
+            return eval(expressions.join("&&"));
+        });
+    }
+
+    /**
+     * 
+     */
+    getItems(): T[] {
+        return this.items;
+    }
+    
+    /**
+     * 
+     * @param items 
+     */
+    setItems(items: T[]): void {
+        this.items = items;
+
+        this.applyFilter(this.getItems());
+    }
+
+    /**
+     * 
+     */
+    getFilters(): Array<[string, string, any]> {
+        return this.filters;
+    }
+
+    /**
+     * 
+     * @param filters 
+     */
+    setFilters(filters: Array<[string, string, any]>): void {
+        this.filters = filters;
+
+        this.applyFilter(this.getItems());
+    }
+} 

+ 51 - 0
src/base/base-view.ts

@@ -0,0 +1,51 @@
+import { ReflectiveInjector } from "@angular/core";
+import { getMetadataStorage } from "../odoo/utils/metadata-storage";
+
+export class BaseView<T> {
+
+    type: T = {} as T;
+    model: any = {};
+    injector: any = {};
+
+    constructor(c: { new (): T; }, ...injectables: any[]) {
+        this.type = new c();
+        this.model = getMetadataStorage().models.filterByTarget(this.type.constructor).items.shift();
+        this.injector = ReflectiveInjector.resolveAndCreate(injectables);
+    }
+
+    /**
+     * 
+     * @param injectable 
+     */
+    inject(injectable: any): any {
+        return this.injector.get(injectable);
+    }
+
+    /**
+     * 
+     */
+    getType(): T {
+        return this.type;
+    }
+
+    /**
+     * 
+     */
+    getModel(): any {
+        return this.model;
+    }
+
+    /**
+     * 
+     */
+    getModelName(): string {
+        return this.getModel().name;
+    }
+
+    /**
+     * 
+     */
+    getInjector(): any {
+        return this.injector;
+    }
+}

+ 1 - 1
src/odoo/collections/model-metadata.ts

@@ -37,7 +37,7 @@ export class ModelMetadataCollection<T extends { target?: Function | string }> {
             if (!metadata.target) {
                 return false;
             }
-
+            
             return classes.indexOf(metadata.target) !== -1;
         });
     }

+ 31 - 0
src/odoo/models/account.tax.code.ts

@@ -0,0 +1,31 @@
+import { OdooModel } from "../decorators/model";
+import { OdooField } from "../decorators/field";
+import { FieldTypes } from "../types/field";
+
+@OdooModel("account.tax.code")
+export class AccountTaxCode {
+
+    @OdooField(FieldTypes.ONE2MANY)
+    child_ids: any;
+
+    @OdooField(FieldTypes.CHAR)
+    code: string;
+
+    @OdooField(FieldTypes.MANY2ONE)
+    company_id: string;
+
+    @OdooField(FieldTypes.CHAR)
+    display_name: string;
+
+    @OdooField(FieldTypes.CHAR)
+    name: string;
+
+    @OdooField(FieldTypes.FLOAT)
+    sign: number;
+
+    @OdooField(FieldTypes.FLOAT)
+    sum: number;
+
+    @OdooField(FieldTypes.FLOAT)
+    sum_period: number;
+}

+ 49 - 0
src/odoo/models/account.tax.ts

@@ -0,0 +1,49 @@
+import { OdooModel } from "../decorators/model";
+import { OdooField } from "../decorators/field";
+import { FieldTypes } from "../types/field";
+
+@OdooModel("account.tax")
+export class AccountTax {
+
+    @OdooField(FieldTypes.FLOAT)
+    amount: number;
+
+    @OdooField(FieldTypes.SELECTION)
+    applicable_type: string;
+
+    @OdooField(FieldTypes.MANY2ONE)
+    base_code_id: any;
+
+    @OdooField(FieldTypes.FLOAT)
+    base_sign: number;
+
+    @OdooField(FieldTypes.BOOLEAN)
+    child_depend: boolean;
+
+    @OdooField(FieldTypes.ONE2MANY)
+    child_ids: any;
+
+    @OdooField(FieldTypes.MANY2ONE)
+    company_id: any;
+
+    @OdooField(FieldTypes.CHAR)
+    display_name: string;
+
+    @OdooField(FieldTypes.CHAR)
+    name: string;
+
+    @OdooField(FieldTypes.BOOLEAN)
+    price_include: boolean;
+
+    @OdooField(FieldTypes.MANY2ONE)
+    tax_code_id: any;
+
+    @OdooField(FieldTypes.FLOAT)
+    tax_sign: number;
+
+    @OdooField(FieldTypes.SELECTION)
+    type: string;
+
+    @OdooField(FieldTypes.SELECTION)
+    type_tax_use: string;
+}

+ 13 - 0
src/odoo/models/crm.case.categ.ts

@@ -0,0 +1,13 @@
+import { OdooModel } from "../decorators/model";
+import { OdooField } from "../decorators/field";
+import { FieldTypes } from "../types/field";
+
+@OdooModel("crm.case.categ")
+export class CaseCategory {
+
+    @OdooField(FieldTypes.CHAR)
+    display_name: string;
+
+    @OdooField(FieldTypes.CHAR)
+    name: string;
+}

+ 25 - 0
src/odoo/models/crm.case.stage.ts

@@ -0,0 +1,25 @@
+import { OdooModel } from "../decorators/model";
+import { OdooField } from "../decorators/field";
+import { FieldTypes } from "../types/field";
+
+@OdooModel("crm.case.stage")
+export class CaseStage {
+
+    @OdooField(FieldTypes.BOOLEAN)
+    case_default: boolean;
+
+    @OdooField(FieldTypes.CHAR)
+    color: string;
+
+    @OdooField(FieldTypes.CHAR)
+    display_name: string;
+
+    @OdooField(FieldTypes.CHAR)
+    name: string;
+
+    @OdooField(FieldTypes.FLOAT)
+    probability: number;
+
+    @OdooField(FieldTypes.SELECTION)
+    type: string;
+}

+ 103 - 0
src/odoo/models/crm.lead.ts

@@ -0,0 +1,103 @@
+import { OdooModel } from "../decorators/model";
+import { OdooField } from "../decorators/field";
+import { FieldTypes } from "../types/field";
+
+@OdooModel("crm.lead", [["active", "=", true]])
+export class Lead {
+
+    @OdooField(FieldTypes.MANY2ONE)
+    campaign_id: any;
+
+    @OdooField(FieldTypes.MANY2MANY)
+    categ_ids: any;
+
+    @OdooField(FieldTypes.CHAR)
+    city: string;
+
+    @OdooField(FieldTypes.CHAR)
+    color: string;
+
+    @OdooField(FieldTypes.CHAR)
+    contact_name: string;
+
+    @OdooField(FieldTypes.DATETIME)
+    create_date: string;
+
+    @OdooField(FieldTypes.DATE)
+    date_action: string;
+
+    @OdooField(FieldTypes.DATETIME)
+    date_action_last: string;
+
+    @OdooField(FieldTypes.DATETIME)
+    date_action_next: string;
+
+    @OdooField(FieldTypes.DATETIME)
+    date_closed: string;
+
+    @OdooField(FieldTypes.DATE)
+    date_deadline: string;
+
+    @OdooField(FieldTypes.DATETIME)
+    date_last_stage_update: string;
+
+    @OdooField(FieldTypes.DATETIME)
+    date_open: string;
+
+    @OdooField(FieldTypes.FLOAT)
+    day_close: number;
+
+    @OdooField(FieldTypes.FLOAT)
+    day_open: number;
+
+    @OdooField(FieldTypes.CHAR)
+    description: string;
+
+    @OdooField(FieldTypes.CHAR)
+    display_name: string;
+
+    @OdooField(FieldTypes.CHAR)
+    email_cc: string;
+
+    @OdooField(FieldTypes.CHAR)
+    email_from: string;
+
+    @OdooField(FieldTypes.CHAR)
+    fax: string;
+
+    @OdooField(FieldTypes.CHAR)
+    mobile: string;
+
+    @OdooField(FieldTypes.CHAR)
+    name: string;
+
+    @OdooField(FieldTypes.CHAR)    
+    partner_name: string
+
+    @OdooField(FieldTypes.MANY2ONE)    
+    partner_id: any;
+
+    @OdooField(FieldTypes.CHAR)    
+    phone: string;
+
+    @OdooField(FieldTypes.SELECTION)    
+    priority: string;
+
+    @OdooField(FieldTypes.FLOAT)    
+    probability: number;
+
+    @OdooField(FieldTypes.MANY2ONE)    
+    stage_id: any;
+
+    @OdooField(FieldTypes.CHAR)    
+    street: string;
+
+    @OdooField(FieldTypes.CHAR)    
+    street2: string;
+
+    @OdooField(FieldTypes.CHAR)    
+    title: string;
+
+    @OdooField(FieldTypes.SELECTION)    
+    type: string;
+}

+ 58 - 0
src/odoo/models/crm.phonecall.ts

@@ -0,0 +1,58 @@
+import { OdooModel } from "../decorators/model";
+import { OdooField } from "../decorators/field";
+import { FieldTypes } from "../types/field";
+
+@OdooModel("crm.phonecall")
+export class Phonecall {
+
+    @OdooField(FieldTypes.MANY2ONE)
+    categ_id: any;
+
+    @OdooField(FieldTypes.DATETIME)
+    date: string;
+
+    @OdooField(FieldTypes.DATETIME)
+    date_action_last: string;
+
+    @OdooField(FieldTypes.DATETIME)
+    date_action_next: string;
+
+    @OdooField(FieldTypes.DATETIME)
+    date_closed: string;
+
+    @OdooField(FieldTypes.DATETIME)
+    date_open: string;
+
+    @OdooField(FieldTypes.CHAR)
+    description: string;
+
+    @OdooField(FieldTypes.CHAR)
+    display_name: string;
+
+    @OdooField(FieldTypes.FLOAT)
+    duration: number;
+
+    @OdooField(FieldTypes.CHAR)
+    email_from: string;
+
+    @OdooField(FieldTypes.CHAR)
+    name: string;
+
+    @OdooField(FieldTypes.MANY2ONE)
+    opportunity_id: any;
+
+    @OdooField(FieldTypes.MANY2ONE)
+    partner_id: any;
+
+    @OdooField(FieldTypes.CHAR)
+    partner_mobile: string;
+
+    @OdooField(FieldTypes.CHAR)
+    partner_phone: string;
+
+    @OdooField(FieldTypes.SELECTION)
+    priority: string;
+
+    @OdooField(FieldTypes.SELECTION)
+    state: string;
+}

+ 0 - 34
src/odoo/models/customer.ts

@@ -1,34 +0,0 @@
-import { OdooModel } from "../decorators/model";
-import { OdooField } from "../decorators/field";
-import { FieldTypes } from "../types/field";
-
-@OdooModel("res.partner", [['customer', '=', true], ['active', '=', true]])
-export class Customer {
-
-    @OdooField(FieldTypes.CHAR)
-    name: string;
-
-    @OdooField(FieldTypes.CHAR)
-    city: string;
-
-    @OdooField(FieldTypes.CHAR)
-    email: string;
-
-    @OdooField(FieldTypes.CHAR)
-    fax: string;
-
-    @OdooField(FieldTypes.CHAR)
-    mobile: string;
-
-    @OdooField(FieldTypes.BINARY)
-    image_medium: string;
-
-    @OdooField(FieldTypes.INTEGER)    
-    opportunity_count: number;
-
-    @OdooField(FieldTypes.FLOAT)
-    partner_latitude: number;
-
-    @OdooField(FieldTypes.FLOAT)
-    partner_longitude: number;
-}

+ 13 - 0
src/odoo/models/product.attribute.line.ts

@@ -0,0 +1,13 @@
+import { OdooModel } from "../decorators/model";
+import { OdooField } from "../decorators/field";
+import { FieldTypes } from "../types/field";
+
+@OdooModel("product.attribute.line")
+export class ProductAttributeLine {
+
+    @OdooField(FieldTypes.CHAR)
+    display_name: string;
+
+    @OdooField(FieldTypes.MANY2MANY)
+    value_ids: any;
+}

+ 19 - 0
src/odoo/models/product.attribute.price.ts

@@ -0,0 +1,19 @@
+import { OdooModel } from "../decorators/model";
+import { OdooField } from "../decorators/field";
+import { FieldTypes } from "../types/field";
+
+@OdooModel("product.attribute.price")
+export class ProductAttributePrice {
+
+    @OdooField(FieldTypes.CHAR)
+    display_name: string;
+
+    @OdooField(FieldTypes.FLOAT)
+    price_extra: number;
+
+    @OdooField(FieldTypes.MANY2ONE)
+    product_tmpl_id: number;
+
+    @OdooField(FieldTypes.MANY2ONE)
+    value_id: number;
+}

+ 19 - 0
src/odoo/models/product.attribute.ts

@@ -0,0 +1,19 @@
+import { OdooModel } from "../decorators/model";
+import { OdooField } from "../decorators/field";
+import { FieldTypes } from "../types/field";
+
+@OdooModel("product.attribute")
+export class ProductAttribute {
+    
+    @OdooField(FieldTypes.CHAR)
+    display_name: string;
+
+    @OdooField(FieldTypes.CHAR)
+    name: string;
+
+    @OdooField(FieldTypes.CHAR)
+    type: string;
+
+    @OdooField(FieldTypes.CHAR)
+    value_ids: any;
+}

+ 28 - 0
src/odoo/models/product.attribute.value.ts

@@ -0,0 +1,28 @@
+import { OdooModel } from "../decorators/model";
+import { OdooField } from "../decorators/field";
+import { FieldTypes } from "../types/field";
+
+@OdooModel("product.attribute.value")
+export class ProductAttributeValue {
+
+    @OdooField(FieldTypes.INTEGER)
+    attribute_id: number;
+    
+    @OdooField(FieldTypes.CHAR)
+    color: string;
+
+    @OdooField(FieldTypes.CHAR)
+    display_name: string;
+
+    @OdooField(FieldTypes.CHAR)
+    name: string;
+
+    @OdooField(FieldTypes.CHAR)
+    price_extra: string;
+
+    @OdooField(FieldTypes.ONE2MANY)
+    price_ids: any;
+
+    @OdooField(FieldTypes.MANY2MANY)
+    product_ids: any;
+}

+ 19 - 0
src/odoo/models/product.pricelist.ts

@@ -0,0 +1,19 @@
+import { OdooModel } from "../decorators/model";
+import { OdooField } from "../decorators/field";
+import { FieldTypes } from "../types/field";
+
+@OdooModel("product.pricelist", [["active", "=", true]])
+export class PriceList {
+
+    @OdooField(FieldTypes.INTEGER)
+    currency_id: number;
+
+    @OdooField(FieldTypes.CHAR)
+    display_name: string;
+
+    @OdooField(FieldTypes.CHAR)
+    name: string;
+
+    @OdooField(FieldTypes.SELECTION)
+    type: string;
+}

+ 55 - 0
src/odoo/models/product.product.ts

@@ -0,0 +1,55 @@
+import { OdooModel } from "../decorators/model";
+import { OdooField } from "../decorators/field";
+import { FieldTypes } from "../types/field";
+
+@OdooModel("product.product", [["sale_ok", "=", true], ["qty_available", ">", 0], ["active", "=", true]])
+export class ProductProduct {
+
+    @OdooField(FieldTypes.ONE2MANY)
+    attribute_line_ids: any;
+
+    @OdooField(FieldTypes.MANY2MANY)
+    attribute_value_ids: any;
+
+    @OdooField(FieldTypes.MANY2ONE)
+    categ_id: any;
+
+    @OdooField(FieldTypes.CHAR)
+    code: string;
+
+    @OdooField(FieldTypes.CHAR)
+    default_code: string;
+
+    @OdooField(FieldTypes.CHAR)
+    display_name: string;
+
+    @OdooField(FieldTypes.CHAR)
+    ean13: string;
+
+    @OdooField(FieldTypes.CHAR)
+    image_medium: string;
+
+    @OdooField(FieldTypes.CHAR)
+    image_variant: string;
+
+    @OdooField(FieldTypes.FLOAT)
+    list_price: number;
+
+    @OdooField(FieldTypes.CHAR)
+    name: string;
+
+    @OdooField(FieldTypes.CHAR)
+    name_template: string;
+
+    @OdooField(FieldTypes.FLOAT)
+    price: number;
+
+    @OdooField(FieldTypes.FLOAT)
+    price_extra: number;
+
+    @OdooField(FieldTypes.MANY2ONE)
+    product_tmpl_id: number;
+
+    @OdooField(FieldTypes.FLOAT)
+    qty_available: number;
+}

+ 13 - 10
src/odoo/models/product.ts → src/odoo/models/product.template.ts

@@ -2,21 +2,27 @@ import { OdooModel } from "../decorators/model";
 import { OdooField } from "../decorators/field";
 import { FieldTypes } from "../types/field";
 
-@OdooModel('product.template', [['sale_ok', '=', true], ['active', '=', 'true']])
-export class Product {
+@OdooModel("product.template", [["sale_ok", '=', true], ["qty_available", ">", 0], ["active", "=", true]])
+export class ProductTemplate {
+
+    @OdooField(FieldTypes.ONE2MANY)
+    attribute_line_ids: any;
+
+    @OdooField(FieldTypes.MANY2ONE)
+    categ_id: any;
+
+    @OdooField(FieldTypes.MANY2ONE)
+    company_id: any;
 
     @OdooField(FieldTypes.CHAR)
     default_code: string;
 
     @OdooField(FieldTypes.CHAR)
-    description: string;
-
+    display_name: string;
+    
     @OdooField(FieldTypes.CHAR)
     ean13: string;
 
-    @OdooField(FieldTypes.CHAR)
-    flip_image: string;
-
     @OdooField(FieldTypes.CHAR)
     image_medium: string;
 
@@ -37,7 +43,4 @@ export class Product {
 
     @OdooField(FieldTypes.FLOAT)
     standard_price: number;
-
-    @OdooField(FieldTypes.SELECTION)
-    state: any;
 }

+ 22 - 0
src/odoo/models/res.currency.ts

@@ -0,0 +1,22 @@
+import { OdooModel } from "../decorators/model";
+import { OdooField } from "../decorators/field";
+import { FieldTypes } from "../types/field";
+
+@OdooModel("res.currency", [["name", "in", ["PYG", "BRL", "USD", "EUR"]], ["active", "=", true]])
+export class Currency {
+
+    @OdooField(FieldTypes.CHAR)
+    display_name: string;
+
+    @OdooField(FieldTypes.CHAR)
+    name: string;
+
+    @OdooField(FieldTypes.CHAR)
+    symbol: string;
+
+    @OdooField(FieldTypes.SELECTION)
+    position: string;
+
+    @OdooField(FieldTypes.FLOAT)
+    rate: number;
+}

+ 55 - 0
src/odoo/models/res.partner.ts

@@ -0,0 +1,55 @@
+import { OdooModel } from "../decorators/model";
+import { OdooField } from "../decorators/field";
+import { FieldTypes } from "../types/field";
+
+@OdooModel("res.partner", [["active", "=", true]])
+export class Partner {
+
+    @OdooField(FieldTypes.ONE2MANY)
+    child_ids: any;
+
+    @OdooField(FieldTypes.CHAR)
+    city: string;
+
+    @OdooField(FieldTypes.CHAR)
+    contact_address: string;
+
+    @OdooField(FieldTypes.BOOLEAN)
+    customer: boolean;
+
+    @OdooField(FieldTypes.DATE)
+    date_localization: string;
+
+    @OdooField(FieldTypes.CHAR)
+    display_name: string;
+
+    @OdooField(FieldTypes.CHAR)
+    email: string;
+
+    @OdooField(FieldTypes.BOOLEAN)
+    employee: boolean;
+
+    @OdooField(FieldTypes.CHAR)
+    fax: string;
+
+    @OdooField(FieldTypes.CHAR)
+    image_medium: string;
+
+    @OdooField(FieldTypes.BOOLEAN)
+    is_company: boolean;
+
+    @OdooField(FieldTypes.CHAR)
+    mobile: string;
+
+    @OdooField(FieldTypes.CHAR)
+    name: string;
+
+    @OdooField(FieldTypes.FLOAT)
+    partner_latitude: number;
+
+    @OdooField(FieldTypes.FLOAT)
+    partner_longitude: number;
+
+    @OdooField(FieldTypes.CHAR)
+    phone: string;
+}

+ 58 - 0
src/odoo/models/sale.order.line.ts

@@ -0,0 +1,58 @@
+import { OdooModel } from "../decorators/model";
+import { OdooField } from "../decorators/field";
+import { FieldTypes } from "../types/field";
+
+@OdooModel("sale.order.line")
+export class SaleOrderLine {
+
+    @OdooField(FieldTypes.FLOAT)
+    discount: number;
+
+    @OdooField(FieldTypes.FLOAT)
+    discounted_price: number;
+
+    @OdooField(FieldTypes.CHAR)
+    display_name: string;
+
+    @OdooField(FieldTypes.CHAR)
+    name: string;
+
+    @OdooField(FieldTypes.MANY2ONE)
+    order_id: any;
+
+    @OdooField(FieldTypes.MANY2ONE)
+    order_partner_id: any;
+
+    @OdooField(FieldTypes.FLOAT)
+    price_reduce: number;
+
+    @OdooField(FieldTypes.FLOAT)
+    price_subtotal: number;
+
+    @OdooField(FieldTypes.FLOAT)
+    price_unit: number;
+
+    @OdooField(FieldTypes.MANY2ONE)
+    product_id: any;
+
+    @OdooField(FieldTypes.MANY2ONE)
+    product_tmpl_id: any;
+
+    @OdooField(FieldTypes.MANY2ONE)
+    product_uom: any;
+
+    @OdooField(FieldTypes.FLOAT)
+    product_uom_qty: number;
+
+    @OdooField(FieldTypes.MANY2ONE)
+    product_uos: any;
+
+    @OdooField(FieldTypes.FLOAT)
+    product_uos_qty: number;
+
+    @OdooField(FieldTypes.SELECTION)
+    state: string;
+
+    @OdooField(FieldTypes.MANY2MANY)
+    tax_id: any;
+}

+ 61 - 0
src/odoo/models/sale.order.ts

@@ -0,0 +1,61 @@
+import { OdooModel } from "../decorators/model";
+import { OdooField } from "../decorators/field";
+import { FieldTypes } from "../types/field";
+
+@OdooModel("sale.order")
+export class SaleOrder {
+
+    @OdooField(FieldTypes.FLOAT)
+    amount_tax: number;
+
+    @OdooField(FieldTypes.FLOAT)
+    amount_total: number;
+
+    @OdooField(FieldTypes.FLOAT)
+    amount_untaxed: number;
+
+    @OdooField(FieldTypes.INTEGER)
+    cart_quantity: number;
+
+    @OdooField(FieldTypes.MANY2MANY)
+    categ_ids: any;
+
+    @OdooField(FieldTypes.MANY2ONE)
+    company_id: any;
+
+    @OdooField(FieldTypes.DATETIME)
+    create_date: string;
+
+    @OdooField(FieldTypes.MANY2ONE)
+    currency_id: any;
+
+    @OdooField(FieldTypes.DATE)
+    date_confirm: string;
+
+    @OdooField(FieldTypes.DATETIME)
+    date_order: string;
+
+    @OdooField(FieldTypes.CHAR)
+    display_name: string;
+
+    @OdooField(FieldTypes.BOOLEAN)
+    invoiced: boolean;
+
+    @OdooField(FieldTypes.CHAR)
+    name: string;
+
+    @OdooField(FieldTypes.ONE2MANY)
+    order_line: any;
+
+    @OdooField(FieldTypes.MANY2ONE)
+    partner_id: any;
+
+    @OdooField(FieldTypes.SELECTION)
+    state: string;
+
+    @OdooField(FieldTypes.MANY2ONE)
+    user_id: any;
+
+    @OdooField(FieldTypes.MANY2ONE)
+    warehouse_id: any;
+}

+ 37 - 0
src/odoo/models/stock.location.ts

@@ -0,0 +1,37 @@
+import { OdooModel } from "../decorators/model";
+import { OdooField } from "../decorators/field";
+import { FieldTypes } from "../types/field";
+
+@OdooModel("stock.location")
+export class StockLocation {
+
+    @OdooField(FieldTypes.ONE2MANY)
+    child_ids: any;
+
+    @OdooField(FieldTypes.MANY2ONE)
+    company_id: any;
+
+    @OdooField(FieldTypes.CHAR)
+    complete_name: string;
+
+    @OdooField(FieldTypes.CHAR)
+    display_name: string;
+
+    @OdooField(FieldTypes.MANY2ONE)
+    location_id: any;
+
+    @OdooField(FieldTypes.CHAR)
+    name: string;
+
+    @OdooField(FieldTypes.INTEGER)
+    parent_left: number;
+
+    @OdooField(FieldTypes.INTEGER)
+    parent_right: number;
+
+    @OdooField(FieldTypes.MANY2ONE)
+    partner_id: any;
+
+    @OdooField(FieldTypes.SELECTION)
+    usage: string;
+}

+ 34 - 0
src/odoo/models/stock.quant.ts

@@ -0,0 +1,34 @@
+import { OdooModel } from "../decorators/model";
+import { OdooField } from "../decorators/field";
+import { FieldTypes } from "../types/field";
+
+@OdooModel("stock.quant", [["qty", ">", 0]])
+export class StockQuant {
+
+    @OdooField(FieldTypes.MANY2ONE)
+    company_id: any;
+
+    @OdooField(FieldTypes.FLOAT)
+    cost: number;
+
+    @OdooField(FieldTypes.CHAR)
+    display_name: string;
+
+    @OdooField(FieldTypes.FLOAT)
+    inventory_value: number;
+
+    @OdooField(FieldTypes.MANY2ONE)
+    location_id: any;
+
+    @OdooField(FieldTypes.CHAR)
+    name: string;
+
+    @OdooField(FieldTypes.MANY2ONE)
+    product_id: any;
+
+    @OdooField(FieldTypes.FLOAT)
+    qty: number;
+
+    @OdooField(FieldTypes.MANY2ONE)
+    propagated_from_id: any;
+}

+ 25 - 0
src/odoo/models/stock.warehouse.ts

@@ -0,0 +1,25 @@
+import { OdooModel } from "../decorators/model";
+import { OdooField } from "../decorators/field";
+import { FieldTypes } from "../types/field";
+
+@OdooModel("stock.warehouse")
+export class StockWarehouse {
+    
+    @OdooField(FieldTypes.CHAR)
+    code: string;
+
+    @OdooField(FieldTypes.MANY2ONE)
+    company_id: any;
+
+    @OdooField(FieldTypes.CHAR)
+    display_name: string;
+
+    @OdooField(FieldTypes.MANY2ONE)
+    lot_stock_id: any;
+
+    @OdooField(FieldTypes.CHAR)
+    name: string;
+
+    @OdooField(FieldTypes.MANY2ONE)
+    partner_id: any;
+}

+ 41 - 3
src/odoo/utils/import-models.ts

@@ -1,5 +1,23 @@
-import { Customer } from "../models/customer";
-import { Product } from "../models/product";
+import { AccountTax } from "../models/account.tax";
+import { AccountTaxCode } from "../models/account.tax.code";
+import { CaseCategory } from "../models/crm.case.categ";
+import { CaseStage } from "../models/crm.case.stage";
+import { Currency } from "../models/res.currency";
+import { Lead } from "../models/crm.lead";
+import { Partner } from "../models/res.partner";
+import { Phonecall } from "../models/crm.phonecall";
+import { PriceList } from "../models/product.pricelist";
+import { ProductTemplate } from "../models/product.template";
+import { ProductProduct } from "../models/product.product";
+import { ProductAttributeLine } from "../models/product.attribute.line";
+import { ProductAttributeValue } from "../models/product.attribute.value";
+import { ProductAttributePrice } from "../models/product.attribute.price";
+import { ProductAttribute } from "../models/product.attribute";
+import { SaleOrder } from "../models/sale.order";
+import { SaleOrderLine } from "../models/sale.order.line";
+import { StockWarehouse } from "../models/stock.warehouse";
+import { StockQuant } from "../models/stock.quant";
+import { StockLocation } from "../models/stock.location";
 
 /**
  *
@@ -8,5 +26,25 @@ export function importModels(): void {
     const models: Function[] = [];
 
     // Add classes to register to metadata storage
-    models.push(Customer, Product);
+    models.push(
+        AccountTax,
+        AccountTaxCode,
+        CaseCategory,
+        CaseStage,
+        Currency,
+        Lead,
+        Phonecall,
+        PriceList,
+        ProductTemplate,
+        ProductProduct,
+        ProductAttributeLine,
+        ProductAttributeValue,
+        ProductAttributePrice,
+        ProductAttribute,
+        SaleOrder,
+        SaleOrderLine,
+        StockWarehouse,
+        StockQuant,
+        StockLocation
+    );
 }

+ 25 - 1
src/pages/customers/customers.html

@@ -10,7 +10,31 @@
 
 </ion-header>
 
+<ion-content>
+	<ion-list [virtualScroll]="getItems()" approxItemHeight="35px">
 
-<ion-content padding>
+		<ion-item *virtualItem="let item" (doubleTap)="test()">
 
+			<ion-thumbnail item-left>
+				<img src="./assets/images/customer.png" *ngIf="!item.image_medium"/>
+				<img [src]="item.image_medium | sanitizeUrl" *ngIf="item.image_medium"/>
+			</ion-thumbnail>
+
+			<h2>{{ item.name }}</h2>
+			<p>
+				<strong>Ciudad:</strong>
+				{{ item.city || "n/a" }}
+			</p>
+			<p>
+				<strong>Celular:</strong>
+				{{ item.mobile || "n/a" }}
+			</p>
+			<p>
+				<strong>Email:</strong>
+				{{ item.email || "n/a" }}
+			</p>
+			
+		</ion-item>
+
+	</ion-list>
 </ion-content>

+ 9 - 14
src/pages/customers/customers.ts

@@ -1,32 +1,27 @@
 import { Component } from "@angular/core";
 import { NavController, NavParams } from "ionic-angular";
 
-import { PouchService } from "../../services/pouch-service";
+import { BaseListView } from "../../base/base-list-view";
+import { Partner } from "../../odoo/models/res.partner";
 
 @Component({
     selector: 'page-customers',
     templateUrl: 'customers.html'
 })
-export class CustomersPage {
+export class CustomersPage extends BaseListView<Partner> {
 
     constructor(
         public navCtrl: NavController,
-        public navParams: NavParams,
-        public pouch: PouchService
-    ) { }
+        public navParams: NavParams
+    ) {
+        super(Partner, ["customer", "=", true]);
+     }
 
     ionViewDidLoad() {
         console.log('ionViewDidLoad CustomersPage');
-
-        this.loadCustomers();
     }
 
-    /**
-     * 
-     */
-    loadCustomers(): void {
-        this.pouch.getAll('res.partner').subscribe(results => { 
-            console.log(results.docs.shift().records);
-        });
+    test(): void {
+        console.log("hbasbjas");
     }
 }

+ 32 - 1
src/pages/orders/orders.html

@@ -10,6 +10,37 @@
 
 </ion-header>
 
-<ion-content padding>
+<ion-content>
+    <ion-list [virtualScroll]="getItems()" approxItemHeight="35px">
 
+		<ion-item *virtualItem="let item">
+			<h2>{{ item.name }}</h2>
+
+            <p>
+                <strong>Cantidad:</strong>
+                {{ item.cart_quantity }}
+            </p>
+
+            <p>
+                <strong>Subtotal:</strong>
+                {{ item.amount_untaxed }}
+            </p>
+            
+            <p>
+                <strong>Impuestos:</strong>
+                {{ item.amount_tax }}
+            </p>
+            
+            <p>
+                <strong>Total:</strong>
+                {{ item.amount_total }}
+            </p>
+
+            <p>
+                <strong>Fecha:</strong>
+                {{ item.date_order }}
+            </p>
+		</ion-item>
+
+	</ion-list>
 </ion-content>

+ 15 - 13
src/pages/orders/orders.ts

@@ -1,22 +1,24 @@
 import { Component } from '@angular/core';
 import { NavController, NavParams } from 'ionic-angular';
 
-/*
-  Generated class for the Orders page.
+import { BaseListView } from "../../base/base-list-view";
+import { SaleOrder } from "../../odoo/models/sale.order";
 
-  See http://ionicframework.com/docs/v2/components/#navigation for more info on
-  Ionic pages and navigation.
-*/
 @Component({
-  selector: 'page-orders',
-  templateUrl: 'orders.html'
+    selector: 'page-orders',
+    templateUrl: 'orders.html'
 })
-export class OrdersPage {
+export class OrdersPage extends BaseListView<SaleOrder> {
 
-  constructor(public navCtrl: NavController, public navParams: NavParams) {}
-
-  ionViewDidLoad() {
-    console.log('ionViewDidLoad OrdersPage');
-  }
+    constructor(
+        public navCtrl: NavController,
+        public navParams: NavParams
+    ) { 
+        super(SaleOrder);
+        // this.setFilters(navParams.data.filters);
+    }
 
+    ionViewDidLoad() {
+        console.log('ionViewDidLoad OrdersPage');
+    }
 }

+ 21 - 1
src/pages/products/products.html

@@ -10,6 +10,26 @@
 
 </ion-header>
 
-<ion-content padding>
+<ion-content>
+    <ion-list [virtualScroll]="getItems()" approxItemHeight="35px">
 
+		<ion-item *virtualItem="let item">
+
+			<ion-thumbnail item-left>
+                <img src="./assets/images/product.png" *ngIf="!item.image_medium"/>
+				<img [src]="item.image_medium | sanitizeUrl" *ngIf="item.image_medium"/>
+			</ion-thumbnail>
+
+			<h2>{{ item.name }}</h2>
+			<p>
+				<strong>Precio:</strong>
+				{{ item.list_price }}
+			</p>
+            <p>
+				<strong>Cantidad:</strong>
+				{{ item.qty_available }}
+			</p>
+		</ion-item>
+
+	</ion-list>
 </ion-content>

+ 7 - 2
src/pages/products/products.ts

@@ -1,16 +1,21 @@
 import { Component } from '@angular/core';
 import { NavController, NavParams } from 'ionic-angular';
 
+import { BaseListView } from "../../base/base-list-view";
+import { ProductTemplate } from "../../odoo/models/product.template";
+
 @Component({
     selector: 'page-products',
     templateUrl: 'products.html'
 })
-export class ProductsPage {
+export class ProductsPage extends BaseListView<ProductTemplate> {
 
     constructor(
         public navCtrl: NavController,
         public navParams: NavParams
-    ) { }
+    ) { 
+        super(ProductTemplate);
+    }
 
     /**
      *

+ 11 - 3
src/pages/tools/tools.ts

@@ -6,6 +6,8 @@ import { LoginPage } from "../login/login";
 import { SyncService } from "../../services/sync-service";
 import { PouchService } from "../../services/pouch-service";
 
+import { getMetadataStorage } from "../../odoo/utils/metadata-storage";
+
 @Component({
     selector: 'page-tools',
     templateUrl: 'tools.html'
@@ -54,8 +56,11 @@ export class ToolsPage {
      *
      */
     syncData(): void {
+        let numberOfModels = getMetadataStorage().models.length;
+        let numberOfUpdated = 0;
+
         let loader = this.loadingCtrl.create({
-            content: "Actualizando datos, espere..."
+            content: "Actualizando " + numberOfUpdated + " de " + numberOfModels + " , espere..."
         });
         loader.present();
 
@@ -64,13 +69,16 @@ export class ToolsPage {
         });
 
         this.sync.do().subscribe(s => {
-            toast.setMessage("Datos actualizados correctamente");
+            numberOfUpdated++;
+
+            loader.setContent("Actualizando " + numberOfUpdated + " de " + numberOfModels + " , espere...");
         }, e => {
             console.log(e);
-
             toast.setMessage("No se pudo actualizar los datos");
         }, () => {
             loader.dismiss();
+
+            toast.setMessage("Datos actualizados correctamente");
             toast.present();
         });
     }

+ 12 - 0
src/pipes/image.ts

@@ -0,0 +1,12 @@
+import { Pipe, PipeTransform } from '@angular/core';
+import { DomSanitizer, SafeUrl } from '@angular/platform-browser';
+
+@Pipe({ name: 'sanitizeUrl' })
+export class ImageSanitizerPipe implements PipeTransform {
+
+    constructor(public dom: DomSanitizer) {}
+
+    transform(base64: string): SafeUrl {
+        return this.dom.bypassSecurityTrustUrl("data:image/jpeg;base64," + base64);
+    }
+}