</eg-alert-dialog>
<eg-confirm-dialog #warnPayDialog
i18n-dialogBody i18n-dialogTitle dialogTitle="Confirm Payment Amount"
- dialogBody="Are you sure you want to apply a payment of {{payAmount | currency}}?">
+ dialogBody="Are you sure you want to apply a payment of {{paymentAmount | currency}}?">
</eg-confirm-dialog>
+<eg-credit-card-dialog [patron]="patron()" #creditCardDialog>
+</eg-credit-card-dialog>
<!-- SUMMARY -->
</div>
<div class="ml-2"><label for="pay-amount" i18n>Payment Received:</label></div>
<div class="ml-1">
- <input type="number" class="form-control" [(ngModel)]="payAmount"
+ <input type="number" class="form-control" [(ngModel)]="paymentAmount"
id="pay-amount" [min]="0"/>
</div>
<div class="ml-2 form-check form-check-inline">
import {PromptDialogComponent} from '@eg/share/dialog/prompt.component';
import {AlertDialogComponent} from '@eg/share/dialog/alert.component';
import {ConfirmDialogComponent} from '@eg/share/dialog/confirm.component';
+import {CreditCardDialogComponent, CreditCardPaymentParams
+ } from '@eg/staff/share/circ/credit-card-dialog.component';
interface BillGridEntry extends CircDisplayInfo {
xact: IdlObject // mbt
sessionVoided = 0;
paymentType = 'cash_payment';
checkNumber: string;
- payAmount: number;
+ paymentAmount: number;
annotatePayment = false;
annotation: string;
entries: BillGridEntry[];
convertChangeToCredit = false;
receiptOnPayment = false;
+ ccPaymentParams: CreditCardPaymentParams;
maxPayAmount = 100000;
warnPayAmount = 1000;
@ViewChild('annotateDialog') private annotateDialog: PromptDialogComponent;
@ViewChild('maxPayDialog') private maxPayDialog: AlertDialogComponent;
@ViewChild('warnPayDialog') private warnPayDialog: ConfirmDialogComponent;
+ @ViewChild('creditCardDialog') private creditCardDialog: CreditCardDialogComponent;
constructor(
private router: Router,
pendingPaymentInfo(): {payment: number, change: number} {
- const amt = this.payAmount || 0;
+ const amt = this.paymentAmount || 0;
if (amt >= this.paidSelected()) {
const owedSelected = this.owedSelected();
if (!this.billGrid) { return true; } // still loading
return (
- this.payAmount === 0 ||
- (this.payAmount < 0 && this.paymentType !== 'refund') ||
+ this.paymentAmount === 0 ||
+ (this.paymentAmount < 0 && this.paymentType !== 'refund') ||
this.billGrid.context.rowSelector.selected().length === 0
);
}
}
amountExceedsMax(): boolean {
- if (this.payAmount < this.maxPayAmount) { return false; }
+ if (this.paymentAmount < this.maxPayAmount) { return false; }
this.maxPayDialog.open().toPromise().then(_ => this.focusPayAmount());
return true;
}
addCcArgs(): Promise<any> {
- return null;
+ this.ccPaymentParams = {};
+
+ if (this.paymentType !== 'credit_card_payment') {
+ return Promise.resolve();
+ }
+
+ return this.creditCardDialog.open().toPromise().then(ccArgs => {
+ if (ccArgs) {
+ this.ccPaymentParams = ccArgs;
+ } else {
+ return Promise.reject('CC dialog canceled');
+ }
+ });
}
verifyPayAmount(): Promise<any> {
- if (this.payAmount < this.warnPayAmount) {
+ if (this.paymentAmount < this.warnPayAmount) {
return Promise.resolve();
}
import {CircComponentsComponent} from './components.component';
import {CircEventsComponent} from './events-dialog.component';
import {AddBillingDialogComponent} from './billing-dialog.component';
+import {CreditCardDialogComponent} from './credit-card-dialog.component';
@NgModule({
declarations: [
PrecatCheckoutDialogComponent,
ClaimsReturnedDialogComponent,
CircEventsComponent,
+ CreditCardDialogComponent,
AddBillingDialogComponent
],
imports: [
exports: [
CircGridComponent,
CircComponentsComponent,
- AddBillingDialogComponent
+ AddBillingDialogComponent,
+ CreditCardDialogComponent
],
providers: [
CircService
--- /dev/null
+<ng-template #dialogContent>
+ <div class="modal-header bg-info">
+ <h4 class="modal-title" i18n>Credit Card Information</h4>
+ <button type="button" class="close"
+ i18n-aria-label aria-label="Close" (click)="close()">
+ <span aria-hidden="true">×</span>
+ </button>
+ </div>
+ <div class="modal-body" *ngIf="args">
+
+ <div class="card">
+ <div class="card-header" i18n>Credit Card Info</div>
+ <div class="card-body form-validated">
+ <div class="row">
+ <div class="col-lg-4"><label i18n>Process Where</label></div>
+ <div class="col-lg-8">
+ <select class="form-control" [(ngModel)]="args.where_process">
+ <option [value]='1' [disabled]="!supportsExternal" i18n>
+ Process payment through Evergreen
+ </option>
+ <option [value]='0' i18n>
+ Record externally processed payment
+ </option>
+ </select>
+ </div>
+ </div>
+ <ng-container *ngIf="args.where_process == 1">
+ <div class="row mt-2">
+ <div class="col-lg-4"><label i18n>Approval Code</label></div>
+ <div class="col-lg-8">
+ <input type="text" class="form-control"
+ required [(ngModel)]="args.approval_code"/>
+ </div>
+ </div>
+ </ng-container>
+ <ng-container *ngIf="args.where_process == 0">
+ <div class="row mt-2">
+ <div class="col-lg-4"><label i18n>Expire Month</label></div>
+ <div class="col-lg-8">
+ <input type="number" class="form-control" [min]="1"
+ required [(ngModel)]="args.expire_month"/>
+ </div>
+ </div>
+ <div class="row mt-2">
+ <div class="col-lg-4"><label i18n>Expire Year</label></div>
+ <div class="col-lg-8">
+ <input type="number" class="form-control" [min]="thisYear"
+ required [(ngModel)]="args.expire_year"/>
+ </div>
+ </div>
+ </ng-container>
+ </div>
+ </div>
+
+ <div class="card mt-2">
+ <div class="card-header" i18n>Optional Fields</div>
+ <div class="card-body form-validated">
+ <div class="row">
+ <div class="col-lg-4"><label i18n>Billing Name (first)</label></div>
+ <div class="col-lg-8">
+ <input type='text' class="form-control" [(ngModel)]="args.billing_first"/>
+ </div>
+ </div>
+ <div class="row mt-2">
+ <div class="col-lg-4"><label i18n>Billing Name (last)</label></div>
+ <div class="col-lg-8">
+ <input type='text' class="form-control" [(ngModel)]="args.billing_last"/>
+ </div>
+ </div>
+
+ <ng-container *ngIf="args.where_process == 0">
+ <div class="row mt-2">
+ <div class="col-lg-4"><label i18n>Address</label></div>
+ <div class="col-lg-8">
+ <input type='text' class="form-control" [(ngModel)]="args.billing_address"/>
+ </div>
+ </div>
+ <div class="row mt-2">
+ <div class="col-lg-4"><label i18n>City, town or village</label></div>
+ <div class="col-lg-8">
+ <input type='text' class="form-control" [(ngModel)]="args.billing_city"/>
+ </div>
+ </div>
+ <div class="row mt-2">
+ <div class="col-lg-4"><label i18n>State or province</label></div>
+ <div class="col-lg-8">
+ <input type='text' class="form-control" [(ngModel)]="args.billing_state"/>
+ </div>
+ </div>
+ <div class="row mt-2">
+ <div class="col-lg-4"><label i18n>ZIP or postal code</label></div>
+ <div class="col-lg-8">
+ <input type='text' class="form-control" [(ngModel)]="args.billing_zip"/>
+ </div>
+ </div>
+ </ng-container>
+
+ <div class="row mt-2">
+ <div class="col-lg-4"><label i18n>Note</label></div>
+ <div class="col-lg-8">
+ <input type='text' class="form-control" [(ngModel)]="args.note"/>
+ </div>
+ </div>
+
+ </div>
+ </div>
+
+ </div>
+ <div class="modal-footer">
+ <button type="button" class="btn btn-success" [disabled]="!saveable()"
+ (click)="submit(args)" i18n>Submit</button>
+ <button type="button" class="btn btn-warning"
+ (click)="close()" i18n>Cancel</button>
+ </div>
+</ng-template>
--- /dev/null
+import {Component, OnInit, Input, ViewChild} from '@angular/core';
+import {Observable} from 'rxjs';
+import {switchMap} from 'rxjs/operators';
+import {IdlObject, IdlService} from '@eg/core/idl.service';
+import {NetService} from '@eg/core/net.service';
+import {EventService} from '@eg/core/event.service';
+import {ToastService} from '@eg/share/toast/toast.service';
+import {PcrudService} from '@eg/core/pcrud.service';
+import {AuthService} from '@eg/core/auth.service';
+import {OrgService} from '@eg/core/org.service';
+import {ServerStoreService} from '@eg/core/server-store.service';
+import {DialogComponent} from '@eg/share/dialog/dialog.component';
+import {NgbModal, NgbModalOptions} from '@ng-bootstrap/ng-bootstrap';
+import {StringComponent} from '@eg/share/string/string.component';
+import {ComboboxEntry, ComboboxComponent} from '@eg/share/combobox/combobox.component';
+import {CircService} from './circ.service';
+
+export interface CreditCardPaymentParams {
+ where_process?: 0 | 1,
+ approval_code?: string,
+ expire_month?: number,
+ expire_year?: number,
+ billing_first?: string,
+ billing_last?: string,
+ billing_address?: string,
+ billing_city?: string,
+ billing_state?: string,
+ billing_zip?: string,
+ note?: string
+}
+
+/* Dialog for collecting credit card payment information */
+
+@Component({
+ selector: 'eg-credit-card-dialog',
+ templateUrl: 'credit-card-dialog.component.html'
+})
+
+export class CreditCardDialogComponent
+ extends DialogComponent implements OnInit {
+
+ @Input() patron: IdlObject; // au, fleshed with billing address
+ args: CreditCardPaymentParams;
+ supportsExternal: boolean;
+ thisYear = new Date().getFullYear();
+
+ constructor(
+ private modal: NgbModal,
+ private toast: ToastService,
+ private net: NetService,
+ private idl: IdlService,
+ private evt: EventService,
+ private pcrud: PcrudService,
+ private circ: CircService,
+ private org: OrgService,
+ private serverStore: ServerStoreService,
+ private auth: AuthService) {
+ super(modal);
+ }
+
+ ngOnInit() {
+
+ this.onOpen$.subscribe(_ => {
+
+ this.args = {
+ billing_first: this.patron.first_given_name(),
+ billing_last: this.patron.family_name(),
+ };
+
+ const addr =
+ this.patron.billing_address() || this.patron.mailing_address();
+
+ if (addr) {
+ this.args.billing_address = addr.street1() +
+ (addr.street2() ? ' ' + addr.street2() : '');
+ this.args.billing_city = addr.city();
+ this.args.billing_state = addr.state();
+ this.args.billing_zip = addr.post_code();
+ }
+
+ this.supportsExternal = false;
+
+ this.serverStore.getItem('credit.processor.default')
+ .then(processor => {
+ if (processor && processor !== 'Stripe') {
+ this.supportsExternal = true;
+ this.args.where_process = 1;
+ }
+ })
+ });
+ }
+
+ saveable(): boolean {
+ if (!this.args) { return false; }
+
+ if (this.args.where_process === 0) {
+ return Boolean(this.args.approval_code);
+ }
+
+ return Boolean(this.args.expire_month) && Boolean(this.args.expire_year);
+ }
+
+
+ submit() {
+ }
+}
+