Skip to content

Commit

Permalink
misc(invoice-list-item): add issue a credit note action
Browse files Browse the repository at this point in the history
  • Loading branch information
ansmonjol committed Jan 6, 2025
1 parent ee28b55 commit b55dcd7
Show file tree
Hide file tree
Showing 4 changed files with 1,983 additions and 1,878 deletions.
77 changes: 64 additions & 13 deletions src/components/customers/CustomerInvoicesList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ import { addToast, hasDefinedGQLError } from '~/core/apolloClient'
import { CustomerInvoiceDetailsTabsOptionsEnum } from '~/core/constants/NavigationEnum'
import { invoiceStatusMapping, paymentStatusMapping } from '~/core/constants/statusInvoiceMapping'
import { intlFormatNumber } from '~/core/formats/intlFormatNumber'
import { CUSTOMER_INVOICE_DETAILS_ROUTE } from '~/core/router'
import {
CUSTOMER_INVOICE_CREATE_CREDIT_NOTE_ROUTE,
CUSTOMER_INVOICE_DETAILS_ROUTE,
} from '~/core/router'
import { deserializeAmount } from '~/core/serializers/serializeAmount'
import { formatDateToTZ, getTimezoneConfig } from '~/core/timezone'
import { copyToClipboard } from '~/core/utils/copyToClipboard'
Expand All @@ -26,14 +29,17 @@ import {
useRetryInvoicePaymentMutation,
} from '~/generated/graphql'
import { useInternationalization } from '~/hooks/core/useInternationalization'
import { useCurrentUser } from '~/hooks/useCurrentUser'
import { usePermissions } from '~/hooks/usePermissions'

import { createCreditNoteForInvoiceButtonProps } from '../creditNote/utils'
import {
UpdateInvoicePaymentStatusDialog,
UpdateInvoicePaymentStatusDialogRef,
} from '../invoices/EditInvoicePaymentStatusDialog'
import { FinalizeInvoiceDialog, FinalizeInvoiceDialogRef } from '../invoices/FinalizeInvoiceDialog'
import { VoidInvoiceDialog, VoidInvoiceDialogRef } from '../invoices/VoidInvoiceDialog'
import { PremiumWarningDialog, PremiumWarningDialogRef } from '../PremiumWarningDialog'

gql`
fragment InvoiceListItem on Invoice {
Expand All @@ -49,6 +55,10 @@ gql`
voidable
paymentDisputeLostAt
taxProviderVoidable
invoiceType
creditableAmountCents
refundableAmountCents
associatedActiveWalletPresent
customer {
id
name
Expand Down Expand Up @@ -118,8 +128,10 @@ export const CustomerInvoicesList: FC<CustomerInvoicesListProps> = ({
fetchMore,
}) => {
const navigate = useNavigate()
const { isPremium } = useCurrentUser()
const { translate } = useInternationalization()
const { hasPermissions } = usePermissions()
const premiumWarningDialogRef = useRef<PremiumWarningDialogRef>(null)

const [retryCollect] = useRetryInvoicePaymentMutation({
context: { silentErrorCodes: [LagoApiError.PaymentProcessorIsCurrentlyHandlingPayment] },
Expand Down Expand Up @@ -303,6 +315,15 @@ export const CustomerInvoicesList: FC<CustomerInvoicesListProps> = ({
actionColumn={(invoice) => {
const { status, paymentStatus, voidable, taxStatus } = invoice

const { disabledIssueCreditNoteButton, disabledIssueCreditNoteButtonLabel } =
createCreditNoteForInvoiceButtonProps({
invoiceType: invoice?.invoiceType,
paymentStatus: invoice?.paymentStatus,
creditableAmountCents: invoice?.creditableAmountCents,
refundableAmountCents: invoice?.refundableAmountCents,
associatedActiveWalletPresent: invoice?.associatedActiveWalletPresent,
})

const canDownload =
![
InvoiceStatusTypeEnum.Draft,
Expand Down Expand Up @@ -335,6 +356,9 @@ export const CustomerInvoicesList: FC<CustomerInvoicesListProps> = ({
paymentStatus,
) &&
hasPermissions(['invoicesVoid'])
const canIssueCreditNote =
![InvoiceStatusTypeEnum.Draft, InvoiceStatusTypeEnum.Voided].includes(status) &&
hasPermissions(['creditNotesCreate'])

return [
canDownload
Expand All @@ -354,6 +378,18 @@ export const CustomerInvoicesList: FC<CustomerInvoicesListProps> = ({
onAction: (item) => finalizeInvoiceRef.current?.openDialog(item),
}
: null,
{
startIcon: 'duplicate',
title: translate('text_63ac86d897f728a87b2fa031'),
onAction: ({ id }) => {
copyToClipboard(id)
addToast({
severity: 'info',
translateKey: 'text_63ac86d897f728a87b2fa0b0',
})
},
},

canRetryCollect
? {
startIcon: 'push',
Expand All @@ -378,17 +414,32 @@ export const CustomerInvoicesList: FC<CustomerInvoicesListProps> = ({
},
}
: null,
{
startIcon: 'duplicate',
title: translate('text_63ac86d897f728a87b2fa031'),
onAction: ({ id }) => {
copyToClipboard(id)
addToast({
severity: 'info',
translateKey: 'text_63ac86d897f728a87b2fa0b0',
})
},
},
canIssueCreditNote
? isPremium
? {
title: translate('text_636bdef6565341dcb9cfb127'),
startIcon: 'document',
disabled: disabledIssueCreditNoteButton,
onAction: () => {
navigate(
generatePath(CUSTOMER_INVOICE_CREATE_CREDIT_NOTE_ROUTE, {
customerId: invoice?.customer?.id,
invoiceId: invoice.id,
}),
)
},
tooltip: disabledIssueCreditNoteButtonLabel
? translate(disabledIssueCreditNoteButtonLabel)
: undefined,
}
: {
startIcon: 'document',
endIcon: 'sparkles',
title: translate('text_636bdef6565341dcb9cfb127'),
onAction: () => premiumWarningDialogRef.current?.openDialog(),
}
: null,

canUpdatePaymentStatus
? {
startIcon: 'coin-dollar',
Expand All @@ -414,10 +465,10 @@ export const CustomerInvoicesList: FC<CustomerInvoicesListProps> = ({
}}
/>
</InfiniteScroll>

<FinalizeInvoiceDialog ref={finalizeInvoiceRef} />
<UpdateInvoicePaymentStatusDialog ref={updateInvoicePaymentStatusDialog} />
<VoidInvoiceDialog ref={voidInvoiceDialogRef} />
<PremiumWarningDialog ref={premiumWarningDialogRef} />
</>
)
}
2 changes: 2 additions & 0 deletions src/components/designSystem/Table/Table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export type ActionItem<T> = {
title: string | ReactNode
onAction: (item: T) => void
startIcon?: IconName
endIcon?: IconName
disabled?: boolean
tooltip?: string
tooltipListener?: boolean
Expand Down Expand Up @@ -296,6 +297,7 @@ const ActionItemButton = <T,>({
<Button
fullWidth
startIcon={action.startIcon}
endIcon={action.endIcon}
variant="quaternary"
align="left"
disabled={action.disabled}
Expand Down
72 changes: 60 additions & 12 deletions src/components/invoices/InvoicesList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@ import { addToast, hasDefinedGQLError } from '~/core/apolloClient'
import { CustomerInvoiceDetailsTabsOptionsEnum } from '~/core/constants/NavigationEnum'
import { invoiceStatusMapping, paymentStatusMapping } from '~/core/constants/statusInvoiceMapping'
import { intlFormatNumber } from '~/core/formats/intlFormatNumber'
import { CUSTOMER_INVOICE_DETAILS_ROUTE, INVOICE_SETTINGS_ROUTE } from '~/core/router'
import {
CUSTOMER_INVOICE_CREATE_CREDIT_NOTE_ROUTE,
CUSTOMER_INVOICE_DETAILS_ROUTE,
INVOICE_SETTINGS_ROUTE,
} from '~/core/router'
import { deserializeAmount } from '~/core/serializers/serializeAmount'
import { formatDateToTZ } from '~/core/timezone'
import { copyToClipboard } from '~/core/utils/copyToClipboard'
Expand All @@ -39,8 +43,10 @@ import {
useRetryInvoicePaymentMutation,
} from '~/generated/graphql'
import { useInternationalization } from '~/hooks/core/useInternationalization'
import { useCurrentUser } from '~/hooks/useCurrentUser'
import { usePermissions } from '~/hooks/usePermissions'

import { createCreditNoteForInvoiceButtonProps } from '../creditNote/utils'
import { Filters } from '../designSystem/Filters/Filters'
import { AvailableFiltersEnum, AvailableQuickFilters } from '../designSystem/Filters/types'
import {
Expand All @@ -51,6 +57,7 @@ import {
isSucceededUrlParams,
isVoidedUrlParams,
} from '../designSystem/Filters/utils'
import { PremiumWarningDialog, PremiumWarningDialogRef } from '../PremiumWarningDialog'

type TInvoiceListProps = {
error: ApolloError | undefined
Expand All @@ -71,12 +78,14 @@ const InvoicesList = ({
}: TInvoiceListProps) => {
const { translate } = useInternationalization()
const { hasPermissions } = usePermissions()
const { isPremium } = useCurrentUser()
const navigate = useNavigate()
const [searchParams] = useSearchParams()

const finalizeInvoiceRef = useRef<FinalizeInvoiceDialogRef>(null)
const updateInvoicePaymentStatusDialog = useRef<UpdateInvoicePaymentStatusDialogRef>(null)
const voidInvoiceDialogRef = useRef<VoidInvoiceDialogRef>(null)
const premiumWarningDialogRef = useRef<PremiumWarningDialogRef>(null)

const [downloadInvoice] = useDownloadInvoiceItemMutation({
onCompleted({ downloadInvoice: data }) {
Expand Down Expand Up @@ -145,6 +154,15 @@ const InvoicesList = ({
actionColumn={(invoice) => {
const { status, paymentStatus, voidable } = invoice

const { disabledIssueCreditNoteButton, disabledIssueCreditNoteButtonLabel } =
createCreditNoteForInvoiceButtonProps({
invoiceType: invoice?.invoiceType,
paymentStatus: invoice?.paymentStatus,
creditableAmountCents: invoice?.creditableAmountCents,
refundableAmountCents: invoice?.refundableAmountCents,
associatedActiveWalletPresent: invoice?.associatedActiveWalletPresent,
})

const canDownload =
![
InvoiceStatusTypeEnum.Draft,
Expand Down Expand Up @@ -175,6 +193,9 @@ const InvoicesList = ({
InvoicePaymentStatusTypeEnum.Failed,
].includes(paymentStatus) &&
hasPermissions(['invoicesVoid'])
const canIssueCreditNote =
![InvoiceStatusTypeEnum.Draft, InvoiceStatusTypeEnum.Voided].includes(status) &&
hasPermissions(['creditNotesCreate'])

return [
canDownload
Expand All @@ -194,6 +215,18 @@ const InvoicesList = ({
onAction: (item) => finalizeInvoiceRef.current?.openDialog(item),
}
: null,
{
startIcon: 'duplicate',
title: translate('text_63ac86d897f728a87b2fa031'),
onAction: ({ id }) => {
copyToClipboard(id)
addToast({
severity: 'info',
translateKey: 'text_63ac86d897f728a87b2fa0b0',
})
},
},

canRetryCollect
? {
startIcon: 'push',
Expand All @@ -218,17 +251,31 @@ const InvoicesList = ({
},
}
: null,
{
startIcon: 'duplicate',
title: translate('text_63ac86d897f728a87b2fa031'),
onAction: ({ id }) => {
copyToClipboard(id)
addToast({
severity: 'info',
translateKey: 'text_63ac86d897f728a87b2fa0b0',
})
},
},
canIssueCreditNote
? isPremium
? {
title: translate('text_636bdef6565341dcb9cfb127'),
startIcon: 'document',
disabled: disabledIssueCreditNoteButton,
onAction: () => {
navigate(
generatePath(CUSTOMER_INVOICE_CREATE_CREDIT_NOTE_ROUTE, {
customerId: invoice?.customer?.id,
invoiceId: invoice.id,
}),
)
},
tooltip: disabledIssueCreditNoteButtonLabel
? translate(disabledIssueCreditNoteButtonLabel)
: undefined,
}
: {
startIcon: 'document',
endIcon: 'sparkles',
title: translate('text_636bdef6565341dcb9cfb127'),
onAction: () => premiumWarningDialogRef.current?.openDialog(),
}
: null,
canUpdatePaymentStatus
? {
startIcon: 'coin-dollar',
Expand Down Expand Up @@ -453,6 +500,7 @@ const InvoicesList = ({
<FinalizeInvoiceDialog ref={finalizeInvoiceRef} />
<UpdateInvoicePaymentStatusDialog ref={updateInvoicePaymentStatusDialog} />
<VoidInvoiceDialog ref={voidInvoiceDialogRef} />
<PremiumWarningDialog ref={premiumWarningDialogRef} />
</>
)
}
Expand Down
Loading

0 comments on commit b55dcd7

Please sign in to comment.