<button class="btn btn-info btn-sm" (click)="newCharge()" *ngIf="canModify">New Charge</button>
</h4>
+<eg-acq-disencumber-charge-dialog #disencumberChargeDialog></eg-acq-disencumber-charge-dialog>
+
<ng-container *ngIf="showBody">
<div class="row d-flex">
<div class="flex-2 p-2 font-weight-bold">Charge Type</div>
[idlQuerySort]="{acqf: 'year DESC, code'}"
[idlQueryAnd]="{active: 't'}">
</eg-combobox>
+ <span *ngIf="charge.fund_debit() && charge.fund_debit().fund() !== charge.fund()">
+ <br>
+ <i>Fund actually debited is
+ <eg-combobox idlClass="acqf" [selectedId]="charge.fund_debit().fund()"
+ [readOnly]="true"></eg-combobox></i>
+ </span>
</div>
<div class="flex-2 p-2">
<span *ngIf="!charge.isnew() && !charge.ischanged()">{{charge.title()}}</span>
<input *ngIf="charge.isnew() || charge.ischanged()" type="number" min="0" class="form-control"
i18n-placeholder placeholder="Esimated Cost..." [required]="true"
[ngModel]="charge.estimated_cost()" (ngModelChange)="charge.estimated_cost($event)"/>
+ <span *ngIf="charge.fund_debit()">
+ <br>
+ <span *ngIf="charge.fund_debit().encumbrance() === 't'" i18n>
+ <i>Amount encumbered is {{charge.fund_debit().amount() | currency}}</i>
+ </span>
+ <span *ngIf="charge.fund_debit().encumbrance() === 'f'" i18n>
+ <i>Amount expended is {{charge.fund_debit().amount() | currency}}</i>
+ </span>
+ </span>
</div>
<div class="flex-2 p-1">
<button *ngIf="canModify" [disabled]="!(charge.isnew() || charge.ischanged())" class="btn btn-success btn-sm"
(click)="saveCharge(charge)" i18n>Save</button>
<button *ngIf="canModify" [disabled]="charge.isnew()" class="btn btn-outline-dark btn-sm ml-1"
(click)="charge.ischanged(true)" i18n>Edit</button>
+ <button class="btn btn-warning btn-sm ml-1"
+ (click)="disencumberCharge(charge)" *ngIf="canDisencumber(charge)" i18n>Disencumber</button>
<button class="btn btn-danger btn-sm ml-1"
(click)="removeCharge(charge)" *ngIf="canModify" i18n>Remove</button>
</div>
-import {Component, OnInit, OnDestroy, Input} from '@angular/core';
+import {Component, OnInit, OnDestroy, Input, ViewChild} from '@angular/core';
import {Subscription} from 'rxjs';
import {Router, ActivatedRoute, ParamMap} from '@angular/router';
import {IdlService, IdlObject} from '@eg/core/idl.service';
+import {AuthService} from '@eg/core/auth.service';
+import {NetService} from '@eg/core/net.service';
+import {EventService} from '@eg/core/event.service';
import {PcrudService} from '@eg/core/pcrud.service';
import {ComboboxEntry} from '@eg/share/combobox/combobox.component';
import {PoService} from './po.service';
+import {DisencumberChargeDialogComponent} from './disencumber-charge-dialog.component';
@Component({
templateUrl: 'charges.component.html',
autoId = -1;
poSubscription: Subscription;
+ @ViewChild('disencumberChargeDialog') disencumberChargeDialog: DisencumberChargeDialogComponent;
+
constructor(
private idl: IdlService,
+ private net: NetService,
+ private evt: EventService,
+ private auth: AuthService,
private pcrud: PcrudService,
public poService: PoService
) {}
}
}
+ canDisencumber(charge: IdlObject): boolean {
+ if (!this.po() || !this.po().order_date() || this.po().state() === 'cancelled') {
+ return false; // order must be loaded, activated, and not cancelled
+ }
+ if (!charge.fund_debit()) {
+ return false; // that which is not encumbered cannot be disencumbered
+ }
+
+ const debit = charge.fund_debit();
+ if (debit.encumbrance() === 'f') {
+ return false; // that which is expended cannot be disencumbered
+ }
+ if (debit.invoice_entry()) {
+ return false; // we shouldn't actually be a po_item that is
+ // linked to an invoice_entry, but if we are,
+ // do NOT touch
+ }
+ if (debit.invoice_items() && debit.invoice_items().length) {
+ return false; // we're linked to an invoice item, so the disposition of the
+ // invoice entry should govern things
+ }
+ if (Number(debit.amount()) === 0) {
+ return false; // we're already at zero
+ }
+ return true; // we're likely OK to disencumber
+ }
+
+ disencumberCharge(charge: IdlObject) {
+ this.disencumberChargeDialog.charge = charge;
+ this.disencumberChargeDialog.open().subscribe(doIt => {
+ if (!doIt) { return; }
+
+ return this.net.request(
+ 'open-ils.acq',
+ 'open-ils.acq.po_item.disencumber',
+ this.auth.token(), charge.id()
+ ).toPromise().then(res => {
+ const evt = this.evt.parse(res);
+ if (evt) { return Promise.reject(evt + ''); }
+ }).then(_ => this.poService.refreshOrderSummary(true));
+ });
+ }
+
removeCharge(charge: IdlObject) {
this.po().po_items( // remove local copy
this.po().po_items().filter(item => item.id() !== charge.id())
--- /dev/null
+<ng-template #dialogContent>
+ <form class="form-validated">
+ <div class="modal-header bg-info">
+ <h3 class="modal-title" i18n>Disencumber Direct Charge</h3>
+ <button type="button" class="close"
+ i18n-aria-label aria-label="Close" (click)="close()">
+ <span aria-hidden="true">×</span>
+ </button>
+ </div>
+ <div class="modal-body">
+ <div class="d-flex">
+ <div class="flex-2" i18n>Charge:</div>
+ <div class="flex-3">
+ <eg-combobox idlClass="aiit" [selectedId]="charge.inv_item_type()"
+ [readOnly]="true"></eg-combobox>
+ </div>
+ </div>
+ <div class="d-flex">
+ <div class="flex-2" i18n>Amount:</div>
+ <div class="flex-3">{{charge.estimated_cost()}}</div>
+ </div>
+ <div class="d-flex">
+ <div class="flex-2" i18n>Original Fund:</div>
+ <div class="flex-3">
+ <eg-combobox idlClass="acqf" [selectedId]="charge.fund()"
+ [readOnly]="true"></eg-combobox>
+ </div>
+ </div>
+ <div class="d-flex">
+ <div class="flex-2" i18n>Fund Debited:</div>
+ <div class="flex-3">
+ <eg-combobox idlClass="acqf" [selectedId]="charge.fund_debit().fund()"
+ [readOnly]="true"></eg-combobox>
+ </div>
+ </div>
+ <div class="d-flex">
+ <div class="flex-2" i18n>Amount Encumbered:</div>
+ <div class="flex-3">{{charge.fund_debit().amount()}}</div>
+ </div>
+ </div>
+ <div class="modal-footer">
+ <button type="button" class="btn btn-success"
+ (click)="close(true)" i18n>Disencumber</button>
+ <button type="button" class="btn btn-warning"
+ (click)="close()" i18n>Cancel</button>
+ </div>
+ </form>
+</ng-template>
+
--- /dev/null
+import {Component, Input, ViewChild, TemplateRef, OnInit} from '@angular/core';
+import {NgbModal} from '@ng-bootstrap/ng-bootstrap';
+import {DialogComponent} from '@eg/share/dialog/dialog.component';
+import {IdlService, IdlObject} from '@eg/core/idl.service';
+import {ComboboxEntry} from '@eg/share/combobox/combobox.component';
+
+@Component({
+ selector: 'eg-acq-disencumber-charge-dialog',
+ templateUrl: './disencumber-charge-dialog.component.html'
+})
+
+export class DisencumberChargeDialogComponent extends DialogComponent {
+ @Input() charge: IdlObject;
+ constructor(private modal: NgbModal) { super(modal); }
+}
+
+
import {PoCreateComponent} from './create.component';
import {PoChargesComponent} from './charges.component';
import {PicklistUploadService} from '../picklist/upload.service';
+import {DisencumberChargeDialogComponent} from './disencumber-charge-dialog.component';
@NgModule({
declarations: [
PoNotesComponent,
PoCreateComponent,
PoChargesComponent,
- PrintComponent
+ PrintComponent,
+ DisencumberChargeDialogComponent
],
imports: [
StaffCommonModule,
flesh_provider: true,
flesh_notes: true,
flesh_po_items: true,
+ flesh_po_items_further: true,
flesh_price_summary: true,
flesh_lineitem_count: true
}, params.fleshMore || {});
// Fetch the PO again (with less fleshing) and update the
// order summary totals our main fully-fleshed PO.
- refreshOrderSummary(): Promise<any> {
+ refreshOrderSummary(update_po_items = false): Promise<any> {
+ const flesh = Object.assign({
+ flesh_price_summary: true
+ });
+ if (update_po_items) {
+ flesh['flesh_po_items'] = true;
+ flesh['flesh_po_items_further'] = true;
+ }
return this.net.request('open-ils.acq',
'open-ils.acq.purchase_order.retrieve.authoritative',
this.auth.token(), this.currentPo.id(),
- {flesh_price_summary: true}
+ flesh
).toPromise().then(po => {
this.currentPo.amount_encumbered(po.amount_encumbered());
this.currentPo.amount_spent(po.amount_spent());
this.currentPo.amount_estimated(po.amount_estimated());
+ if (update_po_items) {
+ this.currentPo.po_items(po.po_items());
+ }
});
}
}