Browse Source

módulo de productos totalmente implementado

robert2206 8 years ago
parent
commit
90f94f5074

+ 1 - 0
package.json

@@ -14,6 +14,7 @@
   },
   "dependencies": {
     "@ionic/storage": "^1.0.3",
+    "async": "^2.1.2",
     "ionic-angular": "^2.0.0-rc.0",
     "ionic-native": "^2.0.3",
     "ionicons": "^3.0.0",

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

@@ -17,7 +17,7 @@ import { TaskListPage } from '../pages/task-list/task-list';
 
 import { ToolsPage } from '../pages/tools/tools';
 import { SettingsPage } from '../pages/settings/settings';
-import { AboutPage } from '../pages/about/about'
+import { AboutPage } from '../pages/about/about';
 
 @Component({
     templateUrl: 'app.html'
@@ -27,73 +27,86 @@ export class MyApp {
 
     rootPage: any = LoginPage;
     homePage: any = HomePage;
-    entries: Array<{ title: string, pages: Array<{ icon: string, title: string, component: any }> }>;
+    entries: Array<{ visible: boolean, title: string, pages: Array<{ visible: boolean, title: string, icon: string, component: any }> }>;
 
     constructor(public platform: Platform) {
         this.initializeApp();
 
         this.entries = [
             {
-                title: 'Ventas',
+                visible: true,
+                title: "Ventas",
                 pages: [
                     {
+                        visible: false,
+                        title: "Clientes",
                         icon: "people",
-                        title: 'Clientes',
                         component: CustomerListPage
                     },
                     {
-                        icon: "cube",
+                        visible: true,
                         title: 'Productos',
+                        icon: "cube",
                         component: ProductListPage
                     },
                     {
-                        icon: "bulb",
+                        visible: false,
                         title: 'Iniciativas',
+                        icon: "bulb",
                         component: LeadListPage
                     },
                     {
+                        visible: false,
+                        title: "Oportunidades",
                         icon: "ribbon",
-                        title: 'Oportunidades',
                         component: OpportunityListPage
                     },
                     {
+                        visible: false,
+                        title: "Llamadas",
                         icon: "call",
-                        title: 'Llamadas',
                         component: CallListPage
                     }
                 ]
             },
             {
-                title: 'Proyectos',
+                visible: false,
+                title: "Proyectos",
                 pages: [
                     {
+                        visible: true,
+                        title: "Proyectos",
                         icon: "briefcase",
-                        title: 'Proyectos',
                         component: ProjectListPage
                     },
                     {
+                        visible: true,
+                        title: "Tareas",
                         icon: "calendar",
-                        title: 'Tareas',
                         component: TaskListPage
                     }
                 ]
             },
             {
-                title: 'Herramientas',
+                visible: true,
+                title: "Herramientas",
                 pages: [
                     {
-                        icon: "build",
+                        visible: true,
                         title: 'Herramientas',
+                        icon: "build",
                         component: ToolsPage
                     },
                     {
+                        visible: false,
+                        title: "Preferencias",
                         icon: "settings",
-                        title: 'Preferencias',
                         component: SettingsPage
                     },
                     {
+                        visible: true,
+                        title: "Acerca",
                         icon: "information-circle",
-                        title: 'Acerca',
                         component: AboutPage
                     }
                 ]

+ 2 - 2
src/app/app.html

@@ -12,9 +12,9 @@
                 Inicio
             </button>
 
-            <div *ngFor="let e of entries">
+            <div *ngFor="let e of (entries | viewMenu: true)">
                 <ion-list-header>{{ e.title }}</ion-list-header>
-                <button ion-item menuClose *ngFor="let p of e.pages" (click)="openPage(p)">
+                <button ion-item menuClose *ngFor="let p of (e.pages | viewMenu: true)" (click)="openPage(p)">
                     <ion-icon color="primary" name="{{ p.icon }}" style="padding-right: 25px;"></ion-icon>
                     {{ p.title }}
                 </button>

+ 4 - 1
src/app/app.module.ts

@@ -27,6 +27,8 @@ import { NetworkProvider } from '../providers/network-provider';
 import { PreferencesProvider } from '../providers/preferences-provider';
 import { ToolsProvider } from '../providers/tools-provider';
 
+import { ViewMenu } from '../pipes/view-menu-pipe';
+
 @NgModule({
     declarations: [
         MyApp,
@@ -43,7 +45,8 @@ import { ToolsProvider } from '../providers/tools-provider';
         TaskListPage,
         ToolsPage,
         SettingsPage,
-        AboutPage
+        AboutPage,
+        ViewMenu
     ],
     imports: [
         IonicModule.forRoot(MyApp)

+ 1 - 1
src/models/product.ts

@@ -8,7 +8,7 @@ export class Product {
     image_medium: string = null;
     image_small: string = null;
     name: string = null;
-    list_price: number = 0;
+    list_price: number = 1;
     purchase_ok: boolean =  true;
     qty_available: number = 0;
     rental: boolean = false;

+ 3 - 1
src/pages/about/about.html

@@ -13,5 +13,7 @@
 </ion-header>
 
 <ion-content padding>
-
+    <img src="./assets/images/logo.png" />
+    <h1 text-center>Odoo Mobile</h1>
+    <p text-center>Versión 1.0 (alpha)</p>
 </ion-content>

+ 15 - 0
src/pages/about/about.scss

@@ -1,3 +1,18 @@
 page-about {
+    img {
+        display: block;
+        width: 80pt;
+        margin: 50px auto;
+        /*filter: brightness(0) invert(1);*/
+    }
 
+    h1 {
+        font-size: 18pt;
+        color: #909090;
+    }
+
+    p {
+        font-size: 8pt;
+        color: #d3d3d3;   
+    }
 }

+ 1 - 1
src/pages/product-details/product-details.ts

@@ -20,7 +20,7 @@ export class ProductDetailsPage {
         image_medium: null,
         image_small: null,
         name: null,
-        list_price: 0,
+        list_price: 1,
         purchase_ok: true,
         qty_available: 0,
         rental: false,

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

@@ -42,10 +42,10 @@
 <ion-content>
 
     <ion-card *ngFor="let p of list(); let i = index;" (tap)="openItem(i)" (press)="toggleDelete(i)">
-        <button ion-item>
+        <ion-item>
             <ion-avatar item-left>
                 <img src="./assets/images/product.png" *ngIf="!p.image_medium"/>
-                <img src="data:image/jpeg;base64,{{ p.image }}" *ngIf="p.image_medium"/>
+                <img src="data:image/jpeg;base64,{{ p.image_medium }}" *ngIf="p.image_medium"/>
             </ion-avatar>
 
             <h2>{{ p.name }}</h2>
@@ -55,14 +55,13 @@
                 {{ 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>
-        </button>
+        </ion-item>
 
         <ion-row>
             <ion-col>

+ 3 - 1
src/pages/product-list/product-list.ts

@@ -27,7 +27,9 @@ export class ProductListPage extends DefaultListable<Product> implements INaviga
      */
     initialize(): void {
         this.dataProvider.getAll("product").then(r => { 
-            this.elements = r.products;
+            this.elements = r.products.filter(item => {
+                return item.doc_state !== "deleted"; 
+            });
         });
     }
 

+ 11 - 0
src/pipes/view-menu-pipe.ts

@@ -0,0 +1,11 @@
+import { Pipe, PipeTransform } from '@angular/core';
+
+@Pipe({ name: 'viewMenu' })
+export class ViewMenu implements PipeTransform {
+
+    transform(menus: Array<any>, visible: boolean) {
+        return menus.filter(item => { 
+            return item.visible == visible;
+        });
+    }
+}

+ 50 - 28
src/providers/data-provider.ts

@@ -1,5 +1,6 @@
 import { Injectable } from '@angular/core';
 import PouchDB from 'pouchdb';
+import each from 'async/each';
 import * as Relational from 'relational-pouch';
 
 PouchDB.plugin(Relational);
@@ -76,11 +77,33 @@ export class DataProvider {
     }
 
     /**
-     *
+     * Save object or array of objects to database
+     * @argument type: string
+     * @argument data: object or array of objects
      */
     save(type: string, data: any): Promise<any> {
         return new Promise((resolve, reject) => {
-            resolve(this.data.rel.save(type, data));
+           
+            if (data instanceof Array) {
+
+                each(data, (i, c) => { 
+                    this.data.rel.save(type, i).then(() => { 
+                        c();
+                    }).catch(e => { 
+                        c(e);
+                    });
+                }, e => { 
+                    if (e) {
+                        reject(e);
+                    } else {
+                        resolve();
+                    }
+                });
+
+            } else {
+                 resolve(this.data.rel.save(type, data));
+            }
+
         });
     }
 
@@ -89,7 +112,7 @@ export class DataProvider {
      */
     delete(type: string, data: any): any {
         return new Promise((resolve, reject) => {
-            resolve(data.remote_id ? this.data.rel.del(type, data) : this.save(type, data));
+            resolve(data.remote_id ? this.save(type, data) : this.data.rel.del(type, data));
         });
     }
 
@@ -97,32 +120,24 @@ export class DataProvider {
      *
      */
     deleteAll(type: string): Promise<any> {
-        return new Promise((res, rej) => { 
-            
+        return new Promise((resolve, reject) => { 
             this.getAll(type).then(data => {
-                return data;
-            }).then(data => {
-                console.log(data);
-                
-                let promises: Array<Promise<any>> = [];
-
-                for (let i = 0; i < data.length; i++) {
-                    promises.push(new Promise((resolve, reject) => {
-                        resolve(this.data.rel.del(type, data[i]));
-                    }));
-                }
-
-                return promises;
-            }).then(p => {
-                console.log(p);
-                
-                return Promise.all(p);    
-            }).then(() => { 
-                res(true);
-            }).catch(e => {
-                rej(e);
+                each(data[type], (i, c) => { 
+                    this.data.rel.del(type, i).then(r => {
+                        c();
+                    }).catch(e => {
+                        c(e);
+                    });
+                }, e => { 
+                    if (e) {
+                        reject(e);
+                    } else {
+                        resolve();
+                    }
+                });
+            }).catch(e => { 
+                reject(e);    
             });
-            
         });    
     }
 
@@ -143,5 +158,12 @@ export class DataProvider {
         return new Promise((resolve, reject) => {
             resolve(this.data.destroy());
         });
-    } 
+    }
+
+    /**
+     *
+     */
+    parseDocID(id: string): any {
+        return this.data.rel.parseDocID(id);
+    }
 }

+ 6 - 8
src/providers/odoo-provider.ts

@@ -12,11 +12,11 @@ import 'rxjs/add/observable/forkJoin';
 @Injectable()
 export class OdooProvider {
 
-    private url: string;
+    url: string;
 
     constructor(
-        private http: Http,
-        private preferencesProvider: PreferencesProvider
+        public http: Http,
+        public preferencesProvider: PreferencesProvider
     ) {
         this.url = preferencesProvider.getHost();
         this.normalizeUrl();
@@ -79,8 +79,6 @@ export class OdooProvider {
      *
      */
     get(resource: string, id?: number, filter?: Array<[string, string]>): Promise<any> {
-        this.url = this.url + resource;
-
         let headers = new Headers({
             'Authorization': 'JWT ' + this.preferencesProvider.getToken()
         });
@@ -88,7 +86,7 @@ export class OdooProvider {
         let options = new RequestOptions({ headers: headers });
 
         return new Promise((resolve, reject) => {
-            this.http.get(this.url, options).toPromise().then(r => { 
+            this.http.get(this.url + resource, options).toPromise().then(r => { 
                 resolve(r.json());
             }).catch(e => { 
                 reject(e.json());
@@ -114,7 +112,7 @@ export class OdooProvider {
         let toSend: Array<Observable<Response>> = [];
         for (let i = 0; i < data.length; i++) {
             this.encodeData(data[i]);
-            toSend.push(this.http.put(this.url + resource + '/' + data[i].id, this.encodeData(data[i]), options));
+            toSend.push(this.http.put(this.url + resource + '/' + data[i].remote_id, this.encodeData(data[i]), options));
         }
 
         return new Promise((resolve, reject) => { 
@@ -144,7 +142,7 @@ export class OdooProvider {
         let toSend: Array<Observable<Response>> = [];
         for (let i = 0; i < data.length; i++) {
             this.encodeData(data[i]);
-            toSend.push(this.http.delete(this.url + resource + '/' + data[i].id, options));
+            toSend.push(this.http.delete(this.url + resource + '/' + data[i].remote_id, options));
         }
 
         return new Promise((resolve, reject) => { 

+ 31 - 16
src/providers/sync-provider.ts

@@ -1,7 +1,7 @@
 import { Injectable } from '@angular/core';
 import { DataProvider } from './data-provider';
 import { OdooProvider } from './odoo-provider';
-import { NetworkProvider } from './network-provider'
+import { NetworkProvider } from './network-provider';
 
 @Injectable()    
 export class SyncProvider {
@@ -47,7 +47,7 @@ export class SyncProvider {
         return new Promise((resolve, reject) => {
             this.dataProvider.getAll("product").then(r => {
                 resolve(r.products.filter(item => {
-                    return item.doc_state === "created";
+                    return item.doc_state === "created" || (item.doc_state === "updated" && !item.remote_id);
                 }));
             }).catch(e => {
                 reject(e);
@@ -55,14 +55,21 @@ export class SyncProvider {
         });
     }
 
+    private 
+
     /**
      *
      */
     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;
+            this.dataProvider.getAll("product").then(data => {
+                let products = data.products.filter(item => {
+                    return item.doc_state === "updated" && item.remote_id;
+                });
+                
+                resolve(products.map(item => {
+                    delete item.id;
+                    return item;
                 }));
             }).catch(e => {
                 reject(e);
@@ -75,9 +82,14 @@ export class SyncProvider {
      */
     private getDeletedProducts(): Promise<any> {
         return new Promise((resolve, reject) => { 
-            this.dataProvider.getAll("product").then(r => { 
-                resolve(r.products.filter(item => {
+            this.dataProvider.getAll("product").then(data => {
+                let products = data.products.filter(item => { 
                     return item.doc_state === "deleted";
+                });
+                
+                resolve(products.map(item => {
+                    delete item.id;
+                    return item;
                 }));
             }).catch(e => { 
                 reject(e);
@@ -89,17 +101,20 @@ export class SyncProvider {
      *
      */
     private storeProducts(products: Array<any>): Promise<any> {
-        if (products.length == 0) {
-            return;
-        }
-
         return new Promise((resolve, reject) => {
-            this.dataProvider.deleteAll("products").then(r => { 
-                return r;
-            }).then(ok => {
-                console.log(ok);
+            this.dataProvider.deleteAll("products").then(() => {
+                return;
+            }).then(() => {
                 
-                resolve(ok);
+                return this.dataProvider.save("products", products.map(item => {
+                    item.remote_id = item.id;
+                    item.doc_state = "sync";
+                    delete item.id;
+
+                    return item;
+                }));
+            }).then(() => { 
+                resolve();
             }).catch(e => { 
                 reject(e);    
             });

+ 1 - 0
typings/index.d.ts

@@ -1,2 +1,3 @@
 /// <reference path="globals/pouchdb-adapter-websql/index.d.ts" />
 /// <reference path="globals/pouchdb/index.d.ts" />
+/// <reference path="modules/async/index.d.ts" />

+ 207 - 0
typings/modules/async/index.d.ts

@@ -0,0 +1,207 @@
+// Generated by typings
+// Source: https://raw.githubusercontent.com/types/npm-async/ff63908a70ec51b775d9a6b8afac9945b12fbe08/2/index.d.ts
+declare module 'async' {
+// Type definitions for Async 2.0.1
+// Project: https://github.com/caolan/async
+// Definitions by: Boris Yankov <https://github.com/borisyankov/>, Arseniy Maximov <https://github.com/kern0>, Joe Herman <https://github.com/Penryn>
+// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
+
+interface Dictionary<T> { [key: string]: T; }
+
+interface ErrorCallback { (err?: Error): void; }
+interface AsyncResultCallback<T> { (err: Error, result: T): void; }
+interface AsyncResultArrayCallback<T> { (err: Error, results: T[]): void; }
+interface AsyncResultObjectCallback<T> { (err: Error, results: Dictionary<T>): void; }
+
+interface AsyncFunction<T> { (callback: (err?: Error, result?: T) => void): void; }
+interface AsyncIterator<T> { (item: T, callback: ErrorCallback): void; }
+interface AsyncForEachOfIterator<T> { (item: T, key: number|string, callback: ErrorCallback): void; }
+interface AsyncResultIterator<T, R> { (item: T, callback: AsyncResultCallback<R>): void; }
+interface AsyncMemoIterator<T, R> { (memo: R, item: T, callback: AsyncResultCallback<R>): void; }
+interface AsyncBooleanIterator<T> { (item: T, callback: (err: string, truthValue: boolean) => void): void; }
+
+interface AsyncWorker<T> { (task: T, callback: ErrorCallback): void; }
+interface AsyncVoidFunction { (callback: ErrorCallback): void; }
+
+interface AsyncQueue<T> {
+    length(): number;
+    started: boolean;
+    running(): number;
+    idle(): boolean;
+    concurrency: number;
+    push(task: T, callback?: ErrorCallback): void;
+    push(task: T[], callback?: ErrorCallback): void;
+    unshift(task: T, callback?: ErrorCallback): void;
+    unshift(task: T[], callback?: ErrorCallback): void;
+    saturated: () => any;
+    empty: () => any;
+    drain: () => any;
+    paused: boolean;
+    pause(): void
+    resume(): void;
+    kill(): void;
+    workersList(): {
+        data: T,
+        callback: Function
+    }[];
+    error(error: Error, data: any): void;
+    unsaturated(): void;
+    buffer: number;
+}
+
+interface AsyncPriorityQueue<T> {
+    length(): number;
+    concurrency: number;
+    started: boolean;
+    paused: boolean;
+    push(task: T, priority: number, callback?: AsyncResultArrayCallback<T>): void;
+    push(task: T[], priority: number, callback?: AsyncResultArrayCallback<T>): void;
+    saturated: () => any;
+    empty: () => any;
+    drain: () => any;
+    running(): number;
+    idle(): boolean;
+    pause(): void;
+    resume(): void;
+    kill(): void;
+    workersList(): {
+        data: T,
+        priority: number,
+        callback: Function
+    }[];
+    error(error: Error, data: any): void;
+    unsaturated(): void;
+    buffer: number;
+}
+
+interface AsyncCargo {
+    length(): number;
+    payload: number;
+    push(task: any, callback? : Function): void;
+    push(task: any[], callback? : Function): void;
+    saturated(): void;
+    empty(): void;
+    drain(): void;
+    idle(): boolean;
+    pause(): void;
+    resume(): void;
+    kill(): void;
+}
+
+interface Async {
+
+    // Collections
+    each<T>(arr: T[], iterator: AsyncIterator<T>, callback?: ErrorCallback): void;
+    eachSeries<T>(arr: T[], iterator: AsyncIterator<T>, callback?: ErrorCallback): void;
+    eachLimit<T>(arr: T[], limit: number, iterator: AsyncIterator<T>, callback?: ErrorCallback): void;
+    forEachOf(obj: any, iterator: (item: any, key: string|number, callback?: ErrorCallback) => void, callback: ErrorCallback): void;
+    forEachOf<T>(obj: T[], iterator: AsyncForEachOfIterator<T>, callback?: ErrorCallback): void;
+    forEachOfSeries(obj: any, iterator: (item: any, key: string|number, callback?: ErrorCallback) => void, callback: ErrorCallback): void;
+    forEachOfSeries<T>(obj: T[], iterator: AsyncForEachOfIterator<T>, callback?: ErrorCallback): void;
+    forEachOfLimit(obj: any, limit: number, iterator: (item: any, key: string|number, callback?: ErrorCallback) => void, callback: ErrorCallback): void;
+    forEachOfLimit<T>(obj: T[], limit: number, iterator: AsyncForEachOfIterator<T>, callback?: ErrorCallback): void;
+    map<T, R>(arr: T[], iterator: AsyncResultIterator<T, R>, callback?: AsyncResultArrayCallback<R>): any;
+    mapSeries<T, R>(arr: T[], iterator: AsyncResultIterator<T, R>, callback?: AsyncResultArrayCallback<R>): any;
+    mapLimit<T, R>(arr: T[], limit: number, iterator: AsyncResultIterator<T, R>, callback?: AsyncResultArrayCallback<R>): any;
+    mapValuesLimit<T, R>(obj: {[name: string]: T}, limit: number, iteratee: (value: string, key: T, callback: AsyncResultCallback<R>) => void, callback: AsyncResultCallback<R[]>): void;
+    mapValues<T, R>(obj: {[name: string]: T}, iteratee: (value: string, key: T, callback: AsyncResultCallback<R>) => void, callback: AsyncResultCallback<R[]>): void;
+    mapValuesSeries: typeof async.mapValues;
+    filter<T>(arr: T[], iterator: AsyncBooleanIterator<T>, callback?: AsyncResultArrayCallback<T>): any;
+    select<T>(arr: T[], iterator: AsyncBooleanIterator<T>, callback?: AsyncResultArrayCallback<T>): any;
+    filterSeries<T>(arr: T[], iterator: AsyncBooleanIterator<T>, callback?: AsyncResultArrayCallback<T>): any;
+    selectSeries<T>(arr: T[], iterator: AsyncBooleanIterator<T>, callback?: AsyncResultArrayCallback<T>): any;
+    filterLimit<T>(arr: T[], limit: number, iterator: AsyncBooleanIterator<T>, callback?: AsyncResultArrayCallback<T>): any;
+    selectLimit<T>(arr: T[], limit: number, iterator: AsyncBooleanIterator<T>, callback?: AsyncResultArrayCallback<T>): any;
+    reject<T>(arr: T[], iterator: AsyncBooleanIterator<T>, callback?: AsyncResultArrayCallback<T>): any;
+    rejectSeries<T>(arr: T[], iterator: AsyncBooleanIterator<T>, callback?: AsyncResultArrayCallback<T>): any;
+    rejectLimit<T>(arr: T[], limit: number, iterator: AsyncBooleanIterator<T>, callback?: AsyncResultArrayCallback<T>): any;
+    reduce<T, R>(arr: T[], memo: R, iterator: AsyncMemoIterator<T, R>, callback?: AsyncResultCallback<R>): any;
+    inject<T, R>(arr: T[], memo: R, iterator: AsyncMemoIterator<T, R>, callback?: AsyncResultCallback<R>): any;
+    foldl<T, R>(arr: T[], memo: R, iterator: AsyncMemoIterator<T, R>, callback?: AsyncResultCallback<R>): any;
+    reduceRight<T, R>(arr: T[], memo: R, iterator: AsyncMemoIterator<T, R>, callback: AsyncResultCallback<R>): any;
+    foldr<T, R>(arr: T[], memo: R, iterator: AsyncMemoIterator<T, R>, callback: AsyncResultCallback<R>): any;
+    detect<T>(arr: T[], iterator: AsyncBooleanIterator<T>, callback?: AsyncResultCallback<T>): any;
+    find: typeof async.detect;
+    detectSeries<T>(arr: T[], iterator: AsyncBooleanIterator<T>, callback?: AsyncResultCallback<T>): any;
+    findSeries: typeof async.detectSeries;
+    detectLimit<T>(arr: T[], limit: number, iterator: AsyncBooleanIterator<T>, callback?: AsyncResultCallback<T>): any;
+    findLimit: typeof async.detectLimit;
+    sortBy<T, V>(arr: T[], iterator: AsyncResultIterator<T, V>, callback?: AsyncResultArrayCallback<T>): any;
+    some<T>(arr: T[], iterator: AsyncBooleanIterator<T>, callback?: (result: boolean) => void): any;
+    someLimit<T>(arr: T[], limit: number, iterator: AsyncBooleanIterator<T>, callback?: (result: boolean) => void): any;
+    anyLimit: typeof async.someLimit;
+    someSeries<T>(arr: T[], iterator: AsyncBooleanIterator<T>, callback?: (result: boolean) => void): any;
+    anySeries: typeof async.someSeries;
+    any<T>(arr: T[], iterator: AsyncBooleanIterator<T>, callback?: (result: boolean) => void): any;
+    every<T>(arr: T[], iterator: AsyncBooleanIterator<T>, callback?: (result: boolean) => any): any;
+    everyLimit<T>(arr: T[], limit: number, iterator: AsyncBooleanIterator<T>, callback?: (result: boolean) => any): any;
+    all<T>(arr: T[], iterator: AsyncBooleanIterator<T>, callback?: (result: boolean) => any): any;
+    concat<T, R>(arr: T[], iterator: AsyncResultIterator<T, R[]>, callback?: AsyncResultArrayCallback<R>): any;
+    concatSeries<T, R>(arr: T[], iterator: AsyncResultIterator<T, R[]>, callback?: AsyncResultArrayCallback<R>): any;
+
+    // Control Flow
+    series<T>(tasks: AsyncFunction<T>[], callback?: AsyncResultArrayCallback<T>): void;
+    series<T>(tasks: Dictionary<AsyncFunction<T>>, callback?: AsyncResultObjectCallback<T>): void;
+    parallel<T>(tasks: Array<AsyncFunction<T>>, callback?: AsyncResultArrayCallback<T>): void;
+    parallel<T>(tasks: Dictionary<AsyncFunction<T>>, callback?: AsyncResultObjectCallback<T>): void;
+    parallelLimit<T>(tasks: Array<AsyncFunction<T>>, limit: number, callback?: AsyncResultArrayCallback<T>): void;
+    parallelLimit<T>(tasks: Dictionary<AsyncFunction<T>>, limit: number, callback?: AsyncResultObjectCallback<T>): void;
+    whilst(test: () => boolean, fn: AsyncVoidFunction, callback: (err: any) => void): void;
+    doWhilst(fn: AsyncVoidFunction, test: () => boolean, callback: (err: any) => void): void;
+    until(test: () => boolean, fn: AsyncVoidFunction, callback: (err: any) => void): void;
+    doUntil(fn: AsyncVoidFunction, test: () => boolean, callback: (err: any) => void): void;
+    during(test: (testCallback : (error: Error, truth: boolean) => void) => void, fn: AsyncVoidFunction, callback: (err: any) => void): void;
+    doDuring(fn: AsyncVoidFunction, test: (testCallback: (error: Error, truth: boolean) => void) => void, callback: (err: any) => void): void;
+    forever(next: (errCallback : (err: Error) => void) => void, errBack: (err: Error) => void) : void;
+    waterfall(tasks: Function[], callback?: (err: Error, results?: any) => void): void;
+    compose(...fns: Function[]): Function;
+    seq(...fns: Function[]): Function;
+    applyEach(fns: Function[], argsAndCallback: any[]): void;           // applyEach(fns, args..., callback). TS does not support ... for a middle argument. Callback is optional.
+    applyEachSeries(fns: Function[], argsAndCallback: any[]): void;     // applyEachSeries(fns, args..., callback). TS does not support ... for a middle argument. Callback is optional.
+    queue<T>(worker: AsyncWorker<T>, concurrency?: number): AsyncQueue<T>;
+    priorityQueue<T>(worker: AsyncWorker<T>, concurrency: number): AsyncPriorityQueue<T>;
+    cargo(worker : (tasks: any[], callback : ErrorCallback) => void, payload? : number) : AsyncCargo;
+    auto(tasks: any, concurrency?: number, callback?: (error: Error, results: any) => void): void;
+    autoInject(tasks: any, callback?: (error: Error, results: any) => void): void;
+    retry<T>(opts: number, task: (callback : AsyncResultCallback<T>, results: any) => void, callback: (error: Error, results: any) => void): void;
+    retry<T>(opts: { times: number, interval: number|((retryCount: number) => number) }, task: (callback: AsyncResultCallback<T>, results : any) => void, callback: (error: Error, results: any) => void): void;
+    retryable<T>(opts: number | {times: number, interval: number}, task: AsyncFunction<T>): AsyncFunction<T>;
+    apply(fn: Function, ...args: any[]): AsyncFunction<any>;
+    nextTick(callback: Function, ...args: any[]): void;
+    setImmediate: typeof async.nextTick;
+
+    allLimit<T>(arr: T[], limit: number, iteratee: AsyncBooleanIterator<T>, cb?: (result: boolean) => any) : any;
+    everySeries<T>(arr: T[], iteratee: AsyncBooleanIterator<T>, cb?: (result: boolean) => any) : any
+    allSeries: typeof async.everySeries;
+
+    reflect<T>(fn: AsyncFunction<T>) : (callback: (err: void, result: {error?: Error, value?: T}) => void) => void;
+    reflectAll<T>(tasks: AsyncFunction<T>[]): ((callback: (err: void, result: {error?: Error, value?: T}) => void) => void)[];
+
+    timeout<T>(fn: AsyncFunction<T>, milliseconds: number, info: any): AsyncFunction<T>;
+
+    times<T> (n: number, iterator: AsyncResultIterator<number, T>, callback: AsyncResultArrayCallback<T>): void;
+    timesSeries<T>(n: number, iterator: AsyncResultIterator<number, T>, callback: AsyncResultArrayCallback<T>): void;
+    timesLimit<T>(n: number, limit: number, iterator: AsyncResultIterator<number, T>, callback: AsyncResultArrayCallback<T>): void;
+
+    transform<T, R>(arr: T[], iteratee: (acc: R[], item: T, key: string, callback: (error?: Error) => void) => void): void;
+    transform<T, R>(arr: T[], acc: R[], iteratee: (acc: R[], item: T, key: string, callback: (error?: Error) => void) => void): void;
+    transform<T, R>(arr: {[key: string] : T}, iteratee: (acc: {[key: string] : R}, item: T, key: string, callback: (error?: Error) => void) => void): void;
+    transform<T, R>(arr: {[key: string] : T}, acc: {[key: string] : R}, iteratee: (acc: {[key: string] : R}, item: T, key: string, callback: (error?: Error) => void) => void): void;
+
+    race<T>(tasks: (AsyncFunction<T>)[], callback: AsyncResultCallback<T>) : void;
+
+    // Utils
+    memoize(fn: Function, hasher?: Function): Function;
+    unmemoize(fn: Function): Function;
+    ensureAsync(fn: (... argsAndCallback: any[]) => void): Function;
+    constant(...values: any[]): Function;
+    asyncify(fn: Function): Function;
+    wrapSync(fn: Function): Function;
+    log(fn: Function, ...args: any[]): void;
+    dir(fn: Function, ...args: any[]): void;
+}
+
+var async: Async;
+
+export = async;
+}

+ 11 - 0
typings/modules/async/typings.json

@@ -0,0 +1,11 @@
+{
+  "resolution": "main",
+  "tree": {
+    "src": "https://raw.githubusercontent.com/types/npm-async/ff63908a70ec51b775d9a6b8afac9945b12fbe08/2/typings.json",
+    "raw": "registry:npm/async#2.0.1+20160815105832",
+    "main": "index.d.ts",
+    "version": "2.0.1",
+    "name": "async",
+    "type": "typings"
+  }
+}