LPXXX Angular Volcopy
authorBill Erickson <berickxx@gmail.com>
Fri, 5 Jun 2020 20:54:23 +0000 (16:54 -0400)
committerBill Erickson <berickxx@gmail.com>
Fri, 5 Jun 2020 20:54:23 +0000 (16:54 -0400)
Signed-off-by: Bill Erickson <berickxx@gmail.com>
Open-ILS/src/eg2/src/app/staff/cat/volcopy/vol-edit.component.html
Open-ILS/src/eg2/src/app/staff/cat/volcopy/vol-edit.component.ts

index 42fd354..a5f42a5 100644 (file)
@@ -8,7 +8,7 @@
     <label class="font-weight-bold" i18n>Classification</label>
     <div>
       <eg-combobox [smallFormControl]="true" [(ngModel)]="batchVolClass">
-        <eg-combobox-entry *ngFor="let cls of volClasses" 
+        <eg-combobox-entry *ngFor="let cls of volClasses"
           [entryId]="cls.id()" [entryLabel]="cls.name()">
         </eg-combobox-entry>
       </eg-combobox>
@@ -18,7 +18,7 @@
     <label class="font-weight-bold" i18n>Prefix</label>
     <div>
       <eg-combobox [smallFormControl]="true" [(ngModel)]="batchVolPrefix">
-        <eg-combobox-entry *ngFor="let pfx of volPrefixes" 
+        <eg-combobox-entry *ngFor="let pfx of volPrefixes"
           [entryId]="pfx.id()" [entryLabel]="pfx.label()">
         </eg-combobox-entry>
       </eg-combobox>
@@ -37,7 +37,7 @@
     <label class="font-weight-bold" i18n>Suffix</label>
     <div>
       <eg-combobox [smallFormControl]="true" [(ngModel)]="batchVolSuffix">
-        <eg-combobox-entry *ngFor="let sfx of volSuffixes" 
+        <eg-combobox-entry *ngFor="let sfx of volSuffixes"
           [entryId]="sfx.id()" [entryLabel]="sfx.label()">
         </eg-combobox-entry>
       </eg-combobox>
@@ -46,7 +46,7 @@
   <div class="p-1" [ngStyle]="{flex: flexAt(7)}">
     <label class="font-weight-bold" i18n>Batch</label>
     <div>
-      <button class="btn btn-sm btn-outline-dark label-with-material-icon" 
+      <button class="btn btn-sm btn-outline-dark label-with-material-icon"
         (click)="batchVolApply()">
         <span i18n>Apply</span>
         <span class="material-icons">arrow_downward</span>
   </div>
   <div class="p-1" [ngStyle]="{flex: flexAt(8)}">
     <label class="font-weight-bold" i18n>Generate Barcodes</label>
-    <button class="btn btn-sm btn-outline-dark label-with-material-icon" 
+    <button class="btn btn-sm btn-outline-dark label-with-material-icon"
       (click)="generateBarcodes()">
       <span i18n>Generate</span>
       <span class="material-icons">arrow_downward</span>
     </button>
   </div>
-  <div class="p-1" [ngStyle]="{flex: flexAt(9)}"></div>
-  <div class="p-1" [ngStyle]="{flex: flexAt(10)}"></div>
+  <div class="p-1" [ngStyle]="{flex: flexSpan(9, 10)}">
+    <label class="font-weight-bold" i18n>Checkdigit</label>
+    <div class="form-check form-check-inline">
+      <input class="form-check-input" type="checkbox" 
+        id="use-checkdigit" [(ngModel)]="useCheckdigit">
+      <label class="form-check-label" for="use-checkdigit" i18n>
+        Use Checkdigit
+      </label>
+    </div>
+  </div>
 </div>
 
 
         </div>
         <div class="p-1" [ngStyle]="{flex: flexAt(3)}">
           <ng-container *ngIf="copyIdx == 0">
-            <eg-combobox 
+            <eg-combobox
               [selectedId]="volNode.target.label_class()"
               [smallFormControl]="true"
-              [required]="true" 
+              [required]="true"
               (onChange)="applyVolValue(volNode.target, 'label_class', $event ? $event.id : null)">
-              <eg-combobox-entry *ngFor="let cls of volClasses" 
+              <eg-combobox-entry *ngFor="let cls of volClasses"
                 [entryId]="cls.id()" [entryLabel]="cls.name()">
               </eg-combobox-entry>
             </eg-combobox>
         </div>
         <div class="p-1" [ngStyle]="{flex: flexAt(4)}">
           <ng-container *ngIf="copyIdx == 0">
-            <eg-combobox 
+            <eg-combobox
               [selectedId]="volNode.target.prefix()"
-              [required]="true" 
+              [required]="true"
               [smallFormControl]="true"
               (onChange)="applyVolValue(volNode.target, 'prefix', $event ? $event.id : null)">
-              <eg-combobox-entry *ngFor="let pfx of volPrefixes" 
+              <eg-combobox-entry *ngFor="let pfx of volPrefixes"
                 [entryId]="pfx.id()" [entryLabel]="pfx.label()">
               </eg-combobox-entry>
             </eg-combobox>
         </div>
         <div class="p-1" [ngStyle]="{flex: flexAt(6)}">
           <ng-container *ngIf="copyIdx == 0">
-            <eg-combobox 
+            <eg-combobox
               [selectedId]="volNode.target.suffix()"
-              [required]="true" 
+              [required]="true"
               [smallFormControl]="true"
               (onChange)="applyVolValue(volNode.target, 'suffix', $event ? $event.id : null)">
-              <eg-combobox-entry *ngFor="let sfx of volSuffixes" 
+              <eg-combobox-entry *ngFor="let sfx of volSuffixes"
                 [entryId]="sfx.id()" [entryLabel]="sfx.label()">
               </eg-combobox-entry>
             </eg-combobox>
             id="barcode-input-{{copyNode.target.id()}}"
             spellcheck="false"
             [required]="true"
+            [ngClass]="{'text-danger': copyNode.target._dupe_barcode}"
+                                               (ngModelChange)="barcodeChanged(copyNode.target, $event)"
             (keyup.enter)="selectNextBarcode(copyNode.target.id())"
             (keyup.shift.enter)="selectNextBarcode(copyNode.target.id(), true)"
             [ngModel]="copyNode.target.barcode()"
             (ngModelChange)="applyCopyValue(copyNode.target, 'barcode', $event)"/>
+          <div *ngIf="copyNode.target._dupe_barcode"
+            class="alert alert-danger font-italic p-1" i18n>
+            Duplicate Barcode</div>
         </div>
         <div class="p-1" [ngStyle]="{flex: flexAt(9)}">
           <input type="number" class="form-control form-control-sm"
             <label i18n>N/A</label>
           </ng-container>
           <ng-container *ngIf="recordHasParts(volNode.target.record())">
-            <eg-combobox 
+            <eg-combobox
               [disabled]="bibParts[volNode.target.record()].length == 0"
               [selectedId]="copyNode.target.parts()[0] ? copyNode.target.parts()[0].id() : null"
               [smallFormControl]="true"
index 6b9c33a..ecef3b5 100644 (file)
@@ -1,7 +1,9 @@
 import {Component, OnInit, AfterViewInit, ViewChild, Input, Renderer2} from '@angular/core';
 import {Router, ActivatedRoute, ParamMap} from '@angular/router';
+import {tap} from 'rxjs/operators';
 import {IdlObject} from '@eg/core/idl.service';
 import {OrgService} from '@eg/core/org.service';
+import {AuthService} from '@eg/core/auth.service';
 import {NetService} from '@eg/core/net.service';
 import {PcrudService} from '@eg/core/pcrud.service';
 import {VolCopyContext, HoldingsTreeNode} from './volcopy';
@@ -38,10 +40,14 @@ export class VolEditComponent implements OnInit {
 
     recordVolLabels: string[] = [];
 
+    autoBarcodeInProgress = false;
+    useCheckdigit = false;
+
     constructor(
         private renderer: Renderer2,
         private pcrud: PcrudService,
         private net: NetService,
+        private auth: AuthService,
         private holdings: HoldingsService
     ) {}
 
@@ -121,6 +127,15 @@ export class VolEditComponent implements OnInit {
         return this.flexSettings[column];
     }
 
+    // Returns the flex amount occupied by a span of columns.
+    flexSpan(column1: number, column2: number): number {
+        let flex = 0;
+        for (let i = column1; i <= column2; i++) {
+            flex += this.flexSettings[i];
+        }
+        return flex;
+    }
+
     volCountChanged(orgNode: HoldingsTreeNode, count: number) {
         console.log('vol set set to ', count);
     }
@@ -201,7 +216,72 @@ export class VolEditComponent implements OnInit {
                 '#barcode-input-' + (nextId || firstId)).select();
     }
 
+    barcodeCanChange(copy: IdlObject): boolean {
+        // TODO
+        return true;
+    }
+
     generateBarcodes() {
+               this.autoBarcodeInProgress = true;
+
+        // Autogen only replaces barcodes for items which are in
+        // certain statuses.
+        const copies = this.context.copyList()
+        .filter((copy, idx) => {
+            // During autogen we do not replace the first item,
+            // so it's status is not relevant.
+            return idx === 0 || this.barcodeCanChange(copy);
+        });
+
+        if (copies.length > 1) { // seed barcode will always be present
+            this.proceedWithAutogen(copies)
+            .then(_ => this.autoBarcodeInProgress = false);
+        };
+    }
+
+    proceedWithAutogen(copyList: IdlObject[]): Promise<any> {
+
+        const seedBarcode: string = copyList[0].barcode();
+        copyList.shift(); // Avoid replacing the seed barcode
+
+        const count = copyList.length;
+
+        return this.net.request('open-ils.cat',
+            'open-ils.cat.item.barcode.autogen',
+            this.auth.token(), seedBarcode, count, {
+                checkdigit: this.useCheckdigit,
+                skip_dupes: true
+            }
+        ).pipe(tap(barcodes => {
+
+            copyList.forEach(copy => {
+                if (copy.barcode() !== barcodes[0]) {
+                    copy.barcode(barcodes[0]);
+                    copy.ischanged(true);
+                }
+                barcodes.shift();
+            });
+
+        })).toPromise();
+    }
+
+       barcodeChanged(copy: IdlObject, barcode: string) {
+        copy.barcode(barcode);
+        copy.ischanged(true);
+        copy._dupe_barcode = false;
+
+        if (barcode && !this.autoBarcodeInProgress) {
+            // Manual barcode entry requires dupe check
+
+            copy._dupe_barcode = false;
+            this.pcrud.search('acp', {
+                deleted: 'f',
+                barcode: barcode,
+                id: {'!=': copy.id()}
+            }).subscribe(resp => {
+                if (resp) { copy._dupe_barcode = true; }
+            });
+        }
     }
 }