1 import {Component, OnInit, AfterViewInit, Input, Output, EventEmitter,
2 ViewChild} from '@angular/core';
3 import {Router, ActivatedRoute, ParamMap} from '@angular/router';
4 import {tap} from 'rxjs/operators';
5 import {Pager} from '@eg/share/util/pager';
6 import {IdlService, IdlObject} from '@eg/core/idl.service';
7 import {OrgService} from '@eg/core/org.service';
8 import {NetService} from '@eg/core/net.service';
9 import {PcrudService} from '@eg/core/pcrud.service';
10 import {AuthService} from '@eg/core/auth.service';
11 import {LineitemService} from './lineitem.service';
12 import {ComboboxEntry} from '@eg/share/combobox/combobox.component';
13 import {ItemLocationService} from '@eg/share/item-location-select/item-location-select.service';
15 const FORMULA_FIELDS = [
23 interface FormulaApplication {
29 templateUrl: 'copies.component.html'
31 export class LineitemCopiesComponent implements OnInit, AfterViewInit {
32 static newCopyId = -1;
37 batchOwningLib: IdlObject;
38 batchFund: ComboboxEntry;
39 batchCopyLocId: number;
43 formulaFilter = {owner: []};
45 formulaValues: {[field: string]: {[val: string]: boolean}} = {};
47 // Can any changes be applied?
51 private route: ActivatedRoute,
52 private idl: IdlService,
53 private org: OrgService,
54 private net: NetService,
55 private pcrud: PcrudService,
56 private auth: AuthService,
57 private loc: ItemLocationService,
58 private liService: LineitemService
63 this.formulaFilter.owner =
64 this.org.fullPath(this.auth.user().ws_ou(), true);
66 this.route.paramMap.subscribe((params: ParamMap) => {
67 const id = +params.get('lineitemId');
68 if (id !== this.lineitemId) {
70 if (id) { this.load(); }
74 this.liService.getLiAttrDefs();
77 load(): Promise<any> {
80 return this.liService.getFleshedLineitems(
81 [this.lineitemId], {toCache: true, fromCache: true})
82 .pipe(tap(liStruct => this.lineitem = liStruct.lineitem)).toPromise()
85 this.lineitem.state().match(/on-order|received|cancelled/);
87 .then(_ => this.applyCount());
92 const node = document.getElementById('copy-count-input');
93 if (node) { (node as HTMLInputElement).select(); }
98 const copies = this.lineitem.lineitem_details();
99 while (copies.length < this.copyCount) {
100 const copy = this.idl.create('acqlid');
101 copy.id(LineitemCopiesComponent.newCopyId--);
103 copy.lineitem(this.lineitem.id());
107 if (copies.length > this.copyCount) {
108 this.copyCount = copies.length;
112 applyFormula(id: number) {
114 const copies = this.lineitem.lineitem_details();
115 if (this.formulaOffset >= copies.length) {
116 // We have already applied a formula entry to every item.
120 this.formulaValues = {};
122 this.pcrud.retrieve('acqdf', id,
123 {flesh: 1, flesh_fields: {acqdf: ['entries']}})
124 .subscribe(formula => {
127 formula.entries().sort((e1, e2) =>
128 e1.position() < e2.position() ? -1 : 1));
130 let rowIdx = this.formulaOffset - 1;
132 while (++rowIdx < copies.length) {
133 this.formulateOneCopy(formula, rowIdx, true);
136 // No new values will be applied
137 if (!Object.keys(this.formulaValues)) { return; }
139 this.fetchFormulaValues().then(_ => {
142 let rowIdx2 = this.formulaOffset - 1;
144 while (++rowIdx2 < copies.length) {
145 applied += this.formulateOneCopy(formula, rowIdx2);
149 this.formulaOffset += applied;
150 this.saveAppliedFormula(formula);
156 saveAppliedFormula(formula: IdlObject) {
157 const app = this.idl.create('acqdfa');
158 app.lineitem(this.lineitem.id());
159 app.creator(this.auth.user().id());
160 app.formula(formula.id());
162 this.pcrud.create(app).toPromise().then(a => {
163 a.creator(this.auth.user());
165 this.lineitem.distribution_formulas().push(a);
169 // Grab values applied by distribution formulas and cache them before
170 // applying them to their target copies, so the comboboxes, etc.
171 // are not required to go fetch them en masse / en duplicato.
172 fetchFormulaValues(): Promise<any> {
174 const funds = Object.keys(this.formulaValues.fund);
175 const mods = Object.keys(this.formulaValues.circ_modifier);
176 const locs = Object.keys(this.formulaValues.location);
178 let promise = Promise.resolve();
180 if (funds.length > 0) {
181 promise = promise.then(_ => {
182 return this.pcrud.search('acqf', {id: funds})
184 this.liService.fundCache[fund.id()] = fund;
185 this.liService.batchOptionWanted.emit(
186 {fund: {id: fund.id(), label: fund.code(), fm: fund}});
191 if (mods.length > 0) {
192 promise = promise.then(_ => {
193 return this.pcrud.search('ccm', {code: mods})
195 this.liService.circModCache[mod.code()] = mod;
196 this.liService.batchOptionWanted.emit({circ_modifier:
197 {id: mod.code(), label: mod.code(), fm: mod}});
202 if (locs.length > 0) {
203 promise = promise.then(_ => {
204 return this.pcrud.search('acpl', {id: locs})
206 this.loc.locationCache[loc.id()] = loc;
207 this.liService.batchOptionWanted.emit({location:
208 {id: loc.id(), label: loc.name(), fm: loc}});
216 // Apply a formula entry to a single copy.
217 // extracOnly means we are only collecting the new values we wish to
218 // apply from the formula w/o applying them to the copy in question.
219 formulateOneCopy(formula: IdlObject,
220 rowIdx: number, extractOnly?: boolean): number {
222 let targetEntry = null;
223 let entryIdx = this.formulaOffset;
224 const copy = this.lineitem.lineitem_details()[rowIdx];
226 // Find the correct entry for the current copy.
227 formula.entries().forEach(entry => {
229 entryIdx += entry.item_count();
230 if (entryIdx > rowIdx) {
236 // We ran out of copies.
237 if (!targetEntry) { return 0; }
239 FORMULA_FIELDS.forEach(field => {
240 const val = targetEntry[field]();
241 if (val === undefined || val === null) { return; }
244 if (!this.formulaValues[field]) {
245 this.formulaValues[field] = {};
247 this.formulaValues[field][val] = true;
259 this.progressMax = null;
260 this.progressValue = 0;
262 this.liService.updateLiDetails(this.lineitem).subscribe(
264 this.progressMax = struct.total;
265 this.progressValue++;
268 () => this.load().then(_ => {
269 this.liService.activateStateChange.emit(this.lineitem.id());
275 deleteFormula(formula: IdlObject) {
276 this.pcrud.remove(formula).subscribe(_ => {
277 this.lineitem.distribution_formulas(
278 this.lineitem.distribution_formulas()
279 .filter(f => f.id() !== formula.id())