From b55dcd7ebbff40398400065a4dfb703082be1283 Mon Sep 17 00:00:00 2001 From: Alexandre Monjol Date: Mon, 6 Jan 2025 11:58:41 +0100 Subject: [PATCH] misc(invoice-list-item): add issue a credit note action --- .../customers/CustomerInvoicesList.tsx | 77 +- src/components/designSystem/Table/Table.tsx | 2 + src/components/invoices/InvoicesList.tsx | 72 +- src/generated/graphql.tsx | 3710 +++++++++-------- 4 files changed, 1983 insertions(+), 1878 deletions(-) diff --git a/src/components/customers/CustomerInvoicesList.tsx b/src/components/customers/CustomerInvoicesList.tsx index 322c3bfcd..af0d0eb6a 100644 --- a/src/components/customers/CustomerInvoicesList.tsx +++ b/src/components/customers/CustomerInvoicesList.tsx @@ -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' @@ -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 { @@ -49,6 +55,10 @@ gql` voidable paymentDisputeLostAt taxProviderVoidable + invoiceType + creditableAmountCents + refundableAmountCents + associatedActiveWalletPresent customer { id name @@ -118,8 +128,10 @@ export const CustomerInvoicesList: FC = ({ fetchMore, }) => { const navigate = useNavigate() + const { isPremium } = useCurrentUser() const { translate } = useInternationalization() const { hasPermissions } = usePermissions() + const premiumWarningDialogRef = useRef(null) const [retryCollect] = useRetryInvoicePaymentMutation({ context: { silentErrorCodes: [LagoApiError.PaymentProcessorIsCurrentlyHandlingPayment] }, @@ -303,6 +315,15 @@ export const CustomerInvoicesList: FC = ({ 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, @@ -335,6 +356,9 @@ export const CustomerInvoicesList: FC = ({ paymentStatus, ) && hasPermissions(['invoicesVoid']) + const canIssueCreditNote = + ![InvoiceStatusTypeEnum.Draft, InvoiceStatusTypeEnum.Voided].includes(status) && + hasPermissions(['creditNotesCreate']) return [ canDownload @@ -354,6 +378,18 @@ export const CustomerInvoicesList: FC = ({ 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', @@ -378,17 +414,32 @@ export const CustomerInvoicesList: FC = ({ }, } : 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', @@ -414,10 +465,10 @@ export const CustomerInvoicesList: FC = ({ }} /> - + ) } diff --git a/src/components/designSystem/Table/Table.tsx b/src/components/designSystem/Table/Table.tsx index e061a0960..05d60a540 100644 --- a/src/components/designSystem/Table/Table.tsx +++ b/src/components/designSystem/Table/Table.tsx @@ -56,6 +56,7 @@ export type ActionItem = { title: string | ReactNode onAction: (item: T) => void startIcon?: IconName + endIcon?: IconName disabled?: boolean tooltip?: string tooltipListener?: boolean @@ -296,6 +297,7 @@ const ActionItemButton = ({