LP1904036 billing history
authorBill Erickson <berickxx@gmail.com>
Fri, 16 Apr 2021 21:46:50 +0000 (17:46 -0400)
committerGalen Charlton <gmc@equinoxOLI.org>
Fri, 28 Oct 2022 00:13:31 +0000 (20:13 -0400)
Signed-off-by: Bill Erickson <berickxx@gmail.com>
Signed-off-by: Jane Sandberg <js7389@princeton.edu>
Signed-off-by: Galen Charlton <gmc@equinoxOLI.org>
Open-ILS/src/eg2/src/app/staff/circ/patron/billing-history.component.html
Open-ILS/src/eg2/src/app/staff/circ/patron/billing-history.component.ts

index 088642f..118ee19 100644 (file)
   <li ngbNavItem="transactions">
     <a ngbNavLink i18n>Transactions</a>
     <ng-template ngbNavContent>
-      <div class="mt-2">
-        <eg-grid idlClass="mbt" #xactsGrid
-          persistKey="circ.patron.billhistory_xacts"
-          (onRowActivate)="showStatement($event)"
-          [reloadOnColumnChange]="true"
-          [dataSource]="xactsDataSource" [sortable]="true">
-
-          <eg-grid-toolbar-button i18n-label label="Add Billing"
-            (onClick)="addBilling()"></eg-grid-toolbar-button>
-
-          <eg-grid-toolbar-action
-            i18n-label label="Print Bills" (onClick)="printBills($event)">
-          </eg-grid-toolbar-action>
-
-          <eg-grid-column path="summary.balance_owed"></eg-grid-column>
-          <eg-grid-column path="id" i18n-label label="Bill #" [required]="true"></eg-grid-column>
-          <eg-grid-column path="xact_finish" i18n-label label="Finish" 
-            datatype="timestamp" [datePlusTime]="true"></eg-grid-column>
-          <eg-grid-column path="xact_start" i18n-label label="Start" 
-            datatype="timestamp" [datePlusTime]="true"></eg-grid-column>
-          <eg-grid-column path="summary.total_owed" i18n-label label="Total Billed"></eg-grid-column>
-          <eg-grid-column path="summary.total_paid" i18n-label label="Total Paid"></eg-grid-column>
-          <eg-grid-column path="summary.xact_type" i18n-label label="Type"></eg-grid-column>
-          <eg-grid-column path="summary.last_payment_ts" datatype="timestamp" 
-            [required]="true" [hidden]="true"></eg-grid-column>
-
-          <eg-grid-column i18n-label label="Title" name="title" 
-            [cellTemplate]="titleTemplate"
-            path="circulation.target_copy.call_number.record.simple_record.title">
-          </eg-grid-column>
-
-          <eg-grid-column name="record_id" 
-            path="circulation.target_copy.call_number.record.id" 
-            [required]="true" [hidden]="true"></eg-grid-column>
-
-          <eg-grid-column i18n-label label="Barcode" name="copy_barcode" 
-            [cellTemplate]="barcodeTemplate" path="circulation.target_copy.barcode">
-          </eg-grid-column>
-
-          <eg-grid-column name="copy_id" path="circulation.target_copy.id" 
-            [required]="true" [hidden]="true"></eg-grid-column>
-
-          <eg-grid-column path="circulation.target_copy.circ_lib.shortname" 
-            i18n-label label="Item Owning Library"></eg-grid-column>
-          <eg-grid-column path="circulation.circ_lib.shortname" 
-            i18n-label label="Checkout or Renewal Library" [hidden]="true"></eg-grid-column>
-          <eg-grid-column path="circulation.due_date" 
-            i18n-label label="Due Date" datefilter="egDueDate" [hidden]="true"></eg-grid-column>
-          <eg-grid-column path="circulation.stop_fines" 
-            i18n-label label="Fine Stop Reason" [hidden]="true"></eg-grid-column>
-          <eg-grid-column path="circulation.target_copy.call_number.prefix.label" 
-            i18n-label label="CN Prefix" [hidden]="true"></eg-grid-column>
-          <eg-grid-column path="circulation.target_copy.call_number.suffix.label" 
-            i18n-label label="CN Suffix" [hidden]="true"></eg-grid-column>
-
-          <!--
-          <eg-grid-column path="circulation.target_copy.call_number.*" [hidden]="true"></eg-grid-column>
-          <eg-grid-column path="summary.*" hidden></eg-grid-column>
-          <eg-grid-column path="circulation.target_copy.*" hidden></eg-grid-column>
-          -->
-
-        </eg-grid>
+
+      <div class="row mt-3 mb-3 pt-2 pb-2 border rounded">
+        <div class="col-lg-4">
+          <div class="row">
+            <div class="col-lg-5" i18n>Selected Billed:</div>
+            <div class="col-lg-4" i18n>{{selectedXactsInfo().billed | currency}}</div>
+          </div>
+          <div class="row">
+            <div class="col-lg-5" i18n>Selected Paid:</div>
+            <div class="col-lg-4" i18n>{{selectedXactsInfo().paid | currency}}</div>
+          </div>
+        </div>
+        <div class="col-lg-4 form-inline">
+          <span class="mr-2" i18n>Start Date:</span>
+          <eg-date-select [initialIso]="xactsStart"
+            (onChangeAsIso)="dateChange('xactsStart', $event)"></eg-date-select>
+        </div>
+        <div class="col-lg-4 form-inline">
+          <span class="mr-2" i18n>End Date:</span>
+          <eg-date-select [initialIso]="xactsEnd"
+            (onChangeAsIso)="dateChange('xactsEnd', $event)"></eg-date-select>
+        </div>
       </div>
+
+      <eg-grid idlClass="mbt" #xactsGrid
+        persistKey="circ.patron.billhistory_xacts"
+        (onRowActivate)="showStatement($event)"
+        [reloadOnColumnChange]="true"
+        [dataSource]="xactsDataSource" [sortable]="true">
+
+        <eg-grid-toolbar-action i18n-label label="Add Billing"
+          (onClick)="addBillingForXact($event)"></eg-grid-toolbar-action>
+
+        <eg-grid-toolbar-action
+          i18n-label label="Print Bills" (onClick)="printBills($event)">
+        </eg-grid-toolbar-action>
+
+        <eg-grid-column path="summary.balance_owed"></eg-grid-column>
+        <eg-grid-column path="id" [index]="true" i18n-label label="Bill #" [required]="true"></eg-grid-column>
+        <eg-grid-column path="xact_finish" i18n-label label="Finish" 
+          datatype="timestamp" [datePlusTime]="true"></eg-grid-column>
+        <eg-grid-column path="xact_start" i18n-label label="Start" 
+          datatype="timestamp" [datePlusTime]="true"></eg-grid-column>
+        <eg-grid-column path="summary.total_owed" i18n-label label="Total Billed"></eg-grid-column>
+        <eg-grid-column path="summary.total_paid" i18n-label label="Total Paid"></eg-grid-column>
+        <eg-grid-column path="summary.xact_type" i18n-label label="Type"></eg-grid-column>
+        <eg-grid-column path="summary.last_payment_ts" datatype="timestamp" 
+          [required]="true" [hidden]="true"></eg-grid-column>
+
+        <eg-grid-column i18n-label label="Title" name="title" 
+          [cellTemplate]="titleTemplate"
+          path="circulation.target_copy.call_number.record.simple_record.title">
+        </eg-grid-column>
+
+        <eg-grid-column name="record_id" 
+          path="circulation.target_copy.call_number.record.id" 
+          [required]="true" [hidden]="true"></eg-grid-column>
+
+        <eg-grid-column i18n-label label="Barcode" name="copy_barcode" 
+          [cellTemplate]="barcodeTemplate" path="circulation.target_copy.barcode">
+        </eg-grid-column>
+
+        <eg-grid-column name="copy_id" path="circulation.target_copy.id" 
+          [required]="true" [hidden]="true"></eg-grid-column>
+
+        <eg-grid-column path="circulation.target_copy.circ_lib.shortname" 
+          i18n-label label="Item Owning Library"></eg-grid-column>
+        <eg-grid-column path="circulation.circ_lib.shortname" 
+          i18n-label label="Checkout or Renewal Library" [hidden]="true"></eg-grid-column>
+        <eg-grid-column path="circulation.due_date" 
+          i18n-label label="Due Date" datefilter="egDueDate" [hidden]="true"></eg-grid-column>
+        <eg-grid-column path="circulation.stop_fines" 
+          i18n-label label="Fine Stop Reason" [hidden]="true"></eg-grid-column>
+        <eg-grid-column path="circulation.target_copy.call_number.prefix.label" 
+          i18n-label label="CN Prefix" [hidden]="true"></eg-grid-column>
+        <eg-grid-column path="circulation.target_copy.call_number.suffix.label" 
+          i18n-label label="CN Suffix" [hidden]="true"></eg-grid-column>
+
+        <!--
+        <eg-grid-column path="circulation.target_copy.call_number.*" [hidden]="true"></eg-grid-column>
+        <eg-grid-column path="summary.*" hidden></eg-grid-column>
+        <eg-grid-column path="circulation.target_copy.*" hidden></eg-grid-column>
+        -->
+
+      </eg-grid>
     </ng-template>
   </li>
   <li ngbNavItem="payments">
     <a ngbNavLink i18n>Payments</a>
     <ng-template ngbNavContent>
+      <div class="row mt-3 mb-3 pt-2 pb-2 border rounded">
+        <div class="col-lg-4">
+          <div class="row">
+            <div class="col-lg-5" i18n>Selected Paid:</div>
+            <div class="col-lg-4" i18n>{{selectedXactsInfo().paid | currency}}</div>
+          </div>
+        </div>
+        <div class="col-lg-4 form-inline">
+          <span class="mr-2" i18n>Start Date:</span>
+          <eg-date-select [initialIso]="xactsStart"
+            (onChangeAsIso)="dateChange('xactsStart', $event)"></eg-date-select>
+        </div>
+        <div class="col-lg-4 form-inline">
+          <span class="mr-2" i18n>End Date:</span>
+          <eg-date-select [initialIso]="xactsEnd"
+            (onChangeAsIso)="dateChange('xactsEnd', $event)"></eg-date-select>
+        </div>
+      </div>
+
+      <eg-grid idlClass="mp" #xactsGrid
+        persistKey="circ.patron.billhistory_payments"
+        (onRowActivate)="showStatement($event)"
+        [reloadOnColumnChange]="true"
+        [dataSource]="paymentsDataSource" [sortable]="true">
+
+        <eg-grid-column path="amount" i18n-label label="Amount"></eg-grid-column>
+        <eg-grid-column path="id" [index]="true" i18n-label label="Payment ID" [required]="true"></eg-grid-column>
+        <eg-grid-column path="payment_ts" i18n-label label="Payment Time" [datePlusTime]="true"></eg-grid-column>
+        <eg-grid-column path="note" i18n-label label="Note"></eg-grid-column>
+        <eg-grid-column path="voided" i18n-label label="Voided"></eg-grid-column>
+        <eg-grid-column path="xact.summary.xact_type" i18n-label label="Transaction Type"></eg-grid-column>
+        <eg-grid-column path="xact.summary.last_billing_type" i18n-label label="Last Billing Type"></eg-grid-column>
+        <eg-grid-column path="payment_type" i18n-label label="Payment Type"></eg-grid-column>
+
+        <eg-grid-column i18n-label label="Title" name="title" 
+          [cellTemplate]="titleTemplate"
+          path="xact.circulation.target_copy.call_number.record.simple_record.title">
+        </eg-grid-column>
+
+        <eg-grid-column name="record_id" 
+          path="xact.circulation.target_copy.call_number.record.id" 
+          [required]="true" [hidden]="true"></eg-grid-column>
+
+        <eg-grid-column i18n-label label="Barcode" name="copy_barcode" 
+          [cellTemplate]="barcodeTemplate" path="xact.circulation.target_copy.barcode">
+        </eg-grid-column>
+
+        <eg-grid-column name="copy_id" path="xact.circulation.target_copy.id" 
+          [required]="true" [hidden]="true"></eg-grid-column>
+
+        <eg-grid-column path="xact.circulation.target_copy.circ_lib.shortname" 
+          name="owning_lib" i18n-label label="Item Owning Library"></eg-grid-column>
+        <eg-grid-column path="xact.circulation.circ_lib.shortname" name="circ_lib" 
+          i18n-label label="Checkout or Renewal Library" [hidden]="true"></eg-grid-column>
+        <eg-grid-column path="xact.circulation.due_date" i18n-label 
+          label="Due Date" datefilter="egDueDate" [hidden]="true"></eg-grid-column>
+        <eg-grid-column path="xact.circulation.stop_fines" i18n-label 
+          label="Fine Stop Reason" [hidden]="true"></eg-grid-column>
+
+        <eg-grid-column path="xact.id" [required]="true" [hidden]="true"></eg-grid-column>
+        <eg-grid-column path="xact.usr" [required]="true" [hidden]="true"></eg-grid-column>
+        <eg-grid-column path="check_payment.check_number" i18n-label 
+          label="Check Number" [hidden]="true"></eg-grid-column>
+
+        <!--
+        <eg-grid-column path="xact.*" [hidden]="true"></eg-grid-column>
+        <eg-grid-column path="xact.summary.*" [hidden]="true"></eg-grid-column>
+        -->
+
+      </eg-grid>
     </ng-template>
   </li>
 </ul>
index d895a8c..a5ae77d 100644 (file)
@@ -11,7 +11,7 @@ import {PcrudService, PcrudContext} from '@eg/core/pcrud.service';
 import {AuthService} from '@eg/core/auth.service';
 import {ServerStoreService} from '@eg/core/server-store.service';
 import {PatronService} from '@eg/staff/share/patron/patron.service';
-import {PatronContextService, BillGridEntry} from './patron.service';
+import {PatronContextService} from './patron.service';
 import {GridDataSource, GridColumn, GridCellTextGenerator} from '@eg/share/grid/grid';
 import {GridComponent} from '@eg/share/grid/grid.component';
 import {GridFlatDataService} from '@eg/share/grid/grid-flat-data.service';
@@ -25,6 +25,7 @@ import {BillingService} from '@eg/staff/share/billing/billing.service';
 import {AddBillingDialogComponent} from '@eg/staff/share/billing/billing-dialog.component';
 import {AudioService} from '@eg/share/util/audio.service';
 import {ToastService} from '@eg/share/toast/toast.service';
+import {DateUtil} from '@eg/share/util/date';
 
 @Component({
   templateUrl: 'billing-history.component.html',
@@ -41,6 +42,12 @@ export class BillingHistoryComponent implements OnInit {
     xactsTextGenerator: GridCellTextGenerator;
     paymentsTextGenerator: GridCellTextGenerator;
 
+    xactsStart: string;
+    xactsEnd: string;
+
+    paymentsStart: string;
+    paymentsEnd: string;
+
     @ViewChild('xactsGrid') private xactsGrid: GridComponent;
     @ViewChild('paymentsGrid') private paymentsGrid: GridComponent;
     @ViewChild('billingDialog') private billingDialog: AddBillingDialogComponent;
@@ -64,11 +71,19 @@ export class BillingHistoryComponent implements OnInit {
 
     ngOnInit() {
 
+        const start = new Date();
+        const end = new Date();
+        start.setFullYear(start.getFullYear() - 1);
+        end.setDate(end.getDate() + 1);
+
+        this.xactsStart = this.paymentsStart = DateUtil.localYmdFromDate(start);
+        this.xactsEnd = this.paymentsEnd = DateUtil.localYmdFromDate(end);
+
         this.xactsDataSource.getRows = (pager: Pager, sort: any[]) => {
 
             const query: any = {
                usr: this.patronId,
-               xact_start: {between: ['2020-04-16', 'now']},
+               xact_start: {between: [this.xactsStart, this.xactsEnd]},
                '-or': [
                     {'summary.balance_owed': {'<>': 0}},
                     {'summary.last_payment_ts': {'<>': null}}
@@ -79,26 +94,36 @@ export class BillingHistoryComponent implements OnInit {
                 this.xactsGrid.context, query, pager, sort);
         };
 
-        /*
         this.paymentsDataSource.getRows = (pager: Pager, sort: any[]) => {
-            const orderBy: any = {};
-            if (sort.length) {
-                orderBy.mp = sort[0].name + ' ' + sort[0].dir;
-            }
-            return this.pcrud.search(
-                'mp', {xact: this.xactId}, {order_by: orderBy});
+            const query: any = {
+               'xact.usr': this.patronId,
+               payment_ts: {between: [this.paymentsStart, this.paymentsEnd]},
+            };
+
+            return this.flatData.getRows(
+                this.xactsGrid.context, query, pager, sort);
         };
-        */
     }
 
-    showStatement(row: BillGridEntry) {
+    dateChange(which: string, iso: string) {
+
+        this[which] = iso;
+
+        if (which.match(/xacts/)) {
+            this.xactsGrid.reload();
+        } else {
+            this.paymentsGrid.reload();
+        }
+    }
+
+    showStatement(row: any) {
         this.router.navigate(['/staff/circ/patron',
             this.patronId, 'bills', row.xact.id(), 'statement']);
     }
 
-    addBillingForXact(rows: BillGridEntry[]) {
+    addBillingForXact(rows: any[]) {
         if (rows.length === 0) { return; }
-        const xactIds = rows.map(r => r.xact.id());
+        const xactIds = rows.map(r => r.id);
 
         this.billingDialog.newXact = false;
         let changesApplied = false;
@@ -120,7 +145,7 @@ export class BillingHistoryComponent implements OnInit {
         });
     }
 
-    printBills(rows: BillGridEntry[]) {
+    printBills(rows: any) {
         if (rows.length === 0) { return; }
 
         this.printer.print({
@@ -129,6 +154,28 @@ export class BillingHistoryComponent implements OnInit {
             printContext: 'default'
         });
     }
+
+    selectedXactsInfo(): {owed: number, billed: number, paid: number} {
+        const info = {owed : 0, billed : 0, paid : 0};
+
+        if (!this.xactsGrid) { return info; } // page loading
+
+        this.xactsGrid.context.rowSelector.selected().forEach(id => {
+            const row = this.xactsGrid.context.getRowByIndex(id);
+
+            if (!row) { return; } // Called mid-reload
+
+            info.owed   += Number(row['summary.balance_owed']) * 100;
+            info.billed += Number(row['summary.total_owed']) * 100;
+            info.paid   += Number(row['summary.total_paid']) * 100;
+        });
+
+        info.owed /= 100;
+        info.billed /= 100;
+        info.paid /= 100;
+
+        return info;
+    }
 }