diff --git a/overlord/package.json b/overlord/package.json
index 6f230f6c..6fe8d3be 100644
--- a/overlord/package.json
+++ b/overlord/package.json
@@ -26,6 +26,7 @@
     "@angular/router": "^7.1.0",
     "@ngx-loading-bar/http-client": "^3.0.0",
     "@ngx-loading-bar/router": "^3.0.0",
+    "angular2-hotkeys": "^2.1.4",
     "core-js": "^2.5.7",
     "hammerjs": "^2.0.8",
     "mathjs": "^5.0.4",
diff --git a/overlord/src/app/app.module.ts b/overlord/src/app/app.module.ts
index 60a2088c..dcfa31ec 100644
--- a/overlord/src/app/app.module.ts
+++ b/overlord/src/app/app.module.ts
@@ -66,6 +66,7 @@ import {AttendanceModule} from './attendance/attendance.module';
 import {EmployeeAttendanceModule} from './employee-attendance/employee-attendance.module';
 import {RawMaterialCostModule} from './raw-material-cost/raw-material-cost.module';
 import {FlexLayoutModule} from "@angular/flex-layout";
+import {HotkeyModule} from "angular2-hotkeys";
 
 registerLocaleData(enIN);
 
@@ -81,6 +82,7 @@ registerLocaleData(enIN);
     BrowserModule,
     BrowserAnimationsModule,
     FlexLayoutModule.withConfig({useColumnBasisZero: true}),
+    HotkeyModule.forRoot(),
     HttpClientModule,
     LayoutModule,
     MatButtonModule,
diff --git a/overlord/src/app/issue/issue.component.html b/overlord/src/app/issue/issue.component.html
index f1d987e0..4d01f7c7 100644
--- a/overlord/src/app/issue/issue.component.html
+++ b/overlord/src/app/issue/issue.component.html
@@ -7,8 +7,8 @@
       <div fxLayout="row" fxLayoutAlign="space-around start" fxLayout.lt-md="column" fxLayoutGap="20px"
            fxLayoutGap.lt-md="0px">
         <mat-form-field fxFlex="40">
-          <input matInput [matDatepicker]="date" (focus)="date.open()" placeholder="Date" formControlName="date"
-                 autocomplete="off">
+          <input matInput [matDatepicker]="date" placeholder="Date" formControlName="date" autocomplete="off"
+                 #dateElement (focus)="dateElement.select()">
           <mat-datepicker-toggle matSuffix [for]="date"></mat-datepicker-toggle>
           <mat-datepicker #date></mat-datepicker>
         </mat-form-field>
diff --git a/overlord/src/app/issue/issue.component.ts b/overlord/src/app/issue/issue.component.ts
index 8075c51c..8f80ce70 100644
--- a/overlord/src/app/issue/issue.component.ts
+++ b/overlord/src/app/issue/issue.component.ts
@@ -1,4 +1,4 @@
-import {AfterViewInit, Component, ElementRef, OnInit, ViewChild} from '@angular/core';
+import {AfterViewInit, Component, ElementRef, OnInit, OnDestroy, ViewChild} from '@angular/core';
 import {FormBuilder, FormGroup} from '@angular/forms';
 import {MatAutocompleteSelectedEvent, MatDialog} from '@angular/material';
 import {ActivatedRoute, Router} from '@angular/router';
@@ -16,14 +16,16 @@ import {BatchService} from '../purchase-return/batch.service';
 import {IssueGridService} from './issue-grid.service';
 import {CostCentre} from '../cost-centre/cost-centre';
 import {IssueGridDataSource} from './issue-grid-datasource';
+import {Hotkey, HotkeysService} from "angular2-hotkeys";
 
 @Component({
   selector: 'app-issue',
   templateUrl: './issue.component.html',
   styleUrls: ['./issue.component.css']
 })
-export class IssueComponent implements OnInit, AfterViewInit {
+export class IssueComponent implements OnInit, AfterViewInit, OnDestroy {
   @ViewChild('batchElement') batchElement: ElementRef;
+  @ViewChild('dateElement') dateElement: ElementRef;
   public inventoryObservable = new BehaviorSubject<Inventory[]>([]);
   public gridObservable = new BehaviorSubject<any[]>([]);
   dataSource: IssueDataSource;
@@ -45,6 +47,7 @@ export class IssueComponent implements OnInit, AfterViewInit {
     private router: Router,
     private fb: FormBuilder,
     private dialog: MatDialog,
+    private hotkeys: HotkeysService,
     private toaster: ToasterService,
     private auth: AuthService,
     private ser: VoucherService,
@@ -63,12 +66,27 @@ export class IssueComponent implements OnInit, AfterViewInit {
         this.costCentres = data.costCentres;
         this.loadVoucher(data.voucher);
       });
+    this.hotkeys.add(new Hotkey('f2', (event: KeyboardEvent): boolean => {
+      setTimeout(() => {
+        this.dateElement.nativeElement.focus();
+      }, 0);
+      return false; // Prevent bubbling
+    }, ['INPUT', 'SELECT', 'TEXTAREA']));
+    this.hotkeys.add(new Hotkey('ctrl+s', (event: KeyboardEvent): boolean => {
+      if (this.canSave())
+        this.save();
+      return false; // Prevent bubbling
+    }, ['INPUT', 'SELECT', 'TEXTAREA']));
   }
 
   ngAfterViewInit() {
     this.focusBatch();
   }
 
+  ngOnDestroy() {
+    this.hotkeys.reset();
+  }
+
   loadVoucher(voucher: Voucher) {
     this.voucher = voucher;
     this.sourceJournal = this.voucher.journals.filter(x => x.debit === -1)[0];
diff --git a/overlord/src/app/issue/issue.module.ts b/overlord/src/app/issue/issue.module.ts
index 689dadd7..f13b0e27 100644
--- a/overlord/src/app/issue/issue.module.ts
+++ b/overlord/src/app/issue/issue.module.ts
@@ -29,6 +29,7 @@ import {MomentDateAdapter} from '@angular/material-moment-adapter';
 import {A11yModule} from '@angular/cdk/a11y';
 import {IssueDialogComponent} from './issue-dialog.component';
 import {FlexLayoutModule} from '@angular/flex-layout';
+import {HotkeyModule} from "angular2-hotkeys";
 
 export const MY_FORMATS = {
   parse: {
@@ -48,6 +49,7 @@ export const MY_FORMATS = {
     CommonModule,
     CdkTableModule,
     FlexLayoutModule,
+    HotkeyModule,
     MatAutocompleteModule,
     MatButtonModule,
     MatCardModule,
diff --git a/overlord/src/app/journal/journal.component.html b/overlord/src/app/journal/journal.component.html
index 89e09f31..604c5084 100644
--- a/overlord/src/app/journal/journal.component.html
+++ b/overlord/src/app/journal/journal.component.html
@@ -10,8 +10,8 @@
     <form [formGroup]="form" fxLayout="column">
       <div fxLayout="row" fxLayout.lt-md="column" fxLayoutGap="20px" fxLayoutGap.lt-md="0px">
         <mat-form-field fxFlex>
-          <input matInput [matDatepicker]="date" (focus)="date.open()" placeholder="Date" formControlName="date"
-                 autocomplete="off">
+          <input matInput [matDatepicker]="date" placeholder="Date" formControlName="date" autocomplete="off"
+                 #dateElement (focus)="dateElement.select()">
           <mat-datepicker-toggle matSuffix [for]="date"></mat-datepicker-toggle>
           <mat-datepicker #date></mat-datepicker>
         </mat-form-field>
diff --git a/overlord/src/app/journal/journal.component.ts b/overlord/src/app/journal/journal.component.ts
index e32d95a4..8c9ae2ee 100644
--- a/overlord/src/app/journal/journal.component.ts
+++ b/overlord/src/app/journal/journal.component.ts
@@ -1,4 +1,4 @@
-import {AfterViewInit, Component, ElementRef, OnInit, ViewChild} from '@angular/core';
+import {AfterViewInit, Component, ElementRef, OnInit, OnDestroy, ViewChild} from '@angular/core';
 import {FormBuilder, FormGroup} from '@angular/forms';
 import {MatAutocompleteSelectedEvent, MatDialog} from '@angular/material';
 import {ActivatedRoute, Router} from '@angular/router';
@@ -16,14 +16,16 @@ import {ToasterService} from '../core/toaster.service';
 import {debounceTime, distinctUntilChanged, map, startWith, switchMap} from 'rxjs/operators';
 import {JournalDialogComponent} from './journal-dialog.component';
 import {ImageDialogComponent} from '../shared/image-dialog/image-dialog.component';
+import {Hotkey, HotkeysService} from "angular2-hotkeys";
 
 @Component({
   selector: 'app-journal',
   templateUrl: './journal.component.html',
   styleUrls: ['./journal.component.css']
 })
-export class JournalComponent implements OnInit, AfterViewInit {
+export class JournalComponent implements OnInit, AfterViewInit, OnDestroy {
   @ViewChild('accountElement') accountElement: ElementRef;
+  @ViewChild('dateElement') dateElement: ElementRef;
   public journalObservable = new BehaviorSubject<Journal[]>([]);
   dataSource: JournalDataSource;
   form: FormGroup;
@@ -40,6 +42,7 @@ export class JournalComponent implements OnInit, AfterViewInit {
     private router: Router,
     private fb: FormBuilder,
     private dialog: MatDialog,
+    private hotkeys: HotkeysService,
     private toaster: ToasterService,
     private auth: AuthService,
     private ser: VoucherService,
@@ -55,12 +58,32 @@ export class JournalComponent implements OnInit, AfterViewInit {
       .subscribe((data: { voucher: Voucher }) => {
         this.loadVoucher(data.voucher);
       });
+    this.hotkeys.add(new Hotkey('f2', (event: KeyboardEvent): boolean => {
+      setTimeout(() => {
+        this.dateElement.nativeElement.focus();
+      }, 0);
+      return false; // Prevent bubbling
+    }, ['INPUT', 'SELECT', 'TEXTAREA']));
+    this.hotkeys.add(new Hotkey('ctrl+s', (event: KeyboardEvent): boolean => {
+      if (this.canSave())
+        this.save();
+      return false; // Prevent bubbling
+    }, ['INPUT', 'SELECT', 'TEXTAREA']));
+    this.hotkeys.add(new Hotkey('ctrl+p', (event: KeyboardEvent): boolean => {
+      if (this.voucher.id && !this.voucher.posted && this.auth.user.perms.indexOf('Post Vouchers') !== -1)
+        this.post();
+      return false; // Prevent bubbling
+    }, ['INPUT', 'SELECT', 'TEXTAREA']));
   }
 
   ngAfterViewInit() {
     this.focusAccount();
   }
 
+  ngOnDestroy() {
+    this.hotkeys.reset();
+  }
+
   loadVoucher(voucher) {
     this.voucher = voucher;
     this.form.setValue({
diff --git a/overlord/src/app/journal/journal.module.ts b/overlord/src/app/journal/journal.module.ts
index 4952e067..317688aa 100644
--- a/overlord/src/app/journal/journal.module.ts
+++ b/overlord/src/app/journal/journal.module.ts
@@ -29,6 +29,7 @@ import {MomentDateAdapter} from '@angular/material-moment-adapter';
 import {A11yModule} from '@angular/cdk/a11y';
 import {JournalDialogComponent} from './journal-dialog.component';
 import {FlexLayoutModule} from '@angular/flex-layout';
+import {HotkeyModule} from "angular2-hotkeys";
 
 export const MY_FORMATS = {
   parse: {
@@ -48,6 +49,7 @@ export const MY_FORMATS = {
     CommonModule,
     CdkTableModule,
     FlexLayoutModule,
+    HotkeyModule,
     MatAutocompleteModule,
     MatButtonModule,
     MatCardModule,
diff --git a/overlord/src/app/payment/payment.component.html b/overlord/src/app/payment/payment.component.html
index 8b9932ce..47eea8ca 100644
--- a/overlord/src/app/payment/payment.component.html
+++ b/overlord/src/app/payment/payment.component.html
@@ -11,8 +11,8 @@
       <div fxLayout="row" fxLayoutAlign="space-around start" fxLayout.lt-md="column" fxLayoutGap="20px"
            fxLayoutGap.lt-md="0px">
         <mat-form-field fxFlex="40">
-          <input matInput [matDatepicker]="date" (focus)="date.open()" placeholder="Date" formControlName="date"
-                 autocomplete="off">
+          <input matInput [matDatepicker]="date" placeholder="Date" formControlName="date" autocomplete="off"
+                 #dateElement (focus)="dateElement.select()">
           <mat-datepicker-toggle matSuffix [for]="date"></mat-datepicker-toggle>
           <mat-datepicker #date></mat-datepicker>
         </mat-form-field>
diff --git a/overlord/src/app/payment/payment.component.ts b/overlord/src/app/payment/payment.component.ts
index db51524d..8ea60932 100644
--- a/overlord/src/app/payment/payment.component.ts
+++ b/overlord/src/app/payment/payment.component.ts
@@ -1,4 +1,4 @@
-import {AfterViewInit, Component, ElementRef, OnInit, ViewChild} from '@angular/core';
+import {AfterViewInit, Component, ElementRef, OnInit, OnDestroy, ViewChild} from '@angular/core';
 import {FormBuilder, FormGroup} from '@angular/forms';
 import {MatAutocompleteSelectedEvent, MatDialog} from '@angular/material';
 import {ActivatedRoute, Router} from '@angular/router';
@@ -16,14 +16,16 @@ import {ToasterService} from '../core/toaster.service';
 import {debounceTime, distinctUntilChanged, map, startWith, switchMap} from 'rxjs/operators';
 import {PaymentDialogComponent} from './payment-dialog.component';
 import {ImageDialogComponent} from '../shared/image-dialog/image-dialog.component';
+import {Hotkey, HotkeysService} from "angular2-hotkeys";
 
 @Component({
   selector: 'app-payment',
   templateUrl: './payment.component.html',
   styleUrls: ['./payment.component.css']
 })
-export class PaymentComponent implements OnInit, AfterViewInit {
+export class PaymentComponent implements OnInit, AfterViewInit, OnDestroy {
   @ViewChild('accountElement') accountElement: ElementRef;
+  @ViewChild('dateElement') dateElement: ElementRef;
   public journalObservable = new BehaviorSubject<Journal[]>([]);
   dataSource: PaymentDataSource;
   form: FormGroup;
@@ -42,6 +44,7 @@ export class PaymentComponent implements OnInit, AfterViewInit {
     private router: Router,
     private fb: FormBuilder,
     private dialog: MatDialog,
+    private hotkeys: HotkeysService,
     private toaster: ToasterService,
     private auth: AuthService,
     private ser: VoucherService,
@@ -59,12 +62,32 @@ export class PaymentComponent implements OnInit, AfterViewInit {
         this.paymentAccounts = data.paymentAccounts;
         this.loadVoucher(data.voucher);
       });
+    this.hotkeys.add(new Hotkey('f2', (event: KeyboardEvent): boolean => {
+      setTimeout(() => {
+        this.dateElement.nativeElement.focus();
+      }, 0);
+      return false; // Prevent bubbling
+    }, ['INPUT', 'SELECT', 'TEXTAREA']));
+    this.hotkeys.add(new Hotkey('ctrl+s', (event: KeyboardEvent): boolean => {
+      if (this.canSave())
+        this.save();
+      return false; // Prevent bubbling
+    }, ['INPUT', 'SELECT', 'TEXTAREA']));
+    this.hotkeys.add(new Hotkey('ctrl+p', (event: KeyboardEvent): boolean => {
+      if (this.voucher.id && !this.voucher.posted && this.auth.user.perms.indexOf('Post Vouchers') !== -1)
+        this.post();
+      return false; // Prevent bubbling
+    }, ['INPUT', 'SELECT', 'TEXTAREA']));
   }
 
   ngAfterViewInit() {
     this.focusAccount();
   }
 
+  ngOnDestroy() {
+    this.hotkeys.reset();
+  }
+
   loadVoucher(voucher: Voucher) {
     this.voucher = voucher;
     this.paymentJournal = this.voucher.journals.filter(x => x.debit === -1)[0];
diff --git a/overlord/src/app/payment/payment.module.ts b/overlord/src/app/payment/payment.module.ts
index 3dd597cf..472423a8 100644
--- a/overlord/src/app/payment/payment.module.ts
+++ b/overlord/src/app/payment/payment.module.ts
@@ -29,6 +29,7 @@ import {MomentDateAdapter} from '@angular/material-moment-adapter';
 import {A11yModule} from '@angular/cdk/a11y';
 import {PaymentDialogComponent} from './payment-dialog.component';
 import {FlexLayoutModule} from '@angular/flex-layout';
+import {HotkeyModule} from "angular2-hotkeys";
 
 export const MY_FORMATS = {
   parse: {
@@ -48,6 +49,7 @@ export const MY_FORMATS = {
     CommonModule,
     CdkTableModule,
     FlexLayoutModule,
+    HotkeyModule,
     MatAutocompleteModule,
     MatButtonModule,
     MatCardModule,
diff --git a/overlord/src/app/product/product-detail/product-detail.component.ts b/overlord/src/app/product/product-detail/product-detail.component.ts
index b0dd28a4..865cec2b 100644
--- a/overlord/src/app/product/product-detail/product-detail.component.ts
+++ b/overlord/src/app/product/product-detail/product-detail.component.ts
@@ -57,7 +57,6 @@ export class ProductDetailComponent implements OnInit, AfterViewInit {
 
   showItem(item: Product) {
     this.item = item;
-    console.log(item);
     this.form.setValue({
       code: this.item.code || '(Auto)',
       name: this.item.name || '',
diff --git a/overlord/src/app/purchase-return/purchase-return.component.html b/overlord/src/app/purchase-return/purchase-return.component.html
index 182f3d29..58df7f40 100644
--- a/overlord/src/app/purchase-return/purchase-return.component.html
+++ b/overlord/src/app/purchase-return/purchase-return.component.html
@@ -11,8 +11,8 @@
       <div fxLayout="row" fxLayoutAlign="space-around start" fxLayout.lt-md="column" fxLayoutGap="20px"
            fxLayoutGap.lt-md="0px">
         <mat-form-field fxFlex="40">
-          <input matInput [matDatepicker]="date" (focus)="date.open()" placeholder="Date" formControlName="date"
-                 autocomplete="off">
+          <input matInput [matDatepicker]="date" placeholder="Date" formControlName="date" autocomplete="off"
+                 #dateElement (focus)="dateElement.select()">
           <mat-datepicker-toggle matSuffix [for]="date"></mat-datepicker-toggle>
           <mat-datepicker #date></mat-datepicker>
         </mat-form-field>
diff --git a/overlord/src/app/purchase-return/purchase-return.component.ts b/overlord/src/app/purchase-return/purchase-return.component.ts
index a367d467..2d7cc2f8 100644
--- a/overlord/src/app/purchase-return/purchase-return.component.ts
+++ b/overlord/src/app/purchase-return/purchase-return.component.ts
@@ -1,4 +1,4 @@
-import {AfterViewInit, Component, ElementRef, OnInit, ViewChild} from '@angular/core';
+import {AfterViewInit, Component, ElementRef, OnInit, OnDestroy, ViewChild} from '@angular/core';
 import {FormBuilder, FormGroup} from '@angular/forms';
 import {MatAutocompleteSelectedEvent, MatDialog} from '@angular/material';
 import {ActivatedRoute, Router} from '@angular/router';
@@ -16,15 +16,17 @@ import {debounceTime, distinctUntilChanged, map, startWith, switchMap} from 'rxj
 import {PurchaseReturnDialogComponent} from './purchase-return-dialog.component';
 import {ImageDialogComponent} from '../shared/image-dialog/image-dialog.component';
 import {BatchService} from './batch.service';
+import {Hotkey, HotkeysService} from "angular2-hotkeys";
 
 @Component({
   selector: 'app-purchase-return',
   templateUrl: './purchase-return.component.html',
   styleUrls: ['./purchase-return.component.css']
 })
-export class PurchaseReturnComponent implements OnInit, AfterViewInit {
+export class PurchaseReturnComponent implements OnInit, AfterViewInit, OnDestroy {
   @ViewChild('accountElement') accountElement: ElementRef;
   @ViewChild('batchElement') batchElement: ElementRef;
+  @ViewChild('dateElement') dateElement: ElementRef;
   public inventoryObservable = new BehaviorSubject<Inventory[]>([]);
   dataSource: PurchaseReturnDataSource;
   form: FormGroup;
@@ -44,6 +46,7 @@ export class PurchaseReturnComponent implements OnInit, AfterViewInit {
     private router: Router,
     private fb: FormBuilder,
     private dialog: MatDialog,
+    private hotkeys: HotkeysService,
     private toaster: ToasterService,
     private auth: AuthService,
     private ser: VoucherService,
@@ -60,12 +63,32 @@ export class PurchaseReturnComponent implements OnInit, AfterViewInit {
       .subscribe((data: { voucher: Voucher }) => {
         this.loadVoucher(data.voucher);
       });
+    this.hotkeys.add(new Hotkey('f2', (event: KeyboardEvent): boolean => {
+      setTimeout(() => {
+        this.dateElement.nativeElement.focus();
+      }, 0);
+      return false; // Prevent bubbling
+    }, ['INPUT', 'SELECT', 'TEXTAREA']));
+    this.hotkeys.add(new Hotkey('ctrl+s', (event: KeyboardEvent): boolean => {
+      if (this.canSave())
+        this.save();
+      return false; // Prevent bubbling
+    }, ['INPUT', 'SELECT', 'TEXTAREA']));
+    this.hotkeys.add(new Hotkey('ctrl+p', (event: KeyboardEvent): boolean => {
+      if (this.voucher.id && !this.voucher.posted && this.auth.user.perms.indexOf('Post Vouchers') !== -1)
+        this.post();
+      return false; // Prevent bubbling
+    }, ['INPUT', 'SELECT', 'TEXTAREA']));
   }
 
   ngAfterViewInit() {
     this.focusAccount();
   }
 
+  ngOnDestroy() {
+    this.hotkeys.reset();
+  }
+
   loadVoucher(voucher: Voucher) {
     this.voucher = voucher;
     this.purchaseReturnJournal = this.voucher.journals.filter(x => x.debit === 1)[0];
diff --git a/overlord/src/app/purchase-return/purchase-return.module.ts b/overlord/src/app/purchase-return/purchase-return.module.ts
index 06938f7b..b62cf123 100644
--- a/overlord/src/app/purchase-return/purchase-return.module.ts
+++ b/overlord/src/app/purchase-return/purchase-return.module.ts
@@ -29,6 +29,7 @@ import {MomentDateAdapter} from '@angular/material-moment-adapter';
 import {A11yModule} from '@angular/cdk/a11y';
 import {PurchaseReturnDialogComponent} from './purchase-return-dialog.component';
 import {FlexLayoutModule} from '@angular/flex-layout';
+import {HotkeyModule} from "angular2-hotkeys";
 
 export const MY_FORMATS = {
   parse: {
@@ -48,6 +49,7 @@ export const MY_FORMATS = {
     CommonModule,
     CdkTableModule,
     FlexLayoutModule,
+    HotkeyModule,
     MatAutocompleteModule,
     MatButtonModule,
     MatCardModule,
diff --git a/overlord/src/app/purchase/purchase.component.html b/overlord/src/app/purchase/purchase.component.html
index 0c919be6..201c43dd 100644
--- a/overlord/src/app/purchase/purchase.component.html
+++ b/overlord/src/app/purchase/purchase.component.html
@@ -11,8 +11,8 @@
       <div fxLayout="row" fxLayoutAlign="space-around start" fxLayout.lt-md="column" fxLayoutGap="20px"
            fxLayoutGap.lt-md="0px">
         <mat-form-field fxFlex="40">
-          <input matInput [matDatepicker]="date" (focus)="date.open()" placeholder="Date" formControlName="date"
-                 autocomplete="off">
+          <input matInput [matDatepicker]="date" placeholder="Date" formControlName="date" autocomplete="off"
+                 #dateElement (focus)="dateElement.select()">
           <mat-datepicker-toggle matSuffix [for]="date"></mat-datepicker-toggle>
           <mat-datepicker #date></mat-datepicker>
         </mat-form-field>
diff --git a/overlord/src/app/purchase/purchase.component.ts b/overlord/src/app/purchase/purchase.component.ts
index f5329af6..bc8eaacd 100644
--- a/overlord/src/app/purchase/purchase.component.ts
+++ b/overlord/src/app/purchase/purchase.component.ts
@@ -1,4 +1,4 @@
-import {AfterViewInit, Component, ElementRef, OnInit, ViewChild} from '@angular/core';
+import {AfterViewInit, Component, ElementRef, OnInit, OnDestroy, ViewChild} from '@angular/core';
 import {FormBuilder, FormGroup} from '@angular/forms';
 import {MatAutocompleteSelectedEvent, MatDialog} from '@angular/material';
 import {ActivatedRoute, Router} from '@angular/router';
@@ -17,15 +17,17 @@ import {PurchaseDialogComponent} from './purchase-dialog.component';
 import {ImageDialogComponent} from '../shared/image-dialog/image-dialog.component';
 import {ProductService} from '../product/product.service';
 import {Product} from '../product/product';
+import {Hotkey, HotkeysService} from "angular2-hotkeys";
 
 @Component({
   selector: 'app-purchase',
   templateUrl: './purchase.component.html',
   styleUrls: ['./purchase.component.css']
 })
-export class PurchaseComponent implements OnInit, AfterViewInit {
+export class PurchaseComponent implements OnInit, AfterViewInit, OnDestroy {
   @ViewChild('accountElement') accountElement: ElementRef;
   @ViewChild('productElement') productElement: ElementRef;
+  @ViewChild('dateElement') dateElement: ElementRef;
   public inventoryObservable = new BehaviorSubject<Inventory[]>([]);
   dataSource: PurchaseDataSource;
   form: FormGroup;
@@ -45,6 +47,7 @@ export class PurchaseComponent implements OnInit, AfterViewInit {
     private router: Router,
     private fb: FormBuilder,
     private dialog: MatDialog,
+    private hotkeys: HotkeysService,
     private toaster: ToasterService,
     private auth: AuthService,
     private ser: VoucherService,
@@ -61,12 +64,32 @@ export class PurchaseComponent implements OnInit, AfterViewInit {
       .subscribe((data: { voucher: Voucher }) => {
         this.loadVoucher(data.voucher);
       });
+    this.hotkeys.add(new Hotkey('f2', (event: KeyboardEvent): boolean => {
+      setTimeout(() => {
+        this.dateElement.nativeElement.focus();
+      }, 0);
+      return false; // Prevent bubbling
+    }, ['INPUT', 'SELECT', 'TEXTAREA']));
+    this.hotkeys.add(new Hotkey('ctrl+s', (event: KeyboardEvent): boolean => {
+      if (this.canSave())
+        this.save();
+      return false; // Prevent bubbling
+    }, ['INPUT', 'SELECT', 'TEXTAREA']));
+    this.hotkeys.add(new Hotkey('ctrl+p', (event: KeyboardEvent): boolean => {
+      if (this.voucher.id && !this.voucher.posted && this.auth.user.perms.indexOf('Post Vouchers') !== -1)
+        this.post();
+      return false; // Prevent bubbling
+    }, ['INPUT', 'SELECT', 'TEXTAREA']));
   }
 
   ngAfterViewInit() {
     this.focusAccount();
   }
 
+  ngOnDestroy() {
+    this.hotkeys.reset();
+  }
+
   loadVoucher(voucher) {
     this.voucher = voucher;
     this.purchaseJournal = this.voucher.journals.filter(x => x.debit === -1)[0];
diff --git a/overlord/src/app/purchase/purchase.module.ts b/overlord/src/app/purchase/purchase.module.ts
index 07dd69bc..a6f65716 100644
--- a/overlord/src/app/purchase/purchase.module.ts
+++ b/overlord/src/app/purchase/purchase.module.ts
@@ -29,6 +29,7 @@ import {MomentDateAdapter} from '@angular/material-moment-adapter';
 import {A11yModule} from '@angular/cdk/a11y';
 import {PurchaseDialogComponent} from './purchase-dialog.component';
 import {FlexLayoutModule} from '@angular/flex-layout';
+import {HotkeyModule} from "angular2-hotkeys";
 
 export const MY_FORMATS = {
   parse: {
@@ -48,6 +49,7 @@ export const MY_FORMATS = {
     CommonModule,
     CdkTableModule,
     FlexLayoutModule,
+    HotkeyModule,
     MatAutocompleteModule,
     MatButtonModule,
     MatCardModule,
diff --git a/overlord/src/app/receipt/receipt.component.html b/overlord/src/app/receipt/receipt.component.html
index 1458c40f..bd7ed44d 100644
--- a/overlord/src/app/receipt/receipt.component.html
+++ b/overlord/src/app/receipt/receipt.component.html
@@ -11,8 +11,8 @@
       <div fxLayout="row" fxLayoutAlign="space-around start" fxLayout.lt-md="column" fxLayoutGap="20px"
            fxLayoutGap.lt-md="0px">
         <mat-form-field fxFlex="40">
-          <input matInput [matDatepicker]="date" (focus)="date.open()" placeholder="Date" formControlName="date"
-                 autocomplete="off">
+          <input matInput [matDatepicker]="date" placeholder="Date" formControlName="date" autocomplete="off"
+                 #dateElement (focus)="dateElement.select()">
           <mat-datepicker-toggle matSuffix [for]="date"></mat-datepicker-toggle>
           <mat-datepicker #date></mat-datepicker>
         </mat-form-field>
diff --git a/overlord/src/app/receipt/receipt.component.ts b/overlord/src/app/receipt/receipt.component.ts
index d65977db..aea221af 100644
--- a/overlord/src/app/receipt/receipt.component.ts
+++ b/overlord/src/app/receipt/receipt.component.ts
@@ -1,4 +1,4 @@
-import {AfterViewInit, Component, ElementRef, OnInit, ViewChild} from '@angular/core';
+import {AfterViewInit, Component, ElementRef, OnInit, OnDestroy, ViewChild} from '@angular/core';
 import {FormBuilder, FormGroup} from '@angular/forms';
 import {MatAutocompleteSelectedEvent, MatDialog} from '@angular/material';
 import {ActivatedRoute, Router} from '@angular/router';
@@ -16,14 +16,16 @@ import {ToasterService} from '../core/toaster.service';
 import {debounceTime, distinctUntilChanged, map, startWith, switchMap} from 'rxjs/operators';
 import {ReceiptDialogComponent} from './receipt-dialog.component';
 import {ImageDialogComponent} from '../shared/image-dialog/image-dialog.component';
+import {Hotkey, HotkeysService} from "angular2-hotkeys";
 
 @Component({
   selector: 'app-receipt',
   templateUrl: './receipt.component.html',
   styleUrls: ['./receipt.component.css']
 })
-export class ReceiptComponent implements OnInit, AfterViewInit {
+export class ReceiptComponent implements OnInit, AfterViewInit, OnDestroy {
   @ViewChild('accountElement') accountElement: ElementRef;
+  @ViewChild('dateElement') dateElement: ElementRef;
   public journalObservable = new BehaviorSubject<Journal[]>([]);
   dataSource: ReceiptDataSource;
   form: FormGroup;
@@ -42,6 +44,7 @@ export class ReceiptComponent implements OnInit, AfterViewInit {
     private router: Router,
     private fb: FormBuilder,
     private dialog: MatDialog,
+    private hotkeys: HotkeysService,
     private toaster: ToasterService,
     private auth: AuthService,
     private ser: VoucherService,
@@ -59,12 +62,32 @@ export class ReceiptComponent implements OnInit, AfterViewInit {
         this.receiptAccounts = data.receiptAccounts;
         this.loadVoucher(data.voucher);
       });
+    this.hotkeys.add(new Hotkey('f2', (event: KeyboardEvent): boolean => {
+      setTimeout(() => {
+        this.dateElement.nativeElement.focus();
+      }, 0);
+      return false; // Prevent bubbling
+    }, ['INPUT', 'SELECT', 'TEXTAREA']));
+    this.hotkeys.add(new Hotkey('ctrl+s', (event: KeyboardEvent): boolean => {
+      if (this.canSave())
+        this.save();
+      return false; // Prevent bubbling
+    }, ['INPUT', 'SELECT', 'TEXTAREA']));
+    this.hotkeys.add(new Hotkey('ctrl+p', (event: KeyboardEvent): boolean => {
+      if (this.voucher.id && !this.voucher.posted && this.auth.user.perms.indexOf('Post Vouchers') !== -1)
+        this.post();
+      return false; // Prevent bubbling
+    }, ['INPUT', 'SELECT', 'TEXTAREA']));
   }
 
   ngAfterViewInit() {
     this.focusAccount();
   }
 
+  ngOnDestroy() {
+    this.hotkeys.reset();
+  }
+
   loadVoucher(voucher: Voucher) {
     this.voucher = voucher;
     this.receiptJournal = this.voucher.journals.filter(x => x.debit === 1)[0];
diff --git a/overlord/src/app/receipt/receipt.module.ts b/overlord/src/app/receipt/receipt.module.ts
index 974560a6..941b9a4e 100644
--- a/overlord/src/app/receipt/receipt.module.ts
+++ b/overlord/src/app/receipt/receipt.module.ts
@@ -29,6 +29,7 @@ import {MomentDateAdapter} from '@angular/material-moment-adapter';
 import {A11yModule} from '@angular/cdk/a11y';
 import {ReceiptDialogComponent} from './receipt-dialog.component';
 import {FlexLayoutModule} from '@angular/flex-layout';
+import {HotkeyModule} from "angular2-hotkeys";
 
 export const MY_FORMATS = {
   parse: {
@@ -48,6 +49,7 @@ export const MY_FORMATS = {
     CommonModule,
     CdkTableModule,
     FlexLayoutModule,
+    HotkeyModule,
     MatAutocompleteModule,
     MatButtonModule,
     MatCardModule,