Skip to content

Commit

Permalink
Merge pull request #1095 from CruGlobal/use-same-donation-history-end…
Browse files Browse the repository at this point in the history
…point

Use same donation history endpoint
  • Loading branch information
wrandall22 authored Mar 27, 2024
2 parents 34e1fad + 000f9d8 commit 71dd490
Show file tree
Hide file tree
Showing 5 changed files with 162 additions and 62 deletions.
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
import angular from 'angular'
import historicalGift from './historicalGift/historicalGift.component'
import donationsService from 'common/services/api/donations.service'
import profileService from 'common/services/api/profile.service'
import template from './historicalView.tpl.html'
import moment from 'moment'
import cloneDeep from 'lodash/cloneDeep'

const componentName = 'historicalView'

class HistoricalView {
/* @ngInject */
constructor ($log, donationsService) {
constructor ($log, donationsService, profileService) {
this.$log = $log
this.donationsService = donationsService
this.profileService = profileService
}

$onChanges (changes) {
Expand All @@ -22,10 +26,13 @@ class HistoricalView {
this.loadingGiftsError = false
this.setLoading({ loading: true })
this.historicalGifts = undefined
if (angular.isDefined(this.subscriber)) this.subscriber.unsubscribe()
this.subscriber = this.donationsService.getHistoricalGifts(year, month).subscribe((historicalGifts) => {
if (angular.isDefined(this.subscriber)) {
this.subscriber.unsubscribe()
}
const yearToQuery = this.isRecent(year, month) ? 'recent' : year
this.subscriber = this.donationsService.getRecipients(yearToQuery).subscribe((historicalGifts) => {
delete this.subscriber
this.historicalGifts = historicalGifts || []
this.historicalGifts = this.parseHistoricalGifts(historicalGifts, year, month) || []
this.setLoading({ loading: false })
}, (error) => {
delete this.subscriber
Expand All @@ -34,11 +41,55 @@ class HistoricalView {
this.loadingGiftsError = true
})
}

isRecent (year, month) {
const today = moment()
const queryDate = moment(`${year}/${month}/01`, 'YYYY/MM/DD')
return today.diff(queryDate, 'months', true) <= 3
}

parseHistoricalGifts (historicalGifts, year, month) {
if (!historicalGifts.length || !historicalGifts[0].donations) {
return historicalGifts
}

const filteredGifts = cloneDeep(historicalGifts).filter((historicalGift) => {
historicalGift.donations = historicalGift.donations.filter((donation) => {
const transactionDate = donation['historical-donation-line']['transaction-date']
const momentDate = moment(transactionDate['display-value'], 'YYYY/MM/DD')

return momentDate.year() === year && (momentDate.month() + 1) === month
})
return historicalGift.donations.length > 0
})

return filteredGifts.flatMap((donationSummary) => {
donationSummary.donations.forEach(donation => {
const paymentInstrumentLinkUri = donation['payment-instrument-link'] && donation['payment-instrument-link'].uri
if (paymentInstrumentLinkUri) {
this.profileService.getPaymentMethod(paymentInstrumentLinkUri, true).subscribe((paymentMethod) => {
donation.paymentmethod = paymentMethod
}, error => {
this.$log.error(`Failed to load payment instrument at ${paymentInstrumentLinkUri}`, error)
})
}

const recurringDonationLink = donationSummary['recurring-donations-link']
if (recurringDonationLink) {
this.donationsService.getRecipientsRecurringGifts(recurringDonationLink).subscribe(recurringGifts => {
donation.recurringdonation = recurringGifts.donations ? recurringGifts.donations[0] : undefined
})
}
})
return donationSummary.donations
})
}
}
export default angular
.module(componentName, [
historicalGift.name,
donationsService.name
donationsService.name,
profileService.name
])
.component(componentName, {
controller: HistoricalView,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import module from './historicalView.component'
import { Observable } from 'rxjs/Observable'
import 'rxjs/add/observable/of'
import 'rxjs/add/observable/throw'
import recipientResponse from '../../../../common/services/api/fixtures/cortex-donations-recipient.fixture'

describe('your giving', function () {
describe('historical view', () => {
Expand All @@ -13,14 +14,15 @@ describe('your giving', function () {
beforeEach(inject((_$componentController_) => {
$ctrl = _$componentController_(module.name, {}, {
year: 2016,
month: { month: 9 },
month: { month: 5 },
setLoading: jest.fn()
})
}))

it('to be defined', function () {
expect($ctrl).toBeDefined()
expect($ctrl.donationsService).toBeDefined()
expect($ctrl.profileService).toBeDefined()
})

describe('$onChanges()', () => {
Expand All @@ -32,7 +34,7 @@ describe('your giving', function () {
$ctrl.year = 2018
$ctrl.$onChanges({ year: { currentValue: 2018 } })

expect($ctrl.loadGifts).toHaveBeenCalledWith(2018, 9)
expect($ctrl.loadGifts).toHaveBeenCalledWith(2018, 5)
})

it('should reload historical gifts when month changes', () => {
Expand All @@ -45,7 +47,7 @@ describe('your giving', function () {
it('should reload historical gifts when reload changes to true', () => {
$ctrl.$onChanges({ reload: { currentValue: true } })

expect($ctrl.loadGifts).toHaveBeenCalledWith(2016, 9)
expect($ctrl.loadGifts).toHaveBeenCalledWith(2016, 5)
})

it('should not reload historical gifts when reload changes to false', () => {
Expand All @@ -65,36 +67,60 @@ describe('your giving', function () {
let subscriberSpy
beforeEach(() => {
subscriberSpy = { unsubscribe: jest.fn() }
jest.spyOn($ctrl.donationsService, 'getHistoricalGifts')
jest.spyOn($ctrl.donationsService, 'getRecipients')
jest.spyOn($ctrl.donationsService, 'getRecipientsRecurringGifts')
jest.spyOn($ctrl.profileService, 'getPaymentMethod')
})

it('should parse and keep the historical gift data that we care about', () => {
const paymentInstrument = {
'account-type': 'Checking',
'bank-name': 'Test Bank',
'default-on-profile': false,
description: 'Test Bank Checking **0000',
'display-account-number': '0000',
'encrypted-account-nmber': 'encrypted-value',
id: 'base-32-encoded-id',
links: [],
messages: [],
name: 'Cru Payment Instrument',
'routing-number': '123123123',
self: {},
'siebel-row-id': '1-TEST'
}
const recurringGift = {
rate: { recurrence: { interval: 'Monthly' } }
}

const expectedHistoricalGifts = [
{ ...recipientResponse['donation-summaries'][0].donations[0], paymentmethod: paymentInstrument, recurringdonation: recurringGift },
{ ...recipientResponse['donation-summaries'][1].donations[0], recurringdonation: recurringGift },
{ ...recipientResponse['donation-summaries'][2].donations[0], recurringdonation: recurringGift }
]

$ctrl.donationsService.getRecipients.mockImplementation(() => Observable.of(recipientResponse['donation-summaries']))
$ctrl.donationsService.getRecipientsRecurringGifts.mockImplementation(() => Observable.of({ donations: [ recurringGift ] }))
$ctrl.profileService.getPaymentMethod.mockImplementation(() => Observable.of(paymentInstrument))
$ctrl.subscriber = subscriberSpy
$ctrl.loadGifts(2017, 1)
expect($ctrl.historicalGifts).toEqual(expectedHistoricalGifts)
})

it('loads historical gifts by year and month if current request is pending', () => {
$ctrl.donationsService.getHistoricalGifts.mockImplementation(() => Observable.of(['a', 'b']))
$ctrl.donationsService.getRecipients.mockImplementation(() => Observable.of(['a', 'b']))
$ctrl.subscriber = subscriberSpy
$ctrl.loadGifts(2016, 9)
$ctrl.loadGifts(2016, 5)

expect($ctrl.loadingGiftsError).toEqual(false)
expect($ctrl.setLoading).toHaveBeenCalledWith({ loading: true })
expect(subscriberSpy.unsubscribe).toHaveBeenCalled()
expect($ctrl.donationsService.getHistoricalGifts).toHaveBeenCalledWith(2016, 9)
expect($ctrl.donationsService.getRecipients).toHaveBeenCalledWith(2016)
expect($ctrl.historicalGifts).toEqual(['a', 'b'])
expect($ctrl.setLoading).toHaveBeenCalledWith({ loading: false })
})

it('loads historical gifts by year and month', () => {
$ctrl.donationsService.getHistoricalGifts.mockImplementation(() => Observable.of(['c', 'd']))
$ctrl.loadGifts(2015, 8)

expect($ctrl.loadingGiftsError).toEqual(false)
expect($ctrl.setLoading).toHaveBeenCalledWith({ loading: true })
expect(subscriberSpy.unsubscribe).not.toHaveBeenCalled()
expect($ctrl.donationsService.getHistoricalGifts).toHaveBeenCalledWith(2015, 8)
expect($ctrl.historicalGifts).toEqual(['c', 'd'])
expect($ctrl.setLoading).toHaveBeenCalledWith({ loading: false })
})

it('sets loading false on error ', () => {
$ctrl.donationsService.getHistoricalGifts.mockImplementation(() => Observable.throw('error'))
$ctrl.donationsService.getRecipients.mockImplementation(() => Observable.throw('error'))
$ctrl.loadGifts(1990, 1)

expect($ctrl.setLoading).toHaveBeenCalledWith({ loading: true })
Expand All @@ -103,6 +129,33 @@ describe('your giving', function () {
expect($ctrl.loadingGiftsError).toEqual(true)
expect($ctrl.$log.error.logs[0]).toEqual(['Error loading historical gifts', 'error'])
})

it('should log an error when there is a problem with loading a payment method', () => {
$ctrl.donationsService.getRecipients.mockImplementation(() => Observable.of(recipientResponse['donation-summaries']))
$ctrl.profileService.getPaymentMethod.mockImplementation(() => Observable.throw('error'))
$ctrl.loadGifts(2017, 1)

expect($ctrl.$log.error.logs[0])
.toEqual([
`Failed to load payment instrument at ${recipientResponse['donation-summaries'][0].donations[0]['payment-instrument-link'].uri}`,
'error'])
})
})

describe('isRecent', () => {
beforeEach(() => {
Date.now = jest.fn(() => new Date('2024-03-22T05:00:00.000Z'))
})

it.each([
[1, 2024, true],
[2, 2024, true],
[3, 2024, true],
[12, 2023, false],
[2, 2023, false],
])('when the date is %s/%s it should be %s', (month, year, expected) => {
expect($ctrl.isRecent(year, month)).toBe(expected)
})
})
})
})
12 changes: 0 additions & 12 deletions src/common/services/api/donations.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,17 +48,6 @@ const DonationsService = /* @ngInject */ function (cortexApiService, profileServ
})
}

function getHistoricalGifts (year, month) {
return cortexApiService
.get({
path: ['donations', 'historical', cortexApiService.scope, year, month],
zoom: {
gifts: 'element[],element:paymentmethod,element:recurringdonation'
}
})
.pluck('gifts')
}

function getReceipts (data) {
return cortexApiService
.post({
Expand Down Expand Up @@ -166,7 +155,6 @@ const DonationsService = /* @ngInject */ function (cortexApiService, profileServ
}

return {
getHistoricalGifts: getHistoricalGifts,
getRecipients: getRecipients,
getRecipientsRecurringGifts: getRecipientsRecurringGifts,
getReceipts: getReceipts,
Expand Down
12 changes: 0 additions & 12 deletions src/common/services/api/donations.service.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,18 +54,6 @@ describe('donations service', () => {
})
})

describe('getHistoricalGifts( year, month )', () => {
it('should load historical gifts by year and month', () => {
$httpBackend
.expectGET('https://give-stage2.cru.org/cortex/donations/historical/crugive/2016/9?zoom=element,element:paymentmethod,element:recurringdonation')
.respond(200, historicalResponse)
donationsService.getHistoricalGifts(2016, 9).subscribe((historicalGifts) => {
expect(historicalGifts).toEqual(expect.any(Array))
})
$httpBackend.flush()
})
})

describe('getReceipts( data )', () => {
it('should load receipts', () => {
const response = [{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,16 @@ export default {
'given-through-description': 'Steve',
'master-account': false,
'pass-through': false,
'payment-method-id': 'giydambvga=',
'payment-instrument-id': 'gi3tmyrsgazwiljygeytqljugaztkljygjrtmllemqydcyzygi3gmojsmm=',
'payment-type': 'Discover',
'related-account-description': 'Steve',
'transaction-date': { 'display-value': '2017-01-10', value: 1484006400000 },
'transaction-sub-type': 'Credit Card'
},
'payment-instrument-link': {
rel: 'paymentmethod',
type: 'elasticpath.paymentmethods.payment-method',
uri: '/paymentmethods/crugive/giydambvga='
rel: 'paymentinstrument',
type: 'elasticpath.paymentinstruments.purchase-payment-instrument',
uri: '/selfservicepaymentinstruments/crugive/gi3tmyrsgazwiljygeytqljugaztkljygjrtmllemqydcyzygi3gmojsmm='
}
}],
'most-recent-donation': {
Expand All @@ -53,16 +53,16 @@ export default {
'given-through-description': 'Steve',
'master-account': false,
'pass-through': false,
'payment-method-id': 'giydambvga=',
'payment-instrument-id': 'gi3tmyrsgazwiljygeytqljugaztkljygjrtmllemqydcyzygi3gmojsmm=',
'payment-type': 'Discover',
'related-account-description': 'Steve',
'transaction-date': { 'display-value': '2017-01-10', value: 1484006400000 },
'transaction-sub-type': 'Credit Card'
},
'payment-instrument-link': {
rel: 'paymentmethod',
type: 'elasticpath.paymentmethods.payment-method',
uri: '/paymentmethods/crugive/giydambvga='
rel: 'paymentinstrument',
type: 'elasticpath.paymentinstruments.purchase-payment-instrument',
uri: '/selfservicepaymentinstruments/crugive/gi3tmyrsgazwiljygeytqljugaztkljygjrtmllemqydcyzygi3gmojsmm='
}
},
'recurring-donations-link': {
Expand Down Expand Up @@ -172,7 +172,27 @@ export default {
'designation-active': true,
'designation-name': '"God Loves Lebanon" Initiative(2798344)',
'designation-number': '2798344',
donations: [],
donations: [{
'donation-row-id': '1-26020D',
'donation-status': 'Closed',
'historical-donation-line': {
amount: 20,
anonymous: false,
'campaign-code': '000000',
completed: false,
'designation-active': true,
'designation-name': '"God Loves Lebanon" Initiative(2798344)',
'designation-number': '2798344',
'given-through-description': 'Steve',
'master-account': false,
'pass-through': false,
'payment-instrument-id': 'gi3tmyrsgazwiljygeytqljugaztkljygjrtmllemqydcyzygi3gmojsmm=',
'payment-type': 'EFT',
'related-account-description': 'Steve',
'transaction-date': { 'display-value': '2017-02-22', value: 1471824000000 },
'transaction-sub-type': 'EFT'
}
}],
'most-recent-donation': {
'donation-row-id': '1-36020D',
'donation-status': 'Closed',
Expand All @@ -187,16 +207,16 @@ export default {
'given-through-description': 'Steve',
'master-account': false,
'pass-through': false,
'payment-method-id': 'giydambrg4=',
'payment-instrument-id': 'gi3tmyrsgazwiljygeytqljugaztkljygjrtmllemqydcyzygi3gmojsmm=',
'payment-type': 'EFT',
'related-account-description': 'Steve',
'transaction-date': { 'display-value': '2016-08-22', value: 1471824000000 },
'transaction-sub-type': 'EFT'
},
'payment-instrument-link': {
rel: 'paymentmethod',
type: 'elasticpath.paymentmethods.payment-method',
uri: '/paymentmethods/crugive/giydambrg4='
rel: 'paymentinstrument',
type: 'elasticpath.paymentinstruments.purchase-payment-instrument',
uri: '/selfservicepaymentinstruments/crugive/gi3tmyrsgazwiljygeytqljugaztkljygjrtmllemqydcyzygi3gmojsmm='
}
},
'recurring-donations-link': {
Expand Down

0 comments on commit 71dd490

Please sign in to comment.