LPXXX Angular Volcopy
authorBill Erickson <berickxx@gmail.com>
Wed, 24 Jun 2020 21:59:52 +0000 (17:59 -0400)
committerBill Erickson <berickxx@gmail.com>
Wed, 24 Jun 2020 21:59:52 +0000 (17:59 -0400)
Signed-off-by: Bill Erickson <berickxx@gmail.com>
Open-ILS/src/eg2/src/app/staff/cat/volcopy/config.component.html
Open-ILS/src/eg2/src/app/staff/cat/volcopy/copy-attrs.component.html
Open-ILS/src/eg2/src/app/staff/cat/volcopy/copy-attrs.component.ts
Open-ILS/src/eg2/src/app/staff/cat/volcopy/vol-edit.component.ts
Open-ILS/src/eg2/src/app/staff/cat/volcopy/volcopy.ts

index 93b264c..00fbe36 100644 (file)
 </div>
 
 <hr class="p-2"/>
+<h3 i18n>Item Attribute Settings</h3>
+
+<div class="row">
+  <div class="col-lg-6">
+    <div class="card">
+      <div class="card-header" i18n>Item Attributes Behavior</div>
+      <ul class="list-group list-group-flush">
+        <li class="list-group-item">
+          <div class="form-check form-check-inline">
+            <input class="form-check-input" type="checkbox" 
+              id="hide-classification-column" 
+              [(ngModel)]="volcopy.defaults.values.circ_lib_mod_with_owning_lib">
+            <label class="form-check-label" 
+              for="hide-circ_lib_mod_with_owning_lib-column" i18n>
+              Change Circ Lib When Owning Lib Changes
+            </label>
+          </div>
+        </li>
+      </ul>
+    </div>
+  </div>
+</div>
+
+
+<hr class="p-2"/>
 
 <h3 i18n>Hide Item Attributes</h3>
 <span class="font-italic" i18n>
-  Selected Attributes Will be <b>Hidden</b> from the Item Attributes Form.
+  Selected Fields Will be <span class="font-weight-bold">Hidden</span>
+  from the Item Attributes Form.
 </span>
 
 <div class="row d-flex">
index 5128eda..e20dcac 100644 (file)
@@ -60,9 +60,8 @@
     </a>
     
     <div class="flex-1"> </div>
-    <button class="btn btn-outline-dark mr-2" 
-      (click)="copyTemplateCbox.selectedId = null" i18n>Clear</button>
-    <button class="btn btn-outline-danger mr-2" (click)="deleteTemplate()" i18n>Delete Template</button>
+    <button class="btn btn-outline-danger mr-2" 
+      (click)="deleteTemplate()" i18n>Delete Template</button>
   </div>
 </div>
 
     </div>
 
     <div *ngIf="displayAttr('owning_lib')">
+      <eg-string #olLabel text="Owning Library" i18n-text></eg-string>
       <ng-template #owningLibTemplate>
         <eg-org-select 
           domId="owning-lib-input"
         </eg-org-select>
       </ng-template>
       <ng-container *ngTemplateOutlet="batchAttr;
-        context:{field:'owning_lib',template:owningLibTemplate}">
+        context:{field:'owning_lib',template:owningLibTemplate,label:olLabel.text}">
       </ng-container>
     </div>
 
           [emptyIsUnset]="true"
           [editTemplate]="statCatTemplate"
           [labelCounts]="statCatCounts(cat.id())"
+          (valueCleared)="statCatChanged(cat.id(), true)"
           (changesSaved)="statCatChanged(cat.id())">
         </eg-batch-item-attr>
       </div>
index dff2033..bad44c6 100644 (file)
@@ -237,7 +237,9 @@ export class CopyAttrsComponent implements OnInit, AfterViewInit {
             this.values[field] = value;
         }
 
-        // TODO: handle circ_lib, owning_lib changes specially
+        if (field === 'owning_lib') {
+            return this.owningLibChanged(value);
+        }
 
         this.context.copyList().forEach(copy => {
             if (copy[field] && copy[field]() !== value) {
@@ -247,16 +249,82 @@ export class CopyAttrsComponent implements OnInit, AfterViewInit {
         });
     }
 
+    owningLibChanged(orgId: number) {
+        if (!orgId) { return; }
+
+        let promise = Promise.resolve();
+
+        // Map existing vol IDs to their replacments.
+        const newVols: any = {};
+
+        this.context.copyList().forEach(copy => {
+
+            // Change the copy circ lib to match the new owning lib
+            // if configured to do so.
+            if (this.volcopy.defaults.values.circ_lib_mod_with_owning_lib) {
+                if (copy.circ_lib() !== orgId) {
+                    copy.circ_lib(orgId);
+                    copy.ischanged(true);
+
+                    this.batchAttrs
+                        .filter(ba => ba.name === 'circ_lib')
+                        .forEach(attr => attr.hasChanged = true);
+                }
+            }
+
+            const vol = copy.call_number();
+
+            if (vol.owning_lib() === orgId) { return; } // No change needed
+
+            let newVol;
+            if (newVols[vol.id()]) {
+                newVol = newVols[vol.id()];
+
+            } else {
+
+                // The open-ils.cat.asset.volume.fleshed.batch.update API
+                // will use the existing volume when trying to create a
+                // new volume with the same parameters as an existing volume.
+                newVol = this.idl.clone(vol);
+                newVol.owning_lib(orgId);
+                newVol.id(this.volcopy.autoId--);
+                newVol.isnew(true);
+                newVols[vol.id()] = newVol;
+            }
+
+            copy.call_number(newVol);
+            copy.ischanged();
+
+            this.context.removeCopyNode(copy.id());
+            this.context.findOrCreateCopyNode(copy);
+        });
+
+        // If any of the above actions results in an empty volume
+        // remove it from the tree.  Note this does not delete the
+        // volume at the server, since other items could be attached
+        // of which this instance of the editor is not aware.
+        Object.keys(newVols).forEach(volId => {
+            const volNode = this.context.volNodes().filter(
+                volNode => volNode.target.id() === +volId)[0];
+
+            if (volNode && volNode.children.length === 0) {
+                this.context.removeVolNode(+volId);
+            }
+        });
+    }
+
     // Create or modify a stat cat entry for each copy that does not
     // already match the new value.
-    statCatChanged(catId: number) {
+    statCatChanged(catId: number, clear?: boolean) {
         catId = Number(catId);
 
         const entryId = this.statCatValues[catId];
+
         this.context.copyList().forEach(copy => {
 
             let entry = copy.stat_cat_entries()
                 .filter(e => e.stat_cat() === catId)[0];
+                console.log('0', entry);
 
             if (entry) {
                 if (entry.id() === entryId) {
@@ -269,6 +337,7 @@ export class CopyAttrsComponent implements OnInit, AfterViewInit {
                 entry = this.idl.create('asce');
                 entry.stat_cat(catId);
                 copy.stat_cat_entries().push(entry);
+                console.log('1', entry);
             }
 
             entry.id(entryId);
@@ -303,7 +372,7 @@ export class CopyAttrsComponent implements OnInit, AfterViewInit {
 
         this.store.setLocalItem('cat.copy.last_template', entry.id);
 
-        // TODO: handle owning_lib and statcats differently, location
+        // TODO: handle owning_lib
 
         const template = this.volcopy.templates[entry.id];
 
@@ -312,14 +381,18 @@ export class CopyAttrsComponent implements OnInit, AfterViewInit {
 
             if (value === null || value === undefined) { return; }
 
+            if (field === 'statcats') {
+                Object.keys(value).forEach(catId => {
+                    this.statCatValues[+catId] = value[+catId];
+                    this.statCatChanged(+catId);
+                });
+                return;
+            }
+
             // In some cases, we may have to fetch the data since
             // the local code assumes copy field is fleshed.
             let promise = Promise.resolve(value);
 
-            // TODO: promises in loops are dangerous becuase they
-            // can lead to blasts of duplicate requests for non-local
-            // data.  Consider an alternative approach.
-
             if (field === 'location') {
                 // May be a 'remote' location.  Fetch as needed.
                 promise = this.volcopy.getLocation(value);
@@ -357,18 +430,29 @@ export class CopyAttrsComponent implements OnInit, AfterViewInit {
         const copy = this.context.copyList()[0];
 
         this.batchAttrs.forEach(comp => {
-            if (comp.hasChanged) {
-                const value = copy[comp.name]();
-                if (value === null) {
-                    delete template[comp.name];
+            if (!comp.hasChanged) { return; }
 
-                } else {
-                    // some values are fleshed.
-                    // this assumes fleshed objects have an 'id' value,
-                    // which is true so far.
-                    template[comp.name] =
-                        typeof value === 'object' ?  value.id() : value;
-                }
+            const value = copy[comp.name]();
+            const name = comp.name;
+
+            if (value === null) {
+                delete template[name];
+                return;
+            }
+
+            if (name.match(/stat_cat_/)) {
+                const statId = name.match(/stat_cat_(\d+)/)[1];
+                if (!template.statcats) { template.statcats = {}; }
+
+                template.statcats[statId] = value;
+
+            } else {
+
+                // some values are fleshed.
+                // this assumes fleshed objects have an 'id' value,
+                // which is true so far.
+                template[name] =
+                    typeof value === 'object' ?  value.id() : value;
             }
         });
 
index b6948a4..f01c346 100644 (file)
@@ -40,8 +40,6 @@ export class VolEditComponent implements OnInit {
     autoBarcodeInProgress = false;
     useCheckdigit = false;
 
-    autoId = -1;
-
     deleteVolCount: number = null;
     deleteCopyCount: number = null;
 
index d751c7e..b47b59d 100644 (file)
@@ -149,6 +149,28 @@ export class VolCopyContext {
         return node;
     }
 
+    removeVolNode(volId: number) {
+        this.orgNodes().forEach(orgNode => {
+            for (let idx = 0; idx < orgNode.children.length; idx++) {
+                if (orgNode.children[idx].target.id() === volId) {
+                    orgNode.children.splice(idx, 1);
+                    break;
+                }
+            }
+        });
+    }
+
+    removeCopyNode(copyId: number) {
+        this.volNodes().forEach(volNode => {
+            for (let idx = 0; idx < volNode.children.length; idx++) {
+                if (volNode.children[idx].target.id() === copyId) {
+                    volNode.children.splice(idx, 1);
+                    break;
+                }
+            }
+        });
+    }
+
     sortHoldings() {
 
         this.orgNodes().forEach(orgNode => {