import { Injectable } from '@angular/core'; import { CLIENT_SETTINGS_SERVICE_MOCK } from '@core/mocks/client-settings.service.mock'; import { CURRENCY_SERVICE_MOCK } from '@core/mocks/currency.service.mock'; import { GCMockModule } from '@core/mocks/gc-module.mock'; import { MASKING_SERVICE_MOCK } from '@core/mocks/masking.service.mock'; import { CyclesAPI } from '@core/typings/api/cycles.typing'; import { Budget, BudgetDashboardFundingSource, BudgetDetail, BudgetFundingSourceCombo, FundingSource, FundingSourceTypes } from '@core/typings/budget.typing'; import { Payment, PaymentFromApi, ProcessingTypes } from '@core/typings/payment.typing'; import { ProgramDetailFromApi } from '@core/typings/program.typing'; import { PaymentStatus } from '@core/typings/status.typing'; import { CyclesUI } from '@core/typings/ui/cycles.typing'; import { WorkflowDetail } from '@core/typings/workflow.typing'; import { PaginatedResponse, SimpleStringMap } from '@yourcause/common'; import { BeforeEach, Spec, TestCase } from '@yourcause/test-decorators'; import { DescribeAngularService } from '@yourcause/test-decorators/angular'; import { expect } from 'chai'; import { AwardResources } from './award.resources'; import { AwardService } from './award.service'; import { ApproveAwardPayModalPayload, AwardForDash, AwardFromApi, AwardModalPayload, MyAward } from './typings/award.typing'; @Injectable({ providedIn: 'root' }) @DescribeAngularService(AwardService, { imports: [ GCMockModule ], providers: [ CURRENCY_SERVICE_MOCK, CLIENT_SETTINGS_SERVICE_MOCK, MASKING_SERVICE_MOCK ] }) export class AwardServiceSpec implements Spec { awardId = 1; paymentId = 2; budgetId = 3; fundingSourceId = 4; budgetFundingSource: BudgetFundingSourceCombo = { budget: { id: this.budgetId, name: 'Test Budget', description: '', budgetFundingSources: [] }, fundingSource: { fundingSourceId: this.fundingSourceId, budgetId: this.budgetId, fundingSourceType: FundingSourceTypes.DOLLARS, totalAmount: 1000, active: true, fundingSourceName: 'Test funding source', numberOfPayments: 2, totalAmountPayments: 800, totalUnitsPayments: 0, totalPendingPayments: 400, amountRemaining: 0, amountUnavailable: 0, isOverAllocationSource: false, processingTypeId: ProcessingTypes.YourCause, isClosed: false }, comboId: `${this.budgetId}-${this.fundingSourceId}`, isClosed: false }; cashPaymentFromApi: PaymentFromApi = { paymentId: this.paymentId, awardId: this.awardId, budgetId: this.budgetId, budgetName: 'Test Budget', fundingSourceId: this.fundingSourceId, fundingSourceName: 'Test Funding Source', fundingSourceType: FundingSourceTypes.DOLLARS, scheduledDate: new Date().toISOString(), totalAmount: 500, paymentTags: [], canAdjustPayment: true, notes: '', status: PaymentStatus.Pending, currencyRequested: 'USD', currencyRequestedAmountEquivalent: 500, inKindItems: [], substatus: null, reissuedForPaymentId: null, reissuedInPaymentId: null, batchName: '', paymentType: null }; paymentsToSum: Partial[] = [{ statusId: PaymentStatus.Pending, amount: 600, currencyRequestedAmountEquivalent: 600 }, { statusId: PaymentStatus.Scheduled, amount: 1000, currencyRequestedAmountEquivalent: 1000 }]; cashPayment: Payment; awardsFromApi: AwardFromApi[] = [{ id: this.awardId, amount: 500, description: '', createdDate: new Date().toISOString(), totalCash: 500, sendEmail: true, payments: [ this.cashPaymentFromApi ], currencyRequested: 'USD', currencyRequestedAmountEquivalent: 500, awardType: FundingSourceTypes.DOLLARS, inKindItems: [], organizationEligibleForGivingStatus: null }]; awardModalResponse: AwardModalPayload = { id: null, amount: 500, description: 'Award desc', sendEmail: true, awardDate: new Date().toISOString(), clientEmailTemplateId: 0, currencyRequested: 'USD', amountEquivalent: 500, currencyExchangeRate: null, customMessage: 'Custom message', awardType: FundingSourceTypes.DOLLARS, awardedItems: [], paidItems: [], tagMap: {}, addedPayment: null, removedPayment: null, updatedPayment: null, addAnotherPayment: false, emailOptionsModel: { bccEmails: [], ccEmails: [], attachments: [] } }; awardInsightsResult: PaginatedResponse = { records: [{ award: { id: this.awardId, amount: 500, createdDate: '', createdBy: null, createByName: '', awardDate: '', awardRemaining: 200, associatedApplicationId: 2, inKindItems: [] }, program: { id: 5, name: 'Program' }, applicant: { id: 4, fullName: 'Tina Conway', email: '', phoneNumber: '', address1: '', address2: '', city: '', country: '', postalCode: '', state: '' }, organization: { id: 6, name: 'Test Org', charityId: null, phoneNumber: '', address1: '', address2: '', city: '', country: '', postalCode: '', state: '', identification: '', isPrivateOrg: false, imageUrl: '', guid: '' }, budgets: [], payments: [], isMasked: false, canViewMaskedApplicantInfo: true }], recordCount: 1 }; cycle: CyclesUI.ProgramCycle = { id: 9, name: 'name', startDate: 'date', endDate: 'date2', budgetIds: [2968, 2969], defaultCashBudgetId: this.budgetFundingSource.budget.id, defaultCashFundingSourceId: this.budgetFundingSource.fundingSource.budgetId, defaultInKindBudgetId: 6, defaultInKindFundingSourceId: 5, clientOrganizationsProcessingTypeId: ProcessingTypes.YourCause, isArchived: false, hasApplications: false, createdBy: 'morgan', createdDate: 'today', updatedBy: 'morgan', updatedDate: 'tomorrow', createImpersonatedBy: 'creator', impersonatedBy: 'imposter', isClientProcessing: true }; cycleTop10: CyclesAPI.CycleTop10[] = [{ cycleId: 9, cycleName: 'name', numberOfAwards: 0, awardAmount: 10, paymentAmount: 10 }]; approveAwardPayModalPayload: ApproveAwardPayModalPayload = { applicationId: 4, sendEmail: false, customMessage: 'oh no', clientEmailTemplateId: 1, emailOptionsModel: { ccEmails: null, bccEmails: null, attachments: null }, usedOverage: true }; budget: BudgetDetail = { id: 20104, name: '02/20 Budget Dash Test', description: '02/20/19', active: true, budgetFundingSources: [{ budgetId: this.budgetId, processingTypeId: ProcessingTypes.Client, fundingSourceId: 4359, fundingSourceType: 1, totalAmount: 1000.0000, totalUnits: 0, active: true, fundingSourceName: 'Corporate Funding Source', numberOfPayments: 2, amountRemaining: 0, amountUnavailable: 0, totalAmountPayments: 1000.0000, totalUnitsPayments: 0, isOverAllocationSource: false, isClosed: false }, { processingTypeId: ProcessingTypes.Client, budgetId: 20104, fundingSourceId: 18203, fundingSourceType: 1, totalAmount: 2000.0000, totalUnits: 0, active: true, amountRemaining: 0, amountUnavailable: 0, fundingSourceName: 'Funding Source A', numberOfPayments: 1, totalAmountPayments: 2000.0000, totalUnitsPayments: 0, isOverAllocationSource: false, isClosed: false }, { budgetId: 20104, fundingSourceId: 38647, processingTypeId: ProcessingTypes.Client, fundingSourceType: 1, totalAmount: 300.0000, totalUnits: 0, active: true, amountRemaining: 0, amountUnavailable: 0, fundingSourceName: 'Overage', numberOfPayments: 1, totalAmountPayments: 100.0000, totalUnitsPayments: 0, isOverAllocationSource: true, isClosed: false }] }; budgets: Budget[] = [ { id: 2968, name: '2018 Grants', description: 'Budget', fundingSourceType: 1, numberOfPayments: 45, numberOfFundingSources: 4, totalAmount: 3065588.0000, totalUnits: 0, totalAmountAvailable: 2973110.0000, totalUnitsAvailable: 0, overageAmount: 162476.1600, totalSpent: 92478.0000, totalSpentUnits: 0, totalSpentOverage: 1500.0000, totalRemainingOverage: 160976.1600, totalUnitsAvailableAmount: 500, totalSpentUnitsAmount: 0, totalRemainingUnitsAmount: 0, totalUnavailableAmount: 0, hasClientProcessingType: true }, { id: 2969, name: 'Discretionary Fund', description: 'For use in one', fundingSourceType: 1, numberOfPayments: 9, numberOfFundingSources: 2, totalAmount: 750000.0000, totalUnits: 0, totalAmountAvailable: 741824.0000, totalUnitsAvailable: 0, overageAmount: null, totalSpent: 8176.0000, totalSpentUnits: 0, totalSpentOverage: 0.0, totalRemainingOverage: 0.0, totalUnitsAvailableAmount: 500, totalSpentUnitsAmount: 0, totalRemainingUnitsAmount: 0, totalUnavailableAmount: 0, hasClientProcessingType: true }]; budgetStats = { totalAllocated: 3000.0000, numberOfFundingSources: 2, totalSpent: 3000.0000, numberOfPayments: 4, totalRemaining: 0.0000, totalAllocatedUnits: 0, totalSpentUnits: 0, totalRemainingUnits: 0, totalAllocatedOverage: 300.0000, totalSpentOverage: 100.0000, totalRemainingOverage: 200.0000, totalUnavailableAmount: 0, reservedAmount: 0 }; budgetPrograms = [{ programId: 21806, programName: '02/20 Budget Dash Program', numberOfPayments: 4, paymentsAmount: 3000.0000, paymentsAmountUnit: 0 }]; budgetSources: BudgetDashboardFundingSource[] = [{ fundingSourceId: 4359, fundingSourceName: 'Corporate Funding Source', totalAllocated: 1000.0000, totalSpent: 1000.0000, totalRemaining: 0.0000, totalAllocatedUnits: 0, totalSpentUnits: 0, totalRemainingUnits: 0, isOverage: false, isClosed: false, totalUnavailableAmount: 0, reservedAmount: 0 }]; openSources: FundingSource[] = [{ id: 4359, name: 'Corporate Funding Source', type: 1, totalAmount: 1000000.0000, totalUnits: null, unitCost: null, unitValue: null, active: true, processingTypeId: 2, amountRemaining: 924721.0000, unitsRemaining: 0, amountUnallocated: 410280.8900, unitsUnallocated: 0, isClosed: false }]; closedSources: FundingSource[] = [{ id: 7906, name: 'Tina\'s Funding Source', type: 2, totalAmount: null, totalUnits: 500, unitCost: 5, unitValue: 10, active: false, processingTypeId: 1, amountRemaining: 35235325.0000, unitsRemaining: 0, amountUnallocated: 35235325.0000, unitsUnallocated: 0, isClosed: true }]; program: ProgramDetailFromApi = { id: 1, name: 'string', description: 'string', charityBucketDescription: 'string', imageName: 'string', logoName: 'string', timezoneId: 'string', maxAwardsAllowed: 1, maxValueForSingleAward: 1, defaultFormId: 1, additionalForms: [], workflowId: 1, defaultWorkflowLevelId: 1, deadlines: [{ name: 'string', date: 'string', description: 'string' }], imageUrl: 'string', logoUrl: 'string', programApplicantType: 1, allowCollaboration: true, sendEmailsToCollaborators: true, eligibilityPassMessage: 'string', eligibilityFailMessage: 'string', hasApplications: false, grantProgramsForNominationProgram: [], notifyNominators: true, allowAddOrg: true, canChangeDefaultForm: true, maskApplicantInfo: false, useProgramLogo: true, defaultLanguageId: 'string', daysBeforeEndDateReminders: 1, isArchived: false, cycles: [this.cycle], inviteOnly: false, formDueReminderFrequencyForApplicant: 1, formDueReminderFrequencyForReviewer: 1, formOverDueReminderFrequencyForApplicant: 1, formOverDueReminderFrequencyForReviewer: 1, reserveFunds: false, autoDeclineBudgetAssignment: false, autoDeclineBudgetAssignmentSendEmail: false, autoDeclineBudgetAssignmentDeclinationComment: 'string', hidePaymentStatus: false, alternatePaymentStatusText: 'string', clientId: 1 }; workflow: WorkflowDetail = { levels: [{ subLevels: [{ id: 444, name: 'string', description: 'string', allowDeclination: true, allowApproval: true, allowAward: true, allowUserToArchiveAndUnarchive: true, allowUserToRequestRevision: true, allowUserToViewAwardsAndPayments: true, allowFormDueDateExtension: true, allowRecommendedFunding: true, showMaskedApplicantInfo: true, showBudgetSummaryInfo: true }], id: 2, name: 'string', description: 'string', allowDeclination: true, allowApproval: true, allowAward: true, allowUserToArchiveAndUnarchive: true, allowUserToRequestRevision: true, allowFormDueDateExtension: true, allowUserToViewAwardsAndPayments: true, allowRecommendedFunding: true, showMaskedApplicantInfo: true, showBudgetSummaryInfo: true }], id: 1, name: 'string', description: 'string', active: true, hasApplications: false, workflowLevelManagers: [{ clientUserId: 222, firstName: 'string', lastName: 'string', email: 'string', workflowActions: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16] }] }; myAwards: MyAward[] = [{ applicationId: 174691, awardId: 196809, programName: 'Amount Requested - Multiple Currencies', organizationId: null, organizationName: null, amount: 300.0000, description: null, totalCash: 300.0000, totalUnits: 0.0, createdDate: '2022-07-19T19:21:03.5172795Z', payments: [{ paymentId: 178696, applicationId: 0, awardId: 196809, fundingSourceType: FundingSourceTypes.UNITS, totalAmount: 300.0000, totalUnits: null, scheduledDate: '2022-07-19T00:00:00Z', status: null, statusDate: '2022-07-19T19:21:03.8922948Z', budgetName: '2022 In Kind', fundingSourceName: 'In Kind 2022', currencyRequested: 'USD', currencyRequestedAmountEquivalent: 300.0000, paymentNumber: null, isACH: false, inKindItems: [{ itemIdentification: 'computer123', count: 2, value: 150.0000 }], substatus: null, reissuedForPaymentId: null, reissuedInPaymentId: null, alternatePaymentStatus: true, alternatePaymentStatusText: 'Alternate text', paymentType: null }], clientLogoUrl: 'https://grantsconnectqa-cdn.azureedge.net/static-content/management/160/images/deeb36cc-9087-42c5-9a1d-a2c88b6c3e8b.png', programLogoUrl: 'https://grantsconnectqa-cdn.azureedge.net/static-content/management/160/images/deeb36cc-9087-42c5-9a1d-a2c88b6c3e8b.png', currencyRequested: 'USD', currencyRequestedAmountEquivalent: 300.0000, grantProgramId: 278198, awardType: FundingSourceTypes.UNITS, inKindItems: [{ itemIdentification: 'computer123', count: 2, value: 150.0000 }] }, { applicationId: 174691, awardId: 196808, programName: 'Amount Requested - Multiple Currencies', organizationId: null, organizationName: null, amount: 3.0800, description: null, totalCash: 3.0800, totalUnits: 0.0, createdDate: '2022-07-19T19:21:02.8610168Z', payments: [{ paymentId: 178695, applicationId: 0, awardId: 196808, fundingSourceType: FundingSourceTypes.DOLLARS, totalAmount: 3.0800, totalUnits: null, scheduledDate: '2022-07-19T00:00:00Z', status: null, statusDate: '2022-07-19T19:21:03.2516472Z', budgetName: '2019 Grants', fundingSourceName: 'Foundation Funding', currencyRequested: 'RUB', currencyRequestedAmountEquivalent: 206.5100, paymentNumber: null, isACH: false, inKindItems: [], substatus: null, reissuedForPaymentId: null, reissuedInPaymentId: null, alternatePaymentStatus: true, alternatePaymentStatusText: 'Alternate text', paymentType: null }], clientLogoUrl: 'https://grantsconnectqa-cdn.azureedge.net/static-content/management/160/images/deeb36cc-9087-42c5-9a1d-a2c88b6c3e8b.png', programLogoUrl: 'https://grantsconnectqa-cdn.azureedge.net/static-content/management/160/images/deeb36cc-9087-42c5-9a1d-a2c88b6c3e8b.png', currencyRequested: 'RUB', currencyRequestedAmountEquivalent: 206.5100, grantProgramId: 278198, awardType: FundingSourceTypes.DOLLARS, inKindItems: [] }]; constructor ( private awardResources: AwardResources ) { } @BeforeEach() async mock (service: AwardService) { service['awardResources'] = this.awardResources; this.awardResources.saveAward = async () => { return { automaticallyRouted: true, awardId: this.awardId }; }; service['awardResources']['getAwardsForInsights'] = async () => { return this.awardInsightsResult; }; service['awardResources']['getTopCycles'] = async () => { return this.cycleTop10; }; service['programService']['getProgram'] = async () => { return this.program; }; service['programService']['programResources'].getCycleBudgetsMap = async () => { return {[9]: this.cycle.budgetIds} as SimpleStringMap; }; service['budgetService']['set']('openFundingSources', this.openSources); service['budgetService']['set']('closedFundingSources', this.closedSources); service['budgetService']['budgetResources'].getBudgetStats = async () => { return this.budgetStats; }; service['budgetService']['budgetResources'].getProgramsForBudgetDashboard = async () => { return this.budgetPrograms; }; service['budgetService']['budgetResources'].getFundingSourcesForBudgetDashboard = async () => { return this.budgetSources; }; service['budgetService']['budgetResources'].saveBudget = async () => { return true; }; service['budgetService']['budgetResources'].getFundingSources = async () => { return this.openSources.concat(this.closedSources); }; service['budgetService']['budgetResources'].getBudgetsSegmented = async () => { return []; }; service['budgetService']['budgetResources'].getFundingSourcesSegmented = async () => { return []; }; service['budgetService']['budgetResources'].getBudgets = async () => { return this.budgets; // return array of mocked budgets }; await service['budgetService'].setBudgets(); (service['statusService'] as any).set('paymentStatusMap', { [PaymentStatus.Pending]: { name: 'Pending', translated: 'Pending', icon: '', iconClass: '' } } ); (service['budgetService'] as any).set('unallocatedSourceMap', { [this.fundingSourceId]: 50 }); service['workflowService']['workflowResources'].getWorkflow = async () => { return this.workflow; }; service['workflowService'].getAndSetWorkflowMap = async () => { return this.workflow; }; const awards = service.constructAwards(this.awardsFromApi); this.cashPayment = awards[0].payments[0]; } @TestCase('should be able to construct awards') async constructAwards (service: AwardService) { const awards = service.constructAwards(this.awardsFromApi); expect(awards[0].amount).to.be.equal(this.awardsFromApi[0].amount); expect(awards[0].payments.length).to.be.equal(this.awardsFromApi[0].payments.length); } @TestCase('should be able to handle creating award') async handleAwardModalUpdates (service: AwardService) { const awardId = await service.handleAwardModalUpdates(this.awardModalResponse, 1); expect(awardId).to.be.equal(this.awardId); } @TestCase('should be able to adapt payment for api') async adaptPaymentForApi (service: AwardService) { const apiPayment = service.adaptPaymentForApi( this.cashPayment, [], null ); expect(apiPayment.budgetId).to.be.equal(this.budgetId); expect(apiPayment.fundingSourceType).to.be.equal(FundingSourceTypes.DOLLARS); } @TestCase('should be able to sum payments') async sumPaymentsInDefault (service: AwardService) { const total = service.sumPayments(this.paymentsToSum, true); expect(total).to.be.equal(1600); } @TestCase('should be able to filter out voided payments when getting sum') async filterOutVoided (service: AwardService) { const total = service.sumPayments( [ ...this.paymentsToSum, { statusId: PaymentStatus.Voided, amount: 1500, currencyRequestedAmountEquivalent: 1500 } ], true ); expect(total).to.be.equal(1600); } @TestCase('should be able to get potential award type') async getAwardType (service: AwardService) { const { awardType } = service.getAwardType( false, true, null, [] ); expect(awardType).to.be.equal(FundingSourceTypes.UNITS); } @TestCase('should be able to get award amount for form group') async getAwardAmountForFormGroup (service: AwardService) { const amount = service.getAwardAmountForFormGroup( 500, 'USD', false ); expect(amount).to.be.equal('500.00'); } @TestCase('should be able to get amount in requested') async getAmountInRequested (service: AwardService) { const amount = service.getAmountInRequested( '500.00', 'USD' ); expect(amount).to.be.equal(500); } @TestCase('should be able to get unmask and convert from requested to default') async unmaskAndConvertFromRequestedToDefault (service: AwardService) { const amount = service.unmaskAndConvertFromRequestedToDefault( '500.00', 'USD', 1 ); expect(amount).to.be.equal(500); } @TestCase('should be able to get sum of all payments from award modal') async getSumOfAllPayments (service: AwardService) { const sum = service.getSumOfAllPayments( '500.00', 'USD', 650, 650, false, true, 1 ); expect(sum).to.be.equal(1150); } @TestCase('should be able to handle payment funding source validation') async handlePaymentSourceValidation (service: AwardService) { const response = service.handlePaymentSourceValidation( this.budgetFundingSource, '1000', 50, 'USD', 1, false, true, false ); expect(response.canMoveFundsText).to.not.be.undefined; expect(response.error).to.not.be.undefined; } @TestCase('should be able to get new payment amount from moving funds') async getNewPaymentAmountFromMovingFunds (service: AwardService) { const amount = service.getNewPaymentAmountFromMovingFunds( this.budgetFundingSource, 500, '1500', 'USD', 1 ); expect(amount).to.be.equal(1050); } @TestCase('should be able to get awards list for insights non CSV') async getAwardListForInsightsNonCsv (service: AwardService) { const response = await service.getAwardListForInsights( { rowsPerPage: 1, pageNumber: 1, sortColumns: [], filterColumns: [], retrieveTotalRecordCount: false, returnAll: true }, [1], false ); expect(response.data.records).to.deep.equal(this.awardInsightsResult.records); } @TestCase('should be able to get awards list for insights for CSV') async getAwardListForInsightsCsv (service: AwardService) { const response = await service.getAwardListForInsights( { rowsPerPage: 1, pageNumber: 1, sortColumns: [], filterColumns: [], retrieveTotalRecordCount: false, returnAll: true }, [1], true ); expect(response).to.be.string; } @TestCase('should be able to get available award types') async getAvailableAwardTypes (service: AwardService) { const response = await service.getAvailableAwardTypes( this.program.id, this.cycle.id, this.cycle ); expect(response[0]).to.be.equal(FundingSourceTypes.DOLLARS); } @TestCase('should be able to check vetting requirement for award') async checkVettingRequirementForAward (service: AwardService) { const response = service.checkVettingRequirementForAward( 11, this.cycle.clientOrganizationsProcessingTypeId, this.cycle.budgetIds, this.awardsFromApi[0].currencyRequestedAmountEquivalent, this.awardsFromApi[0].currencyRequestedAmountEquivalent, 500 ); expect(response).to.be.equal(true); } @TestCase('should be able to get client cycle budgets') async getClientCycleBudgets (service: AwardService) { const response = service.getClientCycleBudgets( [this.budgets[0].id] ); expect(response.clientCashBudgets[0].id).to.be.equal(2968); } @TestCase('should be able to know if there is a client processor to create an award') async hasClientProcessorsToCreateAward (service: AwardService) { const response = service.hasClientProcessorsToCreateAward( true, this.cycle.budgetIds, [FundingSourceTypes.DOLLARS, FundingSourceTypes.UNITS], [FundingSourceTypes.DOLLARS] ); expect(response).to.be.equal(true); } @TestCase('should be able to get top cycles by award') async getTopCyclesByAward (service: AwardService) { const response = await service.getTopCyclesByAward( [this.cycle.id] ); expect(response[0].cycleId).to.be.equal(this.cycle.id); } @TestCase('should not be able to disable create award') async shouldDisableCreateAward (service: AwardService) { const response = service.shouldDisableCreateAward( false, [this.budgets[0].id, this.budgets[1].id], [this.budget.budgetFundingSources[0].fundingSourceType, this.budget.budgetFundingSources[1].fundingSourceType, this.budget.budgetFundingSources[2].fundingSourceType], this.budgets ); expect(response).to.be.equal(false); } @TestCase('should be able to handle approve award pay modal') async handleApproveAwardPayModal (service: AwardService) { const response = await service.handleApproveAwardPayModal( this.approveAwardPayModalPayload, true ); expect(response).to.be.equal(true); } @TestCase('should be able to get amounts for payment control') async getAmountsForPaymentControl (service: AwardService) { const response = service.getAmountsForPaymentControl( this.cashPayment, false, this.cashPayment.currencyRequested, this.cashPayment.isUnits, this.cashPayment.exchangeRate ); expect(response.amount).to.be.equal('500.00'); } @TestCase('should be able to get create payment alert helper') async getCreatePaymentAlertHelper (service: AwardService) { const response = await service.getCreatePaymentAlertHelper( true, false, false ); expect(response).to.be.equal('Create a payment for this award. Payments represent the total amount that the applicant will receive.'); } @TestCase('should be able to get payment type map') async getPaymentTypeMap (service: AwardService) { const response = service.getPaymentTypeMap(); expect(response).to.deep.equal({1: 'Check', 2: 'ACH', 3: 'Wire transfer', 4: 'Other'}); } @TestCase('should be able to get is payment amount disabled - first if') getIsPaymentAmountDisabled (service: AwardService) { let isUnits = true; let isEditingConversion = false; let disabled = service.getIsPaymentAmountDisabled( isUnits, true, PaymentStatus.Pending, isEditingConversion, false, false ); // Disabled should be true bc it's units expect(disabled).to.be.true; isUnits = false; isEditingConversion = true; disabled = service.getIsPaymentAmountDisabled( isUnits, false, PaymentStatus.Pending, isEditingConversion, false, false ); // Disabled should be true bc we are editing conversion expect(disabled).to.be.true; } @TestCase('should be able to get is payment amount disabled - existing payment') getIsPaymentAmountDisabledExistingPayment (service: AwardService) { const isExistingPayment = true; const isUnits = false; const isEditingConversion = false; const isUpdatingBudget = false; let budgetFsIsClosed = false; let disabled = service.getIsPaymentAmountDisabled( isUnits, isExistingPayment, PaymentStatus.Cleared, isEditingConversion, isUpdatingBudget, budgetFsIsClosed ); // Disabled should be true bc the payment is cleared expect(disabled).to.be.true; budgetFsIsClosed = true; disabled = service.getIsPaymentAmountDisabled( isUnits, isExistingPayment, PaymentStatus.Pending, isEditingConversion, isUpdatingBudget, budgetFsIsClosed ); // We are on the original budget, and it's closed so we don't allow edit expect(disabled).to.be.true; } @TestCase('should be able to get is payment amount not disabled') getIsPaymentAmountNotDisabled (service: AwardService) { const isExistingPayment = false; const isUnits = false; const isEditingConversion = false; const isUpdatingBudget = false; const budgetFsIsClosed = false; const disabled = service.getIsPaymentAmountDisabled( isUnits, isExistingPayment, PaymentStatus.Cleared, isEditingConversion, isUpdatingBudget, budgetFsIsClosed ); // Disabled should be false bc it's a brand new payment expect(disabled).to.be.false; } @TestCase('should be able to get number of non voided payments by app id - no voided') async getNumberOfNonVoidedPaymentsByAppId (service: AwardService) { service['awardResources']['getAwards'] = async () => { return { totalAmount: null, awards: this.awardsFromApi }; }; const number = await service.getNumberOfNonVoidedPaymentsByAppId(1); const payments = this.awardsFromApi.reduce((acc, award) => { return [ ...acc, award.payments ]; }, []); const numberExpected = payments.filter((payment) => { return payment.status !== PaymentStatus.Voided; }).length; expect(number).to.equal(numberExpected); } @TestCase('should be able to get number of non voided payments by app id - has voided') async getNumberOfNonVoidedPaymentsByAppIdHasVoided (service: AwardService) { service['awardResources']['getAwards'] = async () => { return { totalAmount: null, awards: [{ payments: [{ status: PaymentStatus.Voided } as PaymentFromApi, { status: PaymentStatus.Cleared } as PaymentFromApi] } as AwardFromApi] }; }; const number = await service.getNumberOfNonVoidedPaymentsByAppId(1); const numberExpected = 1; expect(number).to.equal(numberExpected); } @TestCase('should be able to get award todal text - both units and cash') getAwardTotalText (service: AwardService) { const text = service.getAwardTotalText(this.myAwards); const expected = 'You have been awarded $206.51 and 2 units.'; expect(text).to.be.equal(expected); } @TestCase('should be able to get award todal text - just cash') getAwardTotalTextCash (service: AwardService) { const text = service.getAwardTotalText([this.myAwards[1]]); const expected = 'You have been awarded $206.51.'; expect(text).to.be.equal(expected); } @TestCase('should be able to get award todal text - just units') getAwardTotalTextUnits (service: AwardService) { const text = service.getAwardTotalText([this.myAwards[0]]); const expected = 'You have been awarded 2 units.'; expect(text).to.be.equal(expected); } @TestCase('should be able to get award todal text - none') getAwardTotalTextUnitsNone (service: AwardService) { const text = service.getAwardTotalText([]); const expected = ''; expect(text).to.be.equal(expected); } }