File

src/app/services/payment.service.ts

Index

Properties

Properties

ids
ids: string[]
Type : string[]
import { DatePipe } from '@angular/common';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import { Observable } from 'rxjs/Observable';
import { combineLatest } from 'rxjs/observable/combineLatest';
import { catchError, delay, filter, map, tap } from 'rxjs/operators';
import { ERROR_MESSAGE, LOCALE, PAYMENT_API } from '../app.constants';
import {
  CreatePaymentRequest,
  P2PPaymentModel,
  Payment,
  Template,
  PaymentInFlightResponse,
  BankAccount,
} from '../models';
import { DuplicateInfo } from '../models/duplicate-info';
import { AppState } from '../stores/app-state.store';
import { ErrorStore } from '../stores/error.store';
import { AuthService } from './auth.service';
import { DeliveryDateService } from './delivery-date.service';

interface GetPaymentsResponse {
  Data: P2PPaymentModel[];
}

interface CreatePaymentsResponse {
  ids: string[];
}

@Injectable()
export class PaymentService {
  private headers = new HttpHeaders({
    'Cache-Control': 'no-cache',
    Pragma: 'no-cache',
    Expires: '-1',
  });
  private datePipe = new DatePipe(LOCALE);
  private payments: Payment[] = null;
  private publisher = new BehaviorSubject<Payment[]>(null);
  public payments$ = this.publisher.asObservable();

  constructor(
    private http: HttpClient,
    private errorService: ErrorStore,
    private authService: AuthService,
    private app: AppState,
    private deliveryDateService: DeliveryDateService
  ) {}

  private publish() {
    this.publisher.next(this.payments);
  }

  cachePayment(payment: Payment): void {
    const pmt = payment;
    pmt.paymentDateFormatted = this.datePipe.transform(new Date(), 'shortDate');
    pmt.status = 'InFlight';
    this.payments.push(pmt);
    this.payments = this.payments.sort((pmt1: Payment, pmt2: Payment) => {
      return this.sortByDateThenName(pmt1, pmt2);
    });
    this.publish();
  }

  getTemplatesAsPayments(): Observable<P2PPaymentModel[]> {
    const url = `${PAYMENT_API}/GetTemplatesAsPayments`;
    return this.http.get<GetPaymentsResponse>(url, { headers: this.headers }).pipe(
      map((res) => res.Data),
      catchError((error) => {
        const title = 'Failed To Retrieve Payments';
        return this.handleError(error, title);
      })
    );
  }

  cancelPayment(id: string): Observable<boolean> {
    const url = `${PAYMENT_API}/${id}`;
    return this.http.delete(url, { headers: this.headers }).pipe(
      delay(5000),
      map((res) => {
        return true;
      }),
      catchError((error) => {
        const title = 'Failed To Cancel Payment';
        return this.handleError(error, title);
      })
    );
  }

  dismissPaymentErrorMessage(hash: string): Observable<boolean> {
    const url = `${PAYMENT_API}/${hash}`;
    return this.http.delete(url, { headers: this.headers }).pipe(
      map((res) => {
        return true;
      }),
      catchError((error) => {
        const title = 'Failed To Dismiss Payment Error Message';
        return this.handleError(error, title);
      })
    );
  }

  createPayment(payment: Payment, template: Template): Observable<Payment> {
    const request = {
      templateId: template.id,
      amount: payment.amount,
      memo: payment.memo,
      name: template.name,
      p2PPayToEmailAddress: template.p2PPayToEmailAddress,
      p2PPayToPhoneNumber: template.p2PPayToPhoneNumber,
      secret: template.secret,
      payFromBankAccountDescription: template.payFromBankAccount.accountType,
      payFromAccount: template.payFromBankAccount.accountNumber,
      defaultContactMethod: template.defaultContactMethod,
    } as CreatePaymentRequest;
    if (this.app.acknowledgeDuplicate) {
      request.duplicateOf = !!this.app.duplicateInfo.paymentId
        ? this.app.duplicateInfo.paymentId
        : `${this.app.duplicateInfo.key}|${this.app.duplicateInfo.hash}`;
    }

    // Set Up the Feature Flag Here
    const url = `${PAYMENT_API}/create`;
    return this.http.post<PaymentInFlightResponse>(url, request).pipe(
      map((response) => {
        const payment = new Payment();
        payment.displayName = request.name;
        payment.inFlightKey = response.key;
        payment.hash = response.hash;
        payment.amount = request.amount;
        payment.memo = request.memo;
        payment.status = 'InFlight'; // todo get text from product
        payment.p2PPayToEmailAddress = request.p2PPayToEmailAddress;
        payment.p2PPayToPhoneNumber = request.p2PPayToPhoneNumber;
        payment.secret = request.secret;
        payment.payFromBankAccountDescription = request.payFromBankAccountDescription;
        payment.payFromAccount = request.payFromAccount;
        payment.defaultContactMethod = request.defaultContactMethod;

        // todo store inflight payment dto into session storage for on refresh / leave & return use cases
        this.cachePayment(payment);
        this.payments = this.payments.sort((pmt1: Payment, pmt2: Payment) => {
          return this.sortByDateThenName(pmt1, pmt2);
        });
        this.publish();
        return payment;
      }),
      catchError((error) => {
        const title = 'Failed To Create Payment';
        return this.handleError(error, title);
      })
    );
  }

  getPayment(id: string): Observable<Payment> {
    try {
      return this.payments$.pipe(
        filter((payments) => payments !== null && payments !== undefined),
        map((payments) => {
          let found: any;
          if (id.length === 36) {
            found = payments.filter((p) => p.id === id);
          } else {
            found = payments.filter((p) => p.hash === id);
          }
          const match = found.length > 0 ? found[0] : null;
          return match;
        })
      );
    } catch (error) {
      const title = 'Failed To Retrieve Payment';
      return this.handleError(error, title);
    }
  }

  getPayments(useCache = true): Observable<Payment[]> {
    if (useCache && this.payments != null) {
      return Observable.of(this.payments);
    }
    const url = `${PAYMENT_API}`;
    return this.http.get<Payment[]>(url, { headers: this.headers }).pipe(
      tap((payments) =>
        payments.forEach((payment) =>
          // tslint:disable-next-line:one-line
          {
            // Sets the payFromAccount Information for UI
            let account: BankAccount = new BankAccount();
            account.accountNumber = payment.payFromAccount;
            account.accountType = payment.payFromBankAccountDescription;
            payment.account = account;

            // Formats the date to not use local timezone
            if (payment.networkSendDate && payment.networkSendDate.length > 0) {
              const deliveryDateValue = payment.networkSendDate.toString().split('T');
              payment.deliveryDate = deliveryDateValue[0].concat('T01:00:00');
            }
          }
        )
      ),
      map((payments) => {
        this.payments = payments.map((payment) => new Payment(payment));
        this.publish();
        return payments;
      }),
      catchError((error) => {
        const title = 'Failed To Retrieve Payments';
        return this.handleError(error, title);
      })
    );
  }

  private handleError(error: any, title: string) {
    this.errorService.addError(title, ERROR_MESSAGE);
    this.errorService.displayErrors();
    return Observable.of(null);
  }

  findDuplicate(): Observable<Payment> {
    try {
      return combineLatest(this.payments$, this.deliveryDateService.date$).pipe(
        filter(([payments, nextBusinessDate]) => !!payments && !!nextBusinessDate),
        map(([payments, nextBusinessDate]) => {
          const foundPayment = payments
            .filter((p) => {
              if (p.error && p.error.length > 0) {
                return false;
              }
              if (p.status.toLowerCase() === 'inflight') {
                return true;
              }
              const date1 = new Date(p.paymentDateFormatted);
              const date2 = new Date(nextBusinessDate);
              return date1.getTime() === date2.getTime(); // use date as ms to compare date strings even if formatted differently s
            })
            .filter((p) => p.amount === this.app.payment.amount)
            .filter((p) => p.payToName === this.app.template.name)
            .reduce((x, p) => {
              console.log('matched', p);
              return p;
            }, null); // return only item in the array instead of returning an array
          return foundPayment;
        })
      );
    } catch (error) {
      const title = 'Failed To Retrieve Payment';
      return this.handleError(error, title);
    }
  }

  acknowledgeDuplicate(customerId: string, payment: Payment) {
    const info: DuplicateInfo = {};
    if (payment.inFlightKey && payment.inFlightKey.length > 0) {
      info.hash = payment.hash;
      info.key = payment.inFlightKey;
    } else {
      info.paymentId = payment.id;
    }
    console.error('acknowleded duplicate of', info);
    this.app.acknowledgeDuplicate = true;
    this.app.duplicateInfo = info;
  }

  private sortByDateThenName(pmt1: Payment, pmt2: Payment): number {
    let result = this.sortByDateAsc(pmt1, pmt2);
    if (result === 0) {
      result = this.sortByNameAsc(pmt1, pmt2);
    }
    return result;
  }

  private sortByDateAsc(pmt1: Payment, pmt2: Payment): number {
    const dt1 = new Date(pmt1.paymentDate);
    const dt2 = new Date(pmt2.paymentDate);
    if (dt1 > dt2) {
      return 1;
    }
    if (dt1 < dt2) {
      return -1;
    }
    return 0;
  }

  private sortByNameAsc(pmt1: Payment, pmt2: Payment): number {
    const name1 = pmt1.payToName;
    const name2 = pmt2.payToName;
    if (name1 > name2) {
      return 1;
    }
    if (name1 < name2) {
      return -1;
    }
    return 0;
  }
}

results matching ""

    No results matching ""