diff --git a/auth-web/package-lock.json b/auth-web/package-lock.json index f431645070..1808c61c1e 100644 --- a/auth-web/package-lock.json +++ b/auth-web/package-lock.json @@ -1,12 +1,12 @@ { "name": "auth-web", - "version": "2.6.102", + "version": "2.6.103", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "auth-web", - "version": "2.6.102", + "version": "2.6.103", "dependencies": { "@bcrs-shared-components/base-address": "2.0.3", "@bcrs-shared-components/bread-crumb": "1.0.8", diff --git a/auth-web/package.json b/auth-web/package.json index 2651a72edc..d2533f9d34 100644 --- a/auth-web/package.json +++ b/auth-web/package.json @@ -1,6 +1,6 @@ { "name": "auth-web", - "version": "2.6.102", + "version": "2.6.103", "appName": "Auth Web", "sbcName": "SBC Common Components", "private": true, diff --git a/auth-web/src/components/auth/account-settings/transaction/Transactions.vue b/auth-web/src/components/auth/account-settings/transaction/Transactions.vue index c005e74c16..bc2c0c0318 100644 --- a/auth-web/src/components/auth/account-settings/transaction/Transactions.vue +++ b/auth-web/src/components/auth/account-settings/transaction/Transactions.vue @@ -178,7 +178,7 @@ export default defineComponent({ [MembershipType.Admin, MembershipType.Coordinator].includes(currentMembership.value.membershipTypeCode) }) - const getPaymentDetails = async () => { + const getCredits = async () => { const accountId = currentOrgPaymentDetails.value?.accountId if (!accountId || Number(accountId) !== currentOrganization.value?.id) { const paymentDetails: OrgPaymentDetails = await orgStore.getOrgPayments(currentOrganization.value?.id) @@ -189,22 +189,14 @@ export default defineComponent({ } const initUser = () => { - if (isTransactionsAllowed.value) getPaymentDetails() + if (isTransactionsAllowed.value) getCredits() else { - // if the account switing happening when the user is already in the transaction page, + // if the account switching happening when the user is already in the transaction page, // redirect to account info if its a basic account root.$router.push(`/${Pages.MAIN}/${currentOrganization.value.id}/settings/account-info`) } } - onMounted(() => { - setAccountChangedHandler(initUser) - setViewAll(props.extended) - clearAllFilters() - loadTransactionList() - }) - onBeforeUnmount(() => { beforeDestroy() }) - const exportCSV = async () => { isLoading.value = true // grab from composable** @@ -220,6 +212,15 @@ export default defineComponent({ isLoading.value = false } + onMounted(() => { + initUser() + setAccountChangedHandler(initUser) + setViewAll(props.extended) + clearAllFilters() + loadTransactionList() + }) + onBeforeUnmount(() => { beforeDestroy() }) + return { csvErrorDialog, csvErrorDialogText, diff --git a/auth-web/src/components/auth/account-settings/transaction/TransactionsDataTable.vue b/auth-web/src/components/auth/account-settings/transaction/TransactionsDataTable.vue index 86d1799c09..ee9e21046f 100644 --- a/auth-web/src/components/auth/account-settings/transaction/TransactionsDataTable.vue +++ b/auth-web/src/components/auth/account-settings/transaction/TransactionsDataTable.vue @@ -127,7 +127,7 @@ align-self="center" > ${statusCode.value} - ${statusCode.description}` }, '') const getHelpText = (item: Transaction) => { - if (item?.statusCode === InvoiceStatus.REFUND_REQUESTED) { - return 'We are processing your refund request.
It may take up to 7 business days to refund your total amount.' + switch (item?.statusCode) { + case InvoiceStatus.REFUND_REQUESTED: + return 'We are processing your refund request.
It may take up to 7 business days to refund your total amount.' + case InvoiceStatus.REFUNDED: + return '$' + (item?.total?.toFixed(2) || '') + ' has been refunded to the account used for this transaction.' + case InvoiceStatus.CREDITED: + return '$' + (item?.total?.toFixed(2) || '') + ' has been credited to the account used for this transaction.' + case InvoiceStatus.OVERDUE: + return 'Your monthly statement is overdue.
Please make your payment as soon as possible.' + default: + return '' } - if (item?.statusCode === InvoiceStatus.REFUNDED) { - return '$' + (item?.total?.toFixed(2) || '') + ' has been refunded to the account used for this transaction.' - } - if (item?.statusCode === InvoiceStatus.OVERDUE) { - return 'Your monthly statement is overdue.
Please make your payment as soon as possible.' - } - return '' } const tableDataOptions: Ref = ref(_.cloneDeep(DEFAULT_DATA_OPTIONS) as DataOptions) diff --git a/auth-web/src/composables/transactions-factory.ts b/auth-web/src/composables/transactions-factory.ts index 0e4accf968..4c23ec4ec6 100644 --- a/auth-web/src/composables/transactions-factory.ts +++ b/auth-web/src/composables/transactions-factory.ts @@ -1,4 +1,4 @@ -import { LDFlags, Role } from '@/util/constants' +import { InvoiceStatus, LDFlags, PaymentTypes, Role } from '@/util/constants' import { Transaction, TransactionFilterParams, TransactionState } from '@/models/transaction' import { computed, reactive, ref } from '@vue/composition-api' import LaunchDarklyService from 'sbc-common-components/src/services/launchdarkly.services' @@ -73,6 +73,28 @@ export const useTransactions = () => { if (response?.data) { transactions.results = response.data.items || [] transactions.totalResults = response.data.total + + const transactionClone = [...transactions.results] + const allowedRefundedStatuses = [InvoiceStatus.PAID, InvoiceStatus.REFUNDED, InvoiceStatus.CREDITED] + const allowedPaymentMethods = [PaymentTypes.PAD, PaymentTypes.ONLINE_BANKING] + transactionClone.forEach((transaction: Transaction, i: number) => { + if (transaction.refundDate && transaction.refund && + allowedPaymentMethods.includes(transaction.paymentMethod) && + allowedRefundedStatuses.includes(transaction.statusCode)) { + const newTransaction = { ...transaction } + newTransaction.statusCode = InvoiceStatus.PAID + newTransaction.paymentMethod = PaymentTypes.CREDIT + newTransaction.total = newTransaction.refund + newTransaction.createdOn = newTransaction.refundDate + transactions.totalResults++ + transactions.results.splice(i + 1, 0, newTransaction) + } + }) + if (transactions.results.some((transaction: Transaction) => transaction.refundDate)) { + transactions.results.sort((transaction1: Transaction, transaction2: Transaction) => { + return new Date(transaction2.createdOn).getTime() - new Date(transaction1.createdOn).getTime() + }) + } } else throw new Error('No response from getTransactions') } catch (error) { // eslint-disable-next-line no-console diff --git a/auth-web/src/models/transaction.ts b/auth-web/src/models/transaction.ts index b5c46d914b..6a83e8b22a 100644 --- a/auth-web/src/models/transaction.ts +++ b/auth-web/src/models/transaction.ts @@ -22,6 +22,7 @@ export interface Transaction { statusCode: InvoiceStatus total: number updatedOn: string + refundDate: string } export interface TransactionFilter { diff --git a/auth-web/src/resources/display-mappers/payment-type-display.ts b/auth-web/src/resources/display-mappers/payment-type-display.ts index f45e198010..52dcec782a 100644 --- a/auth-web/src/resources/display-mappers/payment-type-display.ts +++ b/auth-web/src/resources/display-mappers/payment-type-display.ts @@ -12,5 +12,5 @@ export const paymentTypeDisplay = { [PaymentTypes.NO_FEE]: 'No Fee', [PaymentTypes.ONLINE_BANKING]: 'Online Banking', [PaymentTypes.PAD]: 'Pre-Authorized Debit', - [PaymentTypes.WIRE]: 'Wire Transfer' + [PaymentTypes.CREDIT]: 'Account Credit' } diff --git a/auth-web/src/services/payment.services.ts b/auth-web/src/services/payment.services.ts index 1d1730001c..5d26f7fbc5 100644 --- a/auth-web/src/services/payment.services.ts +++ b/auth-web/src/services/payment.services.ts @@ -347,7 +347,7 @@ export default class PaymentService { const url = `${ConfigHelper.getPayAPIURL()}/eft-shortnames/${shortNameId}/payment` return axios.post(url, bodyParams) } - + static async isValidRedirectUrl (redirectUrl: string): AxiosPromise { const body = { redirectUrl: redirectUrl diff --git a/auth-web/src/util/constants.ts b/auth-web/src/util/constants.ts index 86fb1f20ed..c2bd88b33f 100644 --- a/auth-web/src/util/constants.ts +++ b/auth-web/src/util/constants.ts @@ -513,7 +513,8 @@ export enum PaymentTypes { ONLINE_BANKING = 'ONLINE_BANKING', PAD = 'PAD', EJV = 'EJV', - WIRE = 'WIRE' + WIRE = 'WIRE', + CREDIT = 'CREDIT' } export enum paymentErrorType { diff --git a/auth-web/src/views/pay/RefundView.vue b/auth-web/src/views/pay/RefundView.vue index 43811ed9c5..33568786e6 100644 --- a/auth-web/src/views/pay/RefundView.vue +++ b/auth-web/src/views/pay/RefundView.vue @@ -5,51 +5,51 @@ MVP Refunds - OPS only for now. Fetch Invoice Partial Refunds can only be applied to credit card invoices.

Specify the fee amounts to be refunded and click 'Add to Refund', the refund summary entries will be appear for review. @@ -60,9 +60,9 @@ {{ item }} @@ -70,8 +70,8 @@ {{ index + 1 }} @@ -126,10 +126,10 @@ {{ isRefundItemAdded(index) ? 'Remove from Refund' : 'Add to Refund' }} @@ -143,39 +143,41 @@ Refund Summary:

By pressing the refund action, the specified amounts in the summary below will be refunded.

+ v-if="refundType === RefundType.PARTIAL" + id="refund-summary-table" + > - - + - {{ item }} - - + > + {{ item }} + + - - {{ item + 1 }} - {{ paymentLineItems[item].description }} - ${{ paymentLineItems[item].filingFees }} - ${{ paymentLineItems[item].priorityFees }} - ${{ paymentLineItems[item].futureEffectiveFees }} - ${{ paymentLineItems[item].serviceFees }} - + > + {{ item + 1 }} + {{ paymentLineItems[item].description }} + ${{ paymentLineItems[item].filingFees }} + ${{ paymentLineItems[item].priorityFees }} + ${{ paymentLineItems[item].futureEffectiveFees }} + ${{ paymentLineItems[item].serviceFees }} +

REFUND @@ -276,29 +278,29 @@ export default defineComponent({ return (value <= maxAmount) || `Refund amount exceeds $${maxAmount}` } - function showRefundCreditCardError() { + function showRefundCreditCardError () { if (state.refundType !== RefundType.PARTIAL) return false return state.invoicePaymentMethod && state.invoicePaymentMethod !== PaymentTypes.DIRECT_PAY } - function disableFeeInputs() { + function disableFeeInputs () { return state.refundType === RefundType.FULL || state.invoicePaymentMethod !== PaymentTypes.DIRECT_PAY || state.disableSubmit } - function disablePartialRefundAction(item: any) { + function disablePartialRefundAction (item: any) { return item.filingFees > item.filingFeesOriginal || item.priorityFees > item.priorityFeesOriginal || item.futureEffectiveFees > item.futureEffectiveFeesOriginal || item.serviceFees > item.serviceFeesOriginal } - function showPartialRefundAction() { + function showPartialRefundAction () { return !disableFeeInputs() && state.refundType === RefundType.PARTIAL } - function isRefundItemAdded(index) { + function isRefundItemAdded (index) { return state.refundItems.includes(index) } @@ -307,13 +309,13 @@ export default defineComponent({ return invoiceId.match(/\d+/) } - function updateInvoiceState(invoice: any) { + function updateInvoiceState (invoice: any) { state.invoicePaid = invoice.paid state.invoicePaymentMethod = invoice.paymentMethod state.paymentLineItems = invoice.lineItems ? updateInvoiceLineItems(invoice.lineItems) : [] } - function updateInvoiceLineItems(lineItems: any) { + function updateInvoiceLineItems (lineItems: any) { return lineItems.map(item => ({ ...item, ...Object.fromEntries( @@ -330,7 +332,7 @@ export default defineComponent({ clearRefundState() } - function getRefundPayload() { + function getRefundPayload () { let refundPayload = { reason: state.refundComment, refundRevenue: [] diff --git a/auth-web/tests/unit/components/Transactions.spec.ts b/auth-web/tests/unit/components/Transactions.spec.ts index e453644a46..e50a54f573 100644 --- a/auth-web/tests/unit/components/Transactions.spec.ts +++ b/auth-web/tests/unit/components/Transactions.spec.ts @@ -1,5 +1,6 @@ import '../test-utils/composition-api-setup' // important to import this first import { Wrapper, createLocalVue, mount } from '@vue/test-utils' +import { Account } from '@/util/constants' import { MembershipType } from '@/models/Organization' import { Transactions } from '@/components/auth/account-settings/transaction' import TransactionsDataTable from '@/components/auth/account-settings/transaction/TransactionsDataTable.vue' @@ -30,9 +31,9 @@ describe('Transactions tests', () => { const localVue = createLocalVue() const orgStore = useOrgStore() orgStore.currentOrgPaymentDetails = { accountId: 123 } as any - orgStore.currentOrganization = { id: 123 } as any - orgStore.currentMembership = { membershipTypeCode: MembershipType.Admin } as any + orgStore.currentOrganization = { id: 123, orgType: Account.PREMIUM } as any orgStore.getOrgPayments = vi.fn(() => { return { credit: 0 } }) as any + orgStore.currentMembership = { membershipTypeCode: MembershipType.Admin } as any // stub get transactions get call sandbox = sinon.createSandbox()