From e4ff5f75302cd46ac5cfef31edf9117bd1cdd404 Mon Sep 17 00:00:00 2001 From: Kelly Phan Date: Wed, 29 Jan 2025 10:29:51 +0100 Subject: [PATCH 01/12] feat(lago-670): creation page commit 678ae5f96f5a3b31f08e9e750a32a9e67d7ac349 Author: Kelly Phan Date: Tue Jan 28 10:58:44 2025 +0100 fix: handle invoice type credit commit 365bcc6f30423778b48dc12ff8e873a1da32032b Author: Kelly Phan Date: Mon Jan 27 18:11:42 2025 +0100 fix: use totalDueAmountCents instead of totalAmountCents commit d9a2b370db2f67fc47d532f503d5f223f28fbd3d Author: Kelly Phan Date: Fri Jan 24 15:21:43 2025 +0100 fix: support errors commit 47518da966c395c34fec605bf167566e5c0cbab7 Author: Kelly Phan Date: Fri Jan 24 15:02:14 2025 +0100 fix: use params instead of state for invoiceId commit 82bd199087ab04f7cda17b2f948e1d0cfba76f23 Author: Kelly Phan Date: Fri Jan 24 15:01:48 2025 +0100 feat: use datetime utility function commit f3e6c4c53a45ce16ccfa000eeb591727ed52f945 Author: Kelly Phan Date: Thu Jan 23 14:58:36 2025 +0100 feat: handle pre-filled form with invoice id commit 64aa46683fabc64d12e2dfb0971b6862fc7c4702 Author: Kelly Phan Date: Tue Jan 21 18:35:14 2025 +0100 feat: create payment page --- src/core/router/ObjectsRoutes.tsx | 10 + src/core/timezone/utils.ts | 30 +++ src/generated/graphql.tsx | 242 ++++++++++++++++++- src/hooks/usePermissions.ts | 1 + src/pages/CreatePayment.tsx | 373 ++++++++++++++++++++++++++++++ translations/base.json | 20 +- 6 files changed, 663 insertions(+), 13 deletions(-) create mode 100644 src/pages/CreatePayment.tsx diff --git a/src/core/router/ObjectsRoutes.tsx b/src/core/router/ObjectsRoutes.tsx index cb8a51bcf..39bd2067b 100644 --- a/src/core/router/ObjectsRoutes.tsx +++ b/src/core/router/ObjectsRoutes.tsx @@ -20,6 +20,7 @@ const CreateCoupon = lazyLoad(() => import('~/pages/CreateCoupon')) const CreateAddOn = lazyLoad(() => import('~/pages/CreateAddOn')) const CreateSubscription = lazyLoad(() => import('~/pages/CreateSubscription')) const WalletForm = lazyLoad(() => import('~/pages/WalletForm/WalletForm')) +const CreatePayment = lazyLoad(() => import('~/pages/CreatePayment')) // Details const SubscriptionDetails = lazyLoad(() => import('~/pages/SubscriptionDetails')) @@ -68,6 +69,9 @@ export const UPGRADE_DOWNGRADE_SUBSCRIPTION = export const CREATE_WALLET_ROUTE = '/customer/:customerId/wallet/create' export const EDIT_WALLET_ROUTE = '/customer/:customerId/wallet/:walletId' +export const CREATE_PAYMENT_ROUTE = '/create/payment' +export const CREATE_INVOICE_PAYMENT_ROUTE = '/invoice/:invoiceId/create/payment' + // Details export const CUSTOMER_SUBSCRIPTION_DETAILS_ROUTE = '/customer/:customerId/subscription/:subscriptionId/:tab' @@ -172,6 +176,12 @@ export const objectCreationRoutes: CustomRouteObject[] = [ element: , permissions: ['walletsCreate', 'walletsUpdate'], }, + { + path: [CREATE_PAYMENT_ROUTE, CREATE_INVOICE_PAYMENT_ROUTE], + private: true, + element: , + permissions: ['paymentsCreate'], + }, ] export const objectDetailsRoutes: CustomRouteObject[] = [ diff --git a/src/core/timezone/utils.ts b/src/core/timezone/utils.ts index 767c75b42..5f01089fb 100644 --- a/src/core/timezone/utils.ts +++ b/src/core/timezone/utils.ts @@ -51,3 +51,33 @@ export const intlFormatDateToDateMed = ( locale: locale, }).toLocaleString(DateTime.DATE_MED) } + +export const intlFormatDateTime = ( + date: string, + { + timezone = TimezoneEnum.TzUtc, + locale = LocaleEnum.en, + }: { + timezone?: TimezoneEnum | null | undefined + locale?: LocaleEnum + }, +) => { + const localeDateTime = DateTime.fromISO(date, { + zone: getTimezoneConfig(timezone).name, + locale: locale, + }) + + const localeDate = localeDateTime.toLocaleString(DateTime.DATE_MED) + + const localeTime = localeDateTime + .toLocaleParts({ + hour: '2-digit', + minute: '2-digit', + hour12: LocaleEnum.en === locale, + timeZoneName: 'short', + }) + .map((part) => part.value) + .join('') + + return { date: localeDate, time: localeTime } +} diff --git a/src/generated/graphql.tsx b/src/generated/graphql.tsx index b9a6a342e..727cae864 100644 --- a/src/generated/graphql.tsx +++ b/src/generated/graphql.tsx @@ -1374,6 +1374,16 @@ export type CreatePasswordResetPayload = { id: Scalars['String']['output']; }; +/** Autogenerated input type of CreatePayment */ +export type CreatePaymentInput = { + amountCents: Scalars['BigInt']['input']; + /** A unique identifier for the client performing the mutation. */ + clientMutationId?: InputMaybe; + createdAt: Scalars['ISO8601DateTime']['input']; + invoiceId: Scalars['ID']['input']; + reference: Scalars['String']['input']; +}; + /** Autogenerated input type of CreatePlan */ export type CreatePlanInput = { amountCents: Scalars['BigInt']['input']; @@ -2898,6 +2908,7 @@ export enum IntegrationTypeEnum { ApiPermissions = 'api_permissions', AutoDunning = 'auto_dunning', Hubspot = 'hubspot', + ManualPayments = 'manual_payments', Netsuite = 'netsuite', Okta = 'okta', ProgressiveBilling = 'progressive_billing', @@ -2905,8 +2916,7 @@ export enum IntegrationTypeEnum { RevenueAnalytics = 'revenue_analytics', RevenueShare = 'revenue_share', Salesforce = 'salesforce', - Xero = 'xero', - ZeroAmountFees = 'zero_amount_fees' + Xero = 'xero' } export type Invite = { @@ -2987,6 +2997,7 @@ export type Invoice = { taxesAmountCents: Scalars['BigInt']['output']; taxesRate: Scalars['Float']['output']; totalAmountCents: Scalars['BigInt']['output']; + totalDueAmountCents: Scalars['BigInt']['output']; updatedAt: Scalars['ISO8601DateTime']['output']; versionNumber: Scalars['Int']['output']; voidable: Scalars['Boolean']['output']; @@ -3378,6 +3389,8 @@ export type Mutation = { createOktaIntegration?: Maybe; /** Creates a new password reset */ createPasswordReset?: Maybe; + /** Creates a manual payment */ + createPayment?: Maybe; /** Creates a payment request */ createPaymentRequest?: Maybe; /** Creates a new Plan */ @@ -3709,6 +3722,11 @@ export type MutationCreatePasswordResetArgs = { }; +export type MutationCreatePaymentArgs = { + input: CreatePaymentInput; +}; + + export type MutationCreatePaymentRequestArgs = { input: PaymentRequestCreateInput; }; @@ -4280,6 +4298,39 @@ export type OverdueBalanceCollection = { metadata: CollectionMetadata; }; +export type Payable = Invoice | PaymentRequest; + +export enum PayablePaymentStatusEnum { + Failed = 'failed', + Pending = 'pending', + Processing = 'processing', + Succeeded = 'succeeded' +} + +export type Payment = { + __typename?: 'Payment'; + amountCents: Scalars['BigInt']['output']; + amountCurrency: CurrencyEnum; + createdAt: Scalars['ISO8601DateTime']['output']; + customer: Customer; + id: Scalars['ID']['output']; + payable: Payable; + payablePaymentStatus?: Maybe; + paymentProviderType?: Maybe; + paymentType: PaymentTypeEnum; + providerPaymentId?: Maybe; + reference?: Maybe; +}; + +/** PaymentCollection type */ +export type PaymentCollection = { + __typename?: 'PaymentCollection'; + /** A collection of paginated PaymentCollection */ + collection: Array; + /** Pagination Metadata for navigating the Pagination */ + metadata: CollectionMetadata; +}; + export type PaymentProvider = AdyenProvider | CashfreeProvider | GocardlessProvider | StripeProvider; /** PaymentProviderCollection type */ @@ -4322,6 +4373,11 @@ export type PaymentRequestCreateInput = { lagoInvoiceIds?: InputMaybe>; }; +export enum PaymentTypeEnum { + Manual = 'manual', + Provider = 'provider' +} + /** Permissions Type */ export type Permissions = { __typename?: 'Permissions'; @@ -4469,6 +4525,7 @@ export enum PremiumIntegrationTypeEnum { ApiPermissions = 'api_permissions', AutoDunning = 'auto_dunning', Hubspot = 'hubspot', + ManualPayments = 'manual_payments', Netsuite = 'netsuite', Okta = 'okta', ProgressiveBilling = 'progressive_billing', @@ -4476,8 +4533,7 @@ export enum PremiumIntegrationTypeEnum { RevenueAnalytics = 'revenue_analytics', RevenueShare = 'revenue_share', Salesforce = 'salesforce', - Xero = 'xero', - ZeroAmountFees = 'zero_amount_fees' + Xero = 'xero' } export type Properties = { @@ -4653,12 +4709,16 @@ export type Query = { overdueBalances: OverdueBalanceCollection; /** Query a password reset by token */ passwordReset: ResetPassword; + /** Query a single Payment */ + payment?: Maybe; /** Query a single payment provider */ paymentProvider?: Maybe; /** Query organization's payment providers */ paymentProviders?: Maybe; /** Query payment requests of an organization */ paymentRequests: PaymentRequestCollection; + /** Query payments of an organization */ + payments: PaymentCollection; /** Query a single plan of an organization */ plan?: Maybe; /** Query plans of an organization */ @@ -4976,9 +5036,11 @@ export type QueryInvoicesArgs = { issuingDateTo?: InputMaybe; limit?: InputMaybe; page?: InputMaybe; + partiallyPaid?: InputMaybe; paymentDisputeLost?: InputMaybe; paymentOverdue?: InputMaybe; paymentStatus?: InputMaybe>; + positiveDueAmount?: InputMaybe; searchTerm?: InputMaybe; selfBilled?: InputMaybe; status?: InputMaybe>; @@ -5009,6 +5071,11 @@ export type QueryPasswordResetArgs = { }; +export type QueryPaymentArgs = { + id: Scalars['ID']['input']; +}; + + export type QueryPaymentProviderArgs = { code?: InputMaybe; id?: InputMaybe; @@ -5029,6 +5096,14 @@ export type QueryPaymentRequestsArgs = { }; +export type QueryPaymentsArgs = { + externalCustomerId?: InputMaybe; + invoiceId?: InputMaybe; + limit?: InputMaybe; + page?: InputMaybe; +}; + + export type QueryPlanArgs = { id: Scalars['ID']['input']; }; @@ -6502,7 +6577,7 @@ export type XeroIntegration = { export type UserIdentifierQueryVariables = Exact<{ [key: string]: never; }>; -export type UserIdentifierQuery = { __typename?: 'Query', me: { __typename?: 'User', id: string, email?: string | null, premium: boolean, memberships: Array<{ __typename?: 'Membership', id: string, organization: { __typename?: 'Organization', id: string, name: string, logoUrl?: string | null }, permissions: { __typename?: 'Permissions', addonsCreate: boolean, addonsDelete: boolean, addonsUpdate: boolean, addonsView: boolean, analyticsView: boolean, analyticsOverdueBalancesView: boolean, billableMetricsCreate: boolean, billableMetricsDelete: boolean, billableMetricsUpdate: boolean, billableMetricsView: boolean, couponsAttach: boolean, couponsCreate: boolean, couponsDelete: boolean, couponsDetach: boolean, couponsUpdate: boolean, couponsView: boolean, creditNotesCreate: boolean, creditNotesView: boolean, creditNotesVoid: boolean, customerSettingsUpdateGracePeriod: boolean, customerSettingsUpdateLang: boolean, customerSettingsUpdatePaymentTerms: boolean, customerSettingsUpdateTaxRates: boolean, customerSettingsView: boolean, customersCreate: boolean, customersDelete: boolean, customersUpdate: boolean, customersView: boolean, developersKeysManage: boolean, developersManage: boolean, draftInvoicesUpdate: boolean, dunningCampaignsCreate: boolean, dunningCampaignsUpdate: boolean, dunningCampaignsView: boolean, invoiceCustomSectionsCreate: boolean, invoiceCustomSectionsUpdate: boolean, invoicesCreate: boolean, invoicesSend: boolean, invoicesUpdate: boolean, invoicesView: boolean, invoicesVoid: boolean, organizationEmailsUpdate: boolean, organizationEmailsView: boolean, organizationIntegrationsCreate: boolean, organizationIntegrationsDelete: boolean, organizationIntegrationsUpdate: boolean, organizationIntegrationsView: boolean, organizationInvoicesUpdate: boolean, organizationInvoicesView: boolean, organizationMembersCreate: boolean, organizationMembersDelete: boolean, organizationMembersUpdate: boolean, organizationMembersView: boolean, organizationTaxesUpdate: boolean, organizationTaxesView: boolean, organizationUpdate: boolean, organizationView: boolean, plansCreate: boolean, plansDelete: boolean, plansUpdate: boolean, plansView: boolean, subscriptionsCreate: boolean, subscriptionsUpdate: boolean, subscriptionsView: boolean, walletsCreate: boolean, walletsTerminate: boolean, walletsTopUp: boolean, walletsUpdate: boolean } }> }, organization?: { __typename?: 'CurrentOrganization', id: string, name: string, logoUrl?: string | null, timezone?: TimezoneEnum | null, defaultCurrency: CurrencyEnum, premiumIntegrations: Array } | null }; +export type UserIdentifierQuery = { __typename?: 'Query', me: { __typename?: 'User', id: string, email?: string | null, premium: boolean, memberships: Array<{ __typename?: 'Membership', id: string, organization: { __typename?: 'Organization', id: string, name: string, logoUrl?: string | null }, permissions: { __typename?: 'Permissions', addonsCreate: boolean, addonsDelete: boolean, addonsUpdate: boolean, addonsView: boolean, analyticsView: boolean, analyticsOverdueBalancesView: boolean, billableMetricsCreate: boolean, billableMetricsDelete: boolean, billableMetricsUpdate: boolean, billableMetricsView: boolean, couponsAttach: boolean, couponsCreate: boolean, couponsDelete: boolean, couponsDetach: boolean, couponsUpdate: boolean, couponsView: boolean, creditNotesCreate: boolean, creditNotesView: boolean, creditNotesVoid: boolean, customerSettingsUpdateGracePeriod: boolean, customerSettingsUpdateLang: boolean, customerSettingsUpdatePaymentTerms: boolean, customerSettingsUpdateTaxRates: boolean, customerSettingsView: boolean, customersCreate: boolean, customersDelete: boolean, customersUpdate: boolean, customersView: boolean, developersKeysManage: boolean, developersManage: boolean, draftInvoicesUpdate: boolean, dunningCampaignsCreate: boolean, dunningCampaignsUpdate: boolean, dunningCampaignsView: boolean, invoiceCustomSectionsCreate: boolean, invoiceCustomSectionsUpdate: boolean, invoicesCreate: boolean, invoicesSend: boolean, invoicesUpdate: boolean, invoicesView: boolean, invoicesVoid: boolean, organizationEmailsUpdate: boolean, organizationEmailsView: boolean, organizationIntegrationsCreate: boolean, organizationIntegrationsDelete: boolean, organizationIntegrationsUpdate: boolean, organizationIntegrationsView: boolean, organizationInvoicesUpdate: boolean, organizationInvoicesView: boolean, organizationMembersCreate: boolean, organizationMembersDelete: boolean, organizationMembersUpdate: boolean, organizationMembersView: boolean, organizationTaxesUpdate: boolean, organizationTaxesView: boolean, organizationUpdate: boolean, organizationView: boolean, paymentsCreate: boolean, plansCreate: boolean, plansDelete: boolean, plansUpdate: boolean, plansView: boolean, subscriptionsCreate: boolean, subscriptionsUpdate: boolean, subscriptionsView: boolean, walletsCreate: boolean, walletsTerminate: boolean, walletsTopUp: boolean, walletsUpdate: boolean } }> }, organization?: { __typename?: 'CurrentOrganization', id: string, name: string, logoUrl?: string | null, timezone?: TimezoneEnum | null, defaultCurrency: CurrencyEnum, premiumIntegrations: Array } | null }; export type DeleteAddOnFragment = { __typename?: 'AddOn', id: string, name: string }; @@ -8121,14 +8196,14 @@ export type UpdateInviteRoleMutationVariables = Exact<{ export type UpdateInviteRoleMutation = { __typename?: 'Mutation', updateInvite?: { __typename?: 'Invite', id: string, role: MembershipRole, email: string } | null }; -export type MemberForEditRoleForDialogFragment = { __typename?: 'Membership', id: string, role: MembershipRole, user: { __typename?: 'User', id: string, email?: string | null }, permissions: { __typename?: 'Permissions', addonsCreate: boolean, addonsDelete: boolean, addonsUpdate: boolean, addonsView: boolean, analyticsView: boolean, analyticsOverdueBalancesView: boolean, billableMetricsCreate: boolean, billableMetricsDelete: boolean, billableMetricsUpdate: boolean, billableMetricsView: boolean, couponsAttach: boolean, couponsCreate: boolean, couponsDelete: boolean, couponsDetach: boolean, couponsUpdate: boolean, couponsView: boolean, creditNotesCreate: boolean, creditNotesView: boolean, creditNotesVoid: boolean, customerSettingsUpdateGracePeriod: boolean, customerSettingsUpdateLang: boolean, customerSettingsUpdatePaymentTerms: boolean, customerSettingsUpdateTaxRates: boolean, customerSettingsView: boolean, customersCreate: boolean, customersDelete: boolean, customersUpdate: boolean, customersView: boolean, developersKeysManage: boolean, developersManage: boolean, draftInvoicesUpdate: boolean, dunningCampaignsCreate: boolean, dunningCampaignsUpdate: boolean, dunningCampaignsView: boolean, invoiceCustomSectionsCreate: boolean, invoiceCustomSectionsUpdate: boolean, invoicesCreate: boolean, invoicesSend: boolean, invoicesUpdate: boolean, invoicesView: boolean, invoicesVoid: boolean, organizationEmailsUpdate: boolean, organizationEmailsView: boolean, organizationIntegrationsCreate: boolean, organizationIntegrationsDelete: boolean, organizationIntegrationsUpdate: boolean, organizationIntegrationsView: boolean, organizationInvoicesUpdate: boolean, organizationInvoicesView: boolean, organizationMembersCreate: boolean, organizationMembersDelete: boolean, organizationMembersUpdate: boolean, organizationMembersView: boolean, organizationTaxesUpdate: boolean, organizationTaxesView: boolean, organizationUpdate: boolean, organizationView: boolean, plansCreate: boolean, plansDelete: boolean, plansUpdate: boolean, plansView: boolean, subscriptionsCreate: boolean, subscriptionsUpdate: boolean, subscriptionsView: boolean, walletsCreate: boolean, walletsTerminate: boolean, walletsTopUp: boolean, walletsUpdate: boolean } }; +export type MemberForEditRoleForDialogFragment = { __typename?: 'Membership', id: string, role: MembershipRole, user: { __typename?: 'User', id: string, email?: string | null }, permissions: { __typename?: 'Permissions', addonsCreate: boolean, addonsDelete: boolean, addonsUpdate: boolean, addonsView: boolean, analyticsView: boolean, analyticsOverdueBalancesView: boolean, billableMetricsCreate: boolean, billableMetricsDelete: boolean, billableMetricsUpdate: boolean, billableMetricsView: boolean, couponsAttach: boolean, couponsCreate: boolean, couponsDelete: boolean, couponsDetach: boolean, couponsUpdate: boolean, couponsView: boolean, creditNotesCreate: boolean, creditNotesView: boolean, creditNotesVoid: boolean, customerSettingsUpdateGracePeriod: boolean, customerSettingsUpdateLang: boolean, customerSettingsUpdatePaymentTerms: boolean, customerSettingsUpdateTaxRates: boolean, customerSettingsView: boolean, customersCreate: boolean, customersDelete: boolean, customersUpdate: boolean, customersView: boolean, developersKeysManage: boolean, developersManage: boolean, draftInvoicesUpdate: boolean, dunningCampaignsCreate: boolean, dunningCampaignsUpdate: boolean, dunningCampaignsView: boolean, invoiceCustomSectionsCreate: boolean, invoiceCustomSectionsUpdate: boolean, invoicesCreate: boolean, invoicesSend: boolean, invoicesUpdate: boolean, invoicesView: boolean, invoicesVoid: boolean, organizationEmailsUpdate: boolean, organizationEmailsView: boolean, organizationIntegrationsCreate: boolean, organizationIntegrationsDelete: boolean, organizationIntegrationsUpdate: boolean, organizationIntegrationsView: boolean, organizationInvoicesUpdate: boolean, organizationInvoicesView: boolean, organizationMembersCreate: boolean, organizationMembersDelete: boolean, organizationMembersUpdate: boolean, organizationMembersView: boolean, organizationTaxesUpdate: boolean, organizationTaxesView: boolean, organizationUpdate: boolean, organizationView: boolean, paymentsCreate: boolean, plansCreate: boolean, plansDelete: boolean, plansUpdate: boolean, plansView: boolean, subscriptionsCreate: boolean, subscriptionsUpdate: boolean, subscriptionsView: boolean, walletsCreate: boolean, walletsTerminate: boolean, walletsTopUp: boolean, walletsUpdate: boolean } }; export type UpdateMembershipRoleMutationVariables = Exact<{ input: UpdateMembershipInput; }>; -export type UpdateMembershipRoleMutation = { __typename?: 'Mutation', updateMembership?: { __typename?: 'Membership', id: string, role: MembershipRole, user: { __typename?: 'User', id: string, email?: string | null }, permissions: { __typename?: 'Permissions', addonsCreate: boolean, addonsDelete: boolean, addonsUpdate: boolean, addonsView: boolean, analyticsView: boolean, analyticsOverdueBalancesView: boolean, billableMetricsCreate: boolean, billableMetricsDelete: boolean, billableMetricsUpdate: boolean, billableMetricsView: boolean, couponsAttach: boolean, couponsCreate: boolean, couponsDelete: boolean, couponsDetach: boolean, couponsUpdate: boolean, couponsView: boolean, creditNotesCreate: boolean, creditNotesView: boolean, creditNotesVoid: boolean, customerSettingsUpdateGracePeriod: boolean, customerSettingsUpdateLang: boolean, customerSettingsUpdatePaymentTerms: boolean, customerSettingsUpdateTaxRates: boolean, customerSettingsView: boolean, customersCreate: boolean, customersDelete: boolean, customersUpdate: boolean, customersView: boolean, developersKeysManage: boolean, developersManage: boolean, draftInvoicesUpdate: boolean, dunningCampaignsCreate: boolean, dunningCampaignsUpdate: boolean, dunningCampaignsView: boolean, invoiceCustomSectionsCreate: boolean, invoiceCustomSectionsUpdate: boolean, invoicesCreate: boolean, invoicesSend: boolean, invoicesUpdate: boolean, invoicesView: boolean, invoicesVoid: boolean, organizationEmailsUpdate: boolean, organizationEmailsView: boolean, organizationIntegrationsCreate: boolean, organizationIntegrationsDelete: boolean, organizationIntegrationsUpdate: boolean, organizationIntegrationsView: boolean, organizationInvoicesUpdate: boolean, organizationInvoicesView: boolean, organizationMembersCreate: boolean, organizationMembersDelete: boolean, organizationMembersUpdate: boolean, organizationMembersView: boolean, organizationTaxesUpdate: boolean, organizationTaxesView: boolean, organizationUpdate: boolean, organizationView: boolean, plansCreate: boolean, plansDelete: boolean, plansUpdate: boolean, plansView: boolean, subscriptionsCreate: boolean, subscriptionsUpdate: boolean, subscriptionsView: boolean, walletsCreate: boolean, walletsTerminate: boolean, walletsTopUp: boolean, walletsUpdate: boolean } } | null }; +export type UpdateMembershipRoleMutation = { __typename?: 'Mutation', updateMembership?: { __typename?: 'Membership', id: string, role: MembershipRole, user: { __typename?: 'User', id: string, email?: string | null }, permissions: { __typename?: 'Permissions', addonsCreate: boolean, addonsDelete: boolean, addonsUpdate: boolean, addonsView: boolean, analyticsView: boolean, analyticsOverdueBalancesView: boolean, billableMetricsCreate: boolean, billableMetricsDelete: boolean, billableMetricsUpdate: boolean, billableMetricsView: boolean, couponsAttach: boolean, couponsCreate: boolean, couponsDelete: boolean, couponsDetach: boolean, couponsUpdate: boolean, couponsView: boolean, creditNotesCreate: boolean, creditNotesView: boolean, creditNotesVoid: boolean, customerSettingsUpdateGracePeriod: boolean, customerSettingsUpdateLang: boolean, customerSettingsUpdatePaymentTerms: boolean, customerSettingsUpdateTaxRates: boolean, customerSettingsView: boolean, customersCreate: boolean, customersDelete: boolean, customersUpdate: boolean, customersView: boolean, developersKeysManage: boolean, developersManage: boolean, draftInvoicesUpdate: boolean, dunningCampaignsCreate: boolean, dunningCampaignsUpdate: boolean, dunningCampaignsView: boolean, invoiceCustomSectionsCreate: boolean, invoiceCustomSectionsUpdate: boolean, invoicesCreate: boolean, invoicesSend: boolean, invoicesUpdate: boolean, invoicesView: boolean, invoicesVoid: boolean, organizationEmailsUpdate: boolean, organizationEmailsView: boolean, organizationIntegrationsCreate: boolean, organizationIntegrationsDelete: boolean, organizationIntegrationsUpdate: boolean, organizationIntegrationsView: boolean, organizationInvoicesUpdate: boolean, organizationInvoicesView: boolean, organizationMembersCreate: boolean, organizationMembersDelete: boolean, organizationMembersUpdate: boolean, organizationMembersView: boolean, organizationTaxesUpdate: boolean, organizationTaxesView: boolean, organizationUpdate: boolean, organizationView: boolean, paymentsCreate: boolean, plansCreate: boolean, plansDelete: boolean, plansUpdate: boolean, plansView: boolean, subscriptionsCreate: boolean, subscriptionsUpdate: boolean, subscriptionsView: boolean, walletsCreate: boolean, walletsTerminate: boolean, walletsTopUp: boolean, walletsUpdate: boolean } } | null }; export type RevokeInviteMutationVariables = Exact<{ input: RevokeInviteInput; @@ -8468,12 +8543,12 @@ export type UpdateTaxMutationVariables = Exact<{ export type UpdateTaxMutation = { __typename?: 'Mutation', updateTax?: { __typename?: 'Tax', id: string, code: string, description?: string | null, name: string, rate: number, customersCount: number } | null }; -export type CurrentUserInfosFragment = { __typename?: 'User', id: string, email?: string | null, premium: boolean, memberships: Array<{ __typename?: 'Membership', id: string, organization: { __typename?: 'Organization', id: string, name: string, logoUrl?: string | null }, permissions: { __typename?: 'Permissions', addonsCreate: boolean, addonsDelete: boolean, addonsUpdate: boolean, addonsView: boolean, analyticsView: boolean, analyticsOverdueBalancesView: boolean, billableMetricsCreate: boolean, billableMetricsDelete: boolean, billableMetricsUpdate: boolean, billableMetricsView: boolean, couponsAttach: boolean, couponsCreate: boolean, couponsDelete: boolean, couponsDetach: boolean, couponsUpdate: boolean, couponsView: boolean, creditNotesCreate: boolean, creditNotesView: boolean, creditNotesVoid: boolean, customerSettingsUpdateGracePeriod: boolean, customerSettingsUpdateLang: boolean, customerSettingsUpdatePaymentTerms: boolean, customerSettingsUpdateTaxRates: boolean, customerSettingsView: boolean, customersCreate: boolean, customersDelete: boolean, customersUpdate: boolean, customersView: boolean, developersKeysManage: boolean, developersManage: boolean, draftInvoicesUpdate: boolean, dunningCampaignsCreate: boolean, dunningCampaignsUpdate: boolean, dunningCampaignsView: boolean, invoiceCustomSectionsCreate: boolean, invoiceCustomSectionsUpdate: boolean, invoicesCreate: boolean, invoicesSend: boolean, invoicesUpdate: boolean, invoicesView: boolean, invoicesVoid: boolean, organizationEmailsUpdate: boolean, organizationEmailsView: boolean, organizationIntegrationsCreate: boolean, organizationIntegrationsDelete: boolean, organizationIntegrationsUpdate: boolean, organizationIntegrationsView: boolean, organizationInvoicesUpdate: boolean, organizationInvoicesView: boolean, organizationMembersCreate: boolean, organizationMembersDelete: boolean, organizationMembersUpdate: boolean, organizationMembersView: boolean, organizationTaxesUpdate: boolean, organizationTaxesView: boolean, organizationUpdate: boolean, organizationView: boolean, plansCreate: boolean, plansDelete: boolean, plansUpdate: boolean, plansView: boolean, subscriptionsCreate: boolean, subscriptionsUpdate: boolean, subscriptionsView: boolean, walletsCreate: boolean, walletsTerminate: boolean, walletsTopUp: boolean, walletsUpdate: boolean } }> }; +export type CurrentUserInfosFragment = { __typename?: 'User', id: string, email?: string | null, premium: boolean, memberships: Array<{ __typename?: 'Membership', id: string, organization: { __typename?: 'Organization', id: string, name: string, logoUrl?: string | null }, permissions: { __typename?: 'Permissions', addonsCreate: boolean, addonsDelete: boolean, addonsUpdate: boolean, addonsView: boolean, analyticsView: boolean, analyticsOverdueBalancesView: boolean, billableMetricsCreate: boolean, billableMetricsDelete: boolean, billableMetricsUpdate: boolean, billableMetricsView: boolean, couponsAttach: boolean, couponsCreate: boolean, couponsDelete: boolean, couponsDetach: boolean, couponsUpdate: boolean, couponsView: boolean, creditNotesCreate: boolean, creditNotesView: boolean, creditNotesVoid: boolean, customerSettingsUpdateGracePeriod: boolean, customerSettingsUpdateLang: boolean, customerSettingsUpdatePaymentTerms: boolean, customerSettingsUpdateTaxRates: boolean, customerSettingsView: boolean, customersCreate: boolean, customersDelete: boolean, customersUpdate: boolean, customersView: boolean, developersKeysManage: boolean, developersManage: boolean, draftInvoicesUpdate: boolean, dunningCampaignsCreate: boolean, dunningCampaignsUpdate: boolean, dunningCampaignsView: boolean, invoiceCustomSectionsCreate: boolean, invoiceCustomSectionsUpdate: boolean, invoicesCreate: boolean, invoicesSend: boolean, invoicesUpdate: boolean, invoicesView: boolean, invoicesVoid: boolean, organizationEmailsUpdate: boolean, organizationEmailsView: boolean, organizationIntegrationsCreate: boolean, organizationIntegrationsDelete: boolean, organizationIntegrationsUpdate: boolean, organizationIntegrationsView: boolean, organizationInvoicesUpdate: boolean, organizationInvoicesView: boolean, organizationMembersCreate: boolean, organizationMembersDelete: boolean, organizationMembersUpdate: boolean, organizationMembersView: boolean, organizationTaxesUpdate: boolean, organizationTaxesView: boolean, organizationUpdate: boolean, organizationView: boolean, paymentsCreate: boolean, plansCreate: boolean, plansDelete: boolean, plansUpdate: boolean, plansView: boolean, subscriptionsCreate: boolean, subscriptionsUpdate: boolean, subscriptionsView: boolean, walletsCreate: boolean, walletsTerminate: boolean, walletsTopUp: boolean, walletsUpdate: boolean } }> }; export type GetCurrentUserInfosQueryVariables = Exact<{ [key: string]: never; }>; -export type GetCurrentUserInfosQuery = { __typename?: 'Query', currentUser: { __typename?: 'User', id: string, email?: string | null, premium: boolean, memberships: Array<{ __typename?: 'Membership', id: string, organization: { __typename?: 'Organization', id: string, name: string, logoUrl?: string | null }, permissions: { __typename?: 'Permissions', addonsCreate: boolean, addonsDelete: boolean, addonsUpdate: boolean, addonsView: boolean, analyticsView: boolean, analyticsOverdueBalancesView: boolean, billableMetricsCreate: boolean, billableMetricsDelete: boolean, billableMetricsUpdate: boolean, billableMetricsView: boolean, couponsAttach: boolean, couponsCreate: boolean, couponsDelete: boolean, couponsDetach: boolean, couponsUpdate: boolean, couponsView: boolean, creditNotesCreate: boolean, creditNotesView: boolean, creditNotesVoid: boolean, customerSettingsUpdateGracePeriod: boolean, customerSettingsUpdateLang: boolean, customerSettingsUpdatePaymentTerms: boolean, customerSettingsUpdateTaxRates: boolean, customerSettingsView: boolean, customersCreate: boolean, customersDelete: boolean, customersUpdate: boolean, customersView: boolean, developersKeysManage: boolean, developersManage: boolean, draftInvoicesUpdate: boolean, dunningCampaignsCreate: boolean, dunningCampaignsUpdate: boolean, dunningCampaignsView: boolean, invoiceCustomSectionsCreate: boolean, invoiceCustomSectionsUpdate: boolean, invoicesCreate: boolean, invoicesSend: boolean, invoicesUpdate: boolean, invoicesView: boolean, invoicesVoid: boolean, organizationEmailsUpdate: boolean, organizationEmailsView: boolean, organizationIntegrationsCreate: boolean, organizationIntegrationsDelete: boolean, organizationIntegrationsUpdate: boolean, organizationIntegrationsView: boolean, organizationInvoicesUpdate: boolean, organizationInvoicesView: boolean, organizationMembersCreate: boolean, organizationMembersDelete: boolean, organizationMembersUpdate: boolean, organizationMembersView: boolean, organizationTaxesUpdate: boolean, organizationTaxesView: boolean, organizationUpdate: boolean, organizationView: boolean, plansCreate: boolean, plansDelete: boolean, plansUpdate: boolean, plansView: boolean, subscriptionsCreate: boolean, subscriptionsUpdate: boolean, subscriptionsView: boolean, walletsCreate: boolean, walletsTerminate: boolean, walletsTopUp: boolean, walletsUpdate: boolean } }> } }; +export type GetCurrentUserInfosQuery = { __typename?: 'Query', currentUser: { __typename?: 'User', id: string, email?: string | null, premium: boolean, memberships: Array<{ __typename?: 'Membership', id: string, organization: { __typename?: 'Organization', id: string, name: string, logoUrl?: string | null }, permissions: { __typename?: 'Permissions', addonsCreate: boolean, addonsDelete: boolean, addonsUpdate: boolean, addonsView: boolean, analyticsView: boolean, analyticsOverdueBalancesView: boolean, billableMetricsCreate: boolean, billableMetricsDelete: boolean, billableMetricsUpdate: boolean, billableMetricsView: boolean, couponsAttach: boolean, couponsCreate: boolean, couponsDelete: boolean, couponsDetach: boolean, couponsUpdate: boolean, couponsView: boolean, creditNotesCreate: boolean, creditNotesView: boolean, creditNotesVoid: boolean, customerSettingsUpdateGracePeriod: boolean, customerSettingsUpdateLang: boolean, customerSettingsUpdatePaymentTerms: boolean, customerSettingsUpdateTaxRates: boolean, customerSettingsView: boolean, customersCreate: boolean, customersDelete: boolean, customersUpdate: boolean, customersView: boolean, developersKeysManage: boolean, developersManage: boolean, draftInvoicesUpdate: boolean, dunningCampaignsCreate: boolean, dunningCampaignsUpdate: boolean, dunningCampaignsView: boolean, invoiceCustomSectionsCreate: boolean, invoiceCustomSectionsUpdate: boolean, invoicesCreate: boolean, invoicesSend: boolean, invoicesUpdate: boolean, invoicesView: boolean, invoicesVoid: boolean, organizationEmailsUpdate: boolean, organizationEmailsView: boolean, organizationIntegrationsCreate: boolean, organizationIntegrationsDelete: boolean, organizationIntegrationsUpdate: boolean, organizationIntegrationsView: boolean, organizationInvoicesUpdate: boolean, organizationInvoicesView: boolean, organizationMembersCreate: boolean, organizationMembersDelete: boolean, organizationMembersUpdate: boolean, organizationMembersView: boolean, organizationTaxesUpdate: boolean, organizationTaxesView: boolean, organizationUpdate: boolean, organizationView: boolean, paymentsCreate: boolean, plansCreate: boolean, plansDelete: boolean, plansUpdate: boolean, plansView: boolean, subscriptionsCreate: boolean, subscriptionsUpdate: boolean, subscriptionsView: boolean, walletsCreate: boolean, walletsTerminate: boolean, walletsTopUp: boolean, walletsUpdate: boolean } }> } }; export type GetEmailSettingsQueryVariables = Exact<{ [key: string]: never; }>; @@ -8502,7 +8577,7 @@ export type GetOrganizationInfosQueryVariables = Exact<{ [key: string]: never; } export type GetOrganizationInfosQuery = { __typename?: 'Query', organization?: { __typename?: 'CurrentOrganization', id: string, name: string, logoUrl?: string | null, timezone?: TimezoneEnum | null, defaultCurrency: CurrencyEnum, premiumIntegrations: Array } | null }; -export type MembershipPermissionsFragment = { __typename?: 'Membership', id: string, permissions: { __typename?: 'Permissions', addonsCreate: boolean, addonsDelete: boolean, addonsUpdate: boolean, addonsView: boolean, analyticsView: boolean, analyticsOverdueBalancesView: boolean, billableMetricsCreate: boolean, billableMetricsDelete: boolean, billableMetricsUpdate: boolean, billableMetricsView: boolean, couponsAttach: boolean, couponsCreate: boolean, couponsDelete: boolean, couponsDetach: boolean, couponsUpdate: boolean, couponsView: boolean, creditNotesCreate: boolean, creditNotesView: boolean, creditNotesVoid: boolean, customerSettingsUpdateGracePeriod: boolean, customerSettingsUpdateLang: boolean, customerSettingsUpdatePaymentTerms: boolean, customerSettingsUpdateTaxRates: boolean, customerSettingsView: boolean, customersCreate: boolean, customersDelete: boolean, customersUpdate: boolean, customersView: boolean, developersKeysManage: boolean, developersManage: boolean, draftInvoicesUpdate: boolean, dunningCampaignsCreate: boolean, dunningCampaignsUpdate: boolean, dunningCampaignsView: boolean, invoiceCustomSectionsCreate: boolean, invoiceCustomSectionsUpdate: boolean, invoicesCreate: boolean, invoicesSend: boolean, invoicesUpdate: boolean, invoicesView: boolean, invoicesVoid: boolean, organizationEmailsUpdate: boolean, organizationEmailsView: boolean, organizationIntegrationsCreate: boolean, organizationIntegrationsDelete: boolean, organizationIntegrationsUpdate: boolean, organizationIntegrationsView: boolean, organizationInvoicesUpdate: boolean, organizationInvoicesView: boolean, organizationMembersCreate: boolean, organizationMembersDelete: boolean, organizationMembersUpdate: boolean, organizationMembersView: boolean, organizationTaxesUpdate: boolean, organizationTaxesView: boolean, organizationUpdate: boolean, organizationView: boolean, plansCreate: boolean, plansDelete: boolean, plansUpdate: boolean, plansView: boolean, subscriptionsCreate: boolean, subscriptionsUpdate: boolean, subscriptionsView: boolean, walletsCreate: boolean, walletsTerminate: boolean, walletsTopUp: boolean, walletsUpdate: boolean } }; +export type MembershipPermissionsFragment = { __typename?: 'Membership', id: string, permissions: { __typename?: 'Permissions', addonsCreate: boolean, addonsDelete: boolean, addonsUpdate: boolean, addonsView: boolean, analyticsView: boolean, analyticsOverdueBalancesView: boolean, billableMetricsCreate: boolean, billableMetricsDelete: boolean, billableMetricsUpdate: boolean, billableMetricsView: boolean, couponsAttach: boolean, couponsCreate: boolean, couponsDelete: boolean, couponsDetach: boolean, couponsUpdate: boolean, couponsView: boolean, creditNotesCreate: boolean, creditNotesView: boolean, creditNotesVoid: boolean, customerSettingsUpdateGracePeriod: boolean, customerSettingsUpdateLang: boolean, customerSettingsUpdatePaymentTerms: boolean, customerSettingsUpdateTaxRates: boolean, customerSettingsView: boolean, customersCreate: boolean, customersDelete: boolean, customersUpdate: boolean, customersView: boolean, developersKeysManage: boolean, developersManage: boolean, draftInvoicesUpdate: boolean, dunningCampaignsCreate: boolean, dunningCampaignsUpdate: boolean, dunningCampaignsView: boolean, invoiceCustomSectionsCreate: boolean, invoiceCustomSectionsUpdate: boolean, invoicesCreate: boolean, invoicesSend: boolean, invoicesUpdate: boolean, invoicesView: boolean, invoicesVoid: boolean, organizationEmailsUpdate: boolean, organizationEmailsView: boolean, organizationIntegrationsCreate: boolean, organizationIntegrationsDelete: boolean, organizationIntegrationsUpdate: boolean, organizationIntegrationsView: boolean, organizationInvoicesUpdate: boolean, organizationInvoicesView: boolean, organizationMembersCreate: boolean, organizationMembersDelete: boolean, organizationMembersUpdate: boolean, organizationMembersView: boolean, organizationTaxesUpdate: boolean, organizationTaxesView: boolean, organizationUpdate: boolean, organizationView: boolean, paymentsCreate: boolean, plansCreate: boolean, plansDelete: boolean, plansUpdate: boolean, plansView: boolean, subscriptionsCreate: boolean, subscriptionsUpdate: boolean, subscriptionsView: boolean, walletsCreate: boolean, walletsTerminate: boolean, walletsTopUp: boolean, walletsUpdate: boolean } }; export type SideNavInfosQueryVariables = Exact<{ [key: string]: never; }>; @@ -8603,6 +8678,25 @@ export type FetchDraftInvoiceTaxesMutationVariables = Exact<{ export type FetchDraftInvoiceTaxesMutation = { __typename?: 'Mutation', fetchDraftInvoiceTaxes?: { __typename?: 'AnrokFeeObjectCollection', collection: Array<{ __typename?: 'AnrokFeeObject', amountCents?: any | null, itemId?: string | null, taxAmountCents?: any | null, taxBreakdown?: Array<{ __typename?: 'AnrokBreakdownObject', name?: string | null, rate?: number | null, taxAmount?: any | null, enumedTaxCode?: InvoiceAppliedTaxOnWholeInvoiceCodeEnum | null }> | null }> } | null }; +export type GetPayableInvoicesQueryVariables = Exact<{ [key: string]: never; }>; + + +export type GetPayableInvoicesQuery = { __typename?: 'Query', invoices: { __typename?: 'InvoiceCollection', collection: Array<{ __typename?: 'Invoice', id: string, number: string, currency?: CurrencyEnum | null }> } }; + +export type GetPayableInvoiceQueryVariables = Exact<{ + id: Scalars['ID']['input']; +}>; + + +export type GetPayableInvoiceQuery = { __typename?: 'Query', invoice?: { __typename?: 'Invoice', id: string, number: string, paymentStatus: InvoicePaymentStatusTypeEnum, status: InvoiceStatusTypeEnum, totalDueAmountCents: any, issuingDate: any, currency?: CurrencyEnum | null, invoiceType: InvoiceTypeEnum } | null }; + +export type CreatePaymentMutationVariables = Exact<{ + input: CreatePaymentInput; +}>; + + +export type CreatePaymentMutation = { __typename?: 'Mutation', createPayment?: { __typename?: 'Payment', id: string } | null }; + export type TaxForPlanAndChargesInPlanFormFragment = { __typename?: 'Tax', id: string, code: string, name: string, rate: number }; export type BillableMetricForPlanFragment = { __typename?: 'BillableMetric', id: string, name: string, code: string, aggregationType: AggregationTypeEnum, recurring: boolean, filters?: Array<{ __typename?: 'BillableMetricFilter', id: string, key: string, values: Array }> | null }; @@ -9296,7 +9390,7 @@ export type RemoveTaxManagementIntegrationMutation = { __typename?: 'Mutation', export type InviteItemForMembersSettingsFragment = { __typename?: 'Invite', id: string, email: string, token: string, role: MembershipRole, organization: { __typename?: 'Organization', id: string, name: string } }; -export type MembershipItemForMembershipSettingsFragment = { __typename?: 'Membership', id: string, role: MembershipRole, user: { __typename?: 'User', id: string, email?: string | null }, organization: { __typename?: 'Organization', id: string, name: string }, permissions: { __typename?: 'Permissions', addonsCreate: boolean, addonsDelete: boolean, addonsUpdate: boolean, addonsView: boolean, analyticsView: boolean, analyticsOverdueBalancesView: boolean, billableMetricsCreate: boolean, billableMetricsDelete: boolean, billableMetricsUpdate: boolean, billableMetricsView: boolean, couponsAttach: boolean, couponsCreate: boolean, couponsDelete: boolean, couponsDetach: boolean, couponsUpdate: boolean, couponsView: boolean, creditNotesCreate: boolean, creditNotesView: boolean, creditNotesVoid: boolean, customerSettingsUpdateGracePeriod: boolean, customerSettingsUpdateLang: boolean, customerSettingsUpdatePaymentTerms: boolean, customerSettingsUpdateTaxRates: boolean, customerSettingsView: boolean, customersCreate: boolean, customersDelete: boolean, customersUpdate: boolean, customersView: boolean, developersKeysManage: boolean, developersManage: boolean, draftInvoicesUpdate: boolean, dunningCampaignsCreate: boolean, dunningCampaignsUpdate: boolean, dunningCampaignsView: boolean, invoiceCustomSectionsCreate: boolean, invoiceCustomSectionsUpdate: boolean, invoicesCreate: boolean, invoicesSend: boolean, invoicesUpdate: boolean, invoicesView: boolean, invoicesVoid: boolean, organizationEmailsUpdate: boolean, organizationEmailsView: boolean, organizationIntegrationsCreate: boolean, organizationIntegrationsDelete: boolean, organizationIntegrationsUpdate: boolean, organizationIntegrationsView: boolean, organizationInvoicesUpdate: boolean, organizationInvoicesView: boolean, organizationMembersCreate: boolean, organizationMembersDelete: boolean, organizationMembersUpdate: boolean, organizationMembersView: boolean, organizationTaxesUpdate: boolean, organizationTaxesView: boolean, organizationUpdate: boolean, organizationView: boolean, plansCreate: boolean, plansDelete: boolean, plansUpdate: boolean, plansView: boolean, subscriptionsCreate: boolean, subscriptionsUpdate: boolean, subscriptionsView: boolean, walletsCreate: boolean, walletsTerminate: boolean, walletsTopUp: boolean, walletsUpdate: boolean } }; +export type MembershipItemForMembershipSettingsFragment = { __typename?: 'Membership', id: string, role: MembershipRole, user: { __typename?: 'User', id: string, email?: string | null }, organization: { __typename?: 'Organization', id: string, name: string }, permissions: { __typename?: 'Permissions', addonsCreate: boolean, addonsDelete: boolean, addonsUpdate: boolean, addonsView: boolean, analyticsView: boolean, analyticsOverdueBalancesView: boolean, billableMetricsCreate: boolean, billableMetricsDelete: boolean, billableMetricsUpdate: boolean, billableMetricsView: boolean, couponsAttach: boolean, couponsCreate: boolean, couponsDelete: boolean, couponsDetach: boolean, couponsUpdate: boolean, couponsView: boolean, creditNotesCreate: boolean, creditNotesView: boolean, creditNotesVoid: boolean, customerSettingsUpdateGracePeriod: boolean, customerSettingsUpdateLang: boolean, customerSettingsUpdatePaymentTerms: boolean, customerSettingsUpdateTaxRates: boolean, customerSettingsView: boolean, customersCreate: boolean, customersDelete: boolean, customersUpdate: boolean, customersView: boolean, developersKeysManage: boolean, developersManage: boolean, draftInvoicesUpdate: boolean, dunningCampaignsCreate: boolean, dunningCampaignsUpdate: boolean, dunningCampaignsView: boolean, invoiceCustomSectionsCreate: boolean, invoiceCustomSectionsUpdate: boolean, invoicesCreate: boolean, invoicesSend: boolean, invoicesUpdate: boolean, invoicesView: boolean, invoicesVoid: boolean, organizationEmailsUpdate: boolean, organizationEmailsView: boolean, organizationIntegrationsCreate: boolean, organizationIntegrationsDelete: boolean, organizationIntegrationsUpdate: boolean, organizationIntegrationsView: boolean, organizationInvoicesUpdate: boolean, organizationInvoicesView: boolean, organizationMembersCreate: boolean, organizationMembersDelete: boolean, organizationMembersUpdate: boolean, organizationMembersView: boolean, organizationTaxesUpdate: boolean, organizationTaxesView: boolean, organizationUpdate: boolean, organizationView: boolean, paymentsCreate: boolean, plansCreate: boolean, plansDelete: boolean, plansUpdate: boolean, plansView: boolean, subscriptionsCreate: boolean, subscriptionsUpdate: boolean, subscriptionsView: boolean, walletsCreate: boolean, walletsTerminate: boolean, walletsTopUp: boolean, walletsUpdate: boolean } }; export type GetInvitesQueryVariables = Exact<{ page?: InputMaybe; @@ -9312,7 +9406,7 @@ export type GetMembersQueryVariables = Exact<{ }>; -export type GetMembersQuery = { __typename?: 'Query', memberships: { __typename?: 'MembershipCollection', metadata: { __typename?: 'Metadata', currentPage: number, totalPages: number, totalCount: number, adminCount: number }, collection: Array<{ __typename?: 'Membership', id: string, role: MembershipRole, user: { __typename?: 'User', id: string, email?: string | null }, organization: { __typename?: 'Organization', id: string, name: string }, permissions: { __typename?: 'Permissions', addonsCreate: boolean, addonsDelete: boolean, addonsUpdate: boolean, addonsView: boolean, analyticsView: boolean, analyticsOverdueBalancesView: boolean, billableMetricsCreate: boolean, billableMetricsDelete: boolean, billableMetricsUpdate: boolean, billableMetricsView: boolean, couponsAttach: boolean, couponsCreate: boolean, couponsDelete: boolean, couponsDetach: boolean, couponsUpdate: boolean, couponsView: boolean, creditNotesCreate: boolean, creditNotesView: boolean, creditNotesVoid: boolean, customerSettingsUpdateGracePeriod: boolean, customerSettingsUpdateLang: boolean, customerSettingsUpdatePaymentTerms: boolean, customerSettingsUpdateTaxRates: boolean, customerSettingsView: boolean, customersCreate: boolean, customersDelete: boolean, customersUpdate: boolean, customersView: boolean, developersKeysManage: boolean, developersManage: boolean, draftInvoicesUpdate: boolean, dunningCampaignsCreate: boolean, dunningCampaignsUpdate: boolean, dunningCampaignsView: boolean, invoiceCustomSectionsCreate: boolean, invoiceCustomSectionsUpdate: boolean, invoicesCreate: boolean, invoicesSend: boolean, invoicesUpdate: boolean, invoicesView: boolean, invoicesVoid: boolean, organizationEmailsUpdate: boolean, organizationEmailsView: boolean, organizationIntegrationsCreate: boolean, organizationIntegrationsDelete: boolean, organizationIntegrationsUpdate: boolean, organizationIntegrationsView: boolean, organizationInvoicesUpdate: boolean, organizationInvoicesView: boolean, organizationMembersCreate: boolean, organizationMembersDelete: boolean, organizationMembersUpdate: boolean, organizationMembersView: boolean, organizationTaxesUpdate: boolean, organizationTaxesView: boolean, organizationUpdate: boolean, organizationView: boolean, plansCreate: boolean, plansDelete: boolean, plansUpdate: boolean, plansView: boolean, subscriptionsCreate: boolean, subscriptionsUpdate: boolean, subscriptionsView: boolean, walletsCreate: boolean, walletsTerminate: boolean, walletsTopUp: boolean, walletsUpdate: boolean } }> } }; +export type GetMembersQuery = { __typename?: 'Query', memberships: { __typename?: 'MembershipCollection', metadata: { __typename?: 'Metadata', currentPage: number, totalPages: number, totalCount: number, adminCount: number }, collection: Array<{ __typename?: 'Membership', id: string, role: MembershipRole, user: { __typename?: 'User', id: string, email?: string | null }, organization: { __typename?: 'Organization', id: string, name: string }, permissions: { __typename?: 'Permissions', addonsCreate: boolean, addonsDelete: boolean, addonsUpdate: boolean, addonsView: boolean, analyticsView: boolean, analyticsOverdueBalancesView: boolean, billableMetricsCreate: boolean, billableMetricsDelete: boolean, billableMetricsUpdate: boolean, billableMetricsView: boolean, couponsAttach: boolean, couponsCreate: boolean, couponsDelete: boolean, couponsDetach: boolean, couponsUpdate: boolean, couponsView: boolean, creditNotesCreate: boolean, creditNotesView: boolean, creditNotesVoid: boolean, customerSettingsUpdateGracePeriod: boolean, customerSettingsUpdateLang: boolean, customerSettingsUpdatePaymentTerms: boolean, customerSettingsUpdateTaxRates: boolean, customerSettingsView: boolean, customersCreate: boolean, customersDelete: boolean, customersUpdate: boolean, customersView: boolean, developersKeysManage: boolean, developersManage: boolean, draftInvoicesUpdate: boolean, dunningCampaignsCreate: boolean, dunningCampaignsUpdate: boolean, dunningCampaignsView: boolean, invoiceCustomSectionsCreate: boolean, invoiceCustomSectionsUpdate: boolean, invoicesCreate: boolean, invoicesSend: boolean, invoicesUpdate: boolean, invoicesView: boolean, invoicesVoid: boolean, organizationEmailsUpdate: boolean, organizationEmailsView: boolean, organizationIntegrationsCreate: boolean, organizationIntegrationsDelete: boolean, organizationIntegrationsUpdate: boolean, organizationIntegrationsView: boolean, organizationInvoicesUpdate: boolean, organizationInvoicesView: boolean, organizationMembersCreate: boolean, organizationMembersDelete: boolean, organizationMembersUpdate: boolean, organizationMembersView: boolean, organizationTaxesUpdate: boolean, organizationTaxesView: boolean, organizationUpdate: boolean, organizationView: boolean, paymentsCreate: boolean, plansCreate: boolean, plansDelete: boolean, plansUpdate: boolean, plansView: boolean, subscriptionsCreate: boolean, subscriptionsUpdate: boolean, subscriptionsView: boolean, walletsCreate: boolean, walletsTerminate: boolean, walletsTopUp: boolean, walletsUpdate: boolean } }> } }; export type NetsuiteIntegrationDetailsFragment = { __typename?: 'NetsuiteIntegration', id: string, name: string, accountId?: string | null, clientId?: string | null, clientSecret?: string | null, code: string, scriptEndpointUrl: string, syncCreditNotes?: boolean | null, syncInvoices?: boolean | null, syncPayments?: boolean | null, tokenId?: string | null, tokenSecret?: string | null }; @@ -10870,6 +10964,7 @@ export const MembershipPermissionsFragmentDoc = gql` organizationTaxesView organizationUpdate organizationView + paymentsCreate plansCreate plansDelete plansUpdate @@ -22204,6 +22299,129 @@ export function useFetchDraftInvoiceTaxesMutation(baseOptions?: Apollo.MutationH export type FetchDraftInvoiceTaxesMutationHookResult = ReturnType; export type FetchDraftInvoiceTaxesMutationResult = Apollo.MutationResult; export type FetchDraftInvoiceTaxesMutationOptions = Apollo.BaseMutationOptions; +export const GetPayableInvoicesDocument = gql` + query GetPayableInvoices { + invoices(positiveDueAmount: true) { + collection { + id + number + currency + } + } +} + `; + +/** + * __useGetPayableInvoicesQuery__ + * + * To run a query within a React component, call `useGetPayableInvoicesQuery` and pass it any options that fit your needs. + * When your component renders, `useGetPayableInvoicesQuery` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useGetPayableInvoicesQuery({ + * variables: { + * }, + * }); + */ +export function useGetPayableInvoicesQuery(baseOptions?: Apollo.QueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useQuery(GetPayableInvoicesDocument, options); + } +export function useGetPayableInvoicesLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useLazyQuery(GetPayableInvoicesDocument, options); + } +export function useGetPayableInvoicesSuspenseQuery(baseOptions?: Apollo.SkipToken | Apollo.SuspenseQueryHookOptions) { + const options = baseOptions === Apollo.skipToken ? baseOptions : {...defaultOptions, ...baseOptions} + return Apollo.useSuspenseQuery(GetPayableInvoicesDocument, options); + } +export type GetPayableInvoicesQueryHookResult = ReturnType; +export type GetPayableInvoicesLazyQueryHookResult = ReturnType; +export type GetPayableInvoicesSuspenseQueryHookResult = ReturnType; +export type GetPayableInvoicesQueryResult = Apollo.QueryResult; +export const GetPayableInvoiceDocument = gql` + query GetPayableInvoice($id: ID!) { + invoice(id: $id) { + id + number + paymentStatus + status + totalDueAmountCents + issuingDate + currency + invoiceType + } +} + `; + +/** + * __useGetPayableInvoiceQuery__ + * + * To run a query within a React component, call `useGetPayableInvoiceQuery` and pass it any options that fit your needs. + * When your component renders, `useGetPayableInvoiceQuery` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useGetPayableInvoiceQuery({ + * variables: { + * id: // value for 'id' + * }, + * }); + */ +export function useGetPayableInvoiceQuery(baseOptions: Apollo.QueryHookOptions & ({ variables: GetPayableInvoiceQueryVariables; skip?: boolean; } | { skip: boolean; }) ) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useQuery(GetPayableInvoiceDocument, options); + } +export function useGetPayableInvoiceLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useLazyQuery(GetPayableInvoiceDocument, options); + } +export function useGetPayableInvoiceSuspenseQuery(baseOptions?: Apollo.SkipToken | Apollo.SuspenseQueryHookOptions) { + const options = baseOptions === Apollo.skipToken ? baseOptions : {...defaultOptions, ...baseOptions} + return Apollo.useSuspenseQuery(GetPayableInvoiceDocument, options); + } +export type GetPayableInvoiceQueryHookResult = ReturnType; +export type GetPayableInvoiceLazyQueryHookResult = ReturnType; +export type GetPayableInvoiceSuspenseQueryHookResult = ReturnType; +export type GetPayableInvoiceQueryResult = Apollo.QueryResult; +export const CreatePaymentDocument = gql` + mutation CreatePayment($input: CreatePaymentInput!) { + createPayment(input: $input) { + id + } +} + `; +export type CreatePaymentMutationFn = Apollo.MutationFunction; + +/** + * __useCreatePaymentMutation__ + * + * To run a mutation, you first call `useCreatePaymentMutation` within a React component and pass it any options that fit your needs. + * When your component renders, `useCreatePaymentMutation` returns a tuple that includes: + * - A mutate function that you can call at any time to execute the mutation + * - An object with fields that represent the current status of the mutation's execution + * + * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2; + * + * @example + * const [createPaymentMutation, { data, loading, error }] = useCreatePaymentMutation({ + * variables: { + * input: // value for 'input' + * }, + * }); + */ +export function useCreatePaymentMutation(baseOptions?: Apollo.MutationHookOptions) { + const options = {...defaultOptions, ...baseOptions} + return Apollo.useMutation(CreatePaymentDocument, options); + } +export type CreatePaymentMutationHookResult = ReturnType; +export type CreatePaymentMutationResult = Apollo.MutationResult; +export type CreatePaymentMutationOptions = Apollo.BaseMutationOptions; export const GetPlansDocument = gql` query getPlans($page: Int, $limit: Int, $searchTerm: String) { plans(page: $page, limit: $limit, searchTerm: $searchTerm) { diff --git a/src/hooks/usePermissions.ts b/src/hooks/usePermissions.ts index 8fdfbc5be..e220c8db3 100644 --- a/src/hooks/usePermissions.ts +++ b/src/hooks/usePermissions.ts @@ -65,6 +65,7 @@ gql` organizationTaxesView organizationUpdate organizationView + paymentsCreate plansCreate plansDelete plansUpdate diff --git a/src/pages/CreatePayment.tsx b/src/pages/CreatePayment.tsx new file mode 100644 index 000000000..c6f64a7f9 --- /dev/null +++ b/src/pages/CreatePayment.tsx @@ -0,0 +1,373 @@ +import { gql } from '@apollo/client' +import { InputAdornment } from '@mui/material' +import { useFormik } from 'formik' +import { DateTime } from 'luxon' +import { useCallback, useEffect, useMemo, useRef } from 'react' +import { generatePath, useNavigate, useParams } from 'react-router-dom' +import { date, object, string } from 'yup' + +import { Alert, Button, Status, Table, Typography } from '~/components/designSystem' +import { AmountInputField, ComboBox, DatePickerField, TextInputField } from '~/components/form' +import { CenteredPage } from '~/components/layouts/Pages' +import { WarningDialog, WarningDialogRef } from '~/components/WarningDialog' +import { addToast } from '~/core/apolloClient' +import { paymentStatusMapping } from '~/core/constants/statusInvoiceMapping' +import { getCurrencySymbol, intlFormatNumber } from '~/core/formats/intlFormatNumber' +import { deserializeAmount, serializeAmount } from '~/core/serializers/serializeAmount' +import { intlFormatDateTime } from '~/core/timezone' +import { + CreatePaymentInput, + CurrencyEnum, + InvoiceTypeEnum, + LagoApiError, + useCreatePaymentMutation, + useGetPayableInvoiceQuery, + useGetPayableInvoicesQuery, +} from '~/generated/graphql' +import { useInternationalization } from '~/hooks/core/useInternationalization' +import { useOrganizationInfos } from '~/hooks/useOrganizationInfos' +import { FormLoadingSkeleton } from '~/styles/mainObjectsForm' +import { tw } from '~/styles/utils' + +gql` + query GetPayableInvoices { + invoices(positiveDueAmount: true) { + collection { + id + number + currency + } + } + } + + query GetPayableInvoice($id: ID!) { + invoice(id: $id) { + id + number + paymentStatus + status + totalDueAmountCents + issuingDate + currency + invoiceType + } + } + + mutation CreatePayment($input: CreatePaymentInput!) { + createPayment(input: $input) { + id + } + } +` + +const today = DateTime.now() + +const CreatePayment = () => { + const { translate } = useInternationalization() + const navigate = useNavigate() + const params = useParams<{ invoiceId?: string }>() + const warningDirtyAttributesDialogRef = useRef(null) + const { timezone } = useOrganizationInfos() + + const formikProps = useFormik({ + initialValues: { + invoiceId: params.invoiceId ?? '', + amountCents: '', + reference: '', + createdAt: today, + }, + validationSchema: object().shape({ + invoiceId: string().required(''), + amountCents: string() + .required('') + .test((value) => maxAmount(value)), + reference: string().max(40).required(''), + createdAt: date().required(''), + }), + enableReinitialize: true, + validateOnMount: true, + onSubmit: async (values) => { + await createPayment({ + variables: { + input: { + ...values, + amountCents: serializeAmount(values.amountCents, currency), + createdAt: values.createdAt.toISO(), + }, + }, + }) + }, + }) + + const { data: payableInvoices, loading: payableInvoicesLoading } = useGetPayableInvoicesQuery() + + const { data: { invoice } = {}, loading: invoiceLoading } = useGetPayableInvoiceQuery({ + variables: { id: formikProps.values.invoiceId }, + skip: !formikProps.values.invoiceId, + }) + + useEffect(() => { + if (invoice && invoice.invoiceType === InvoiceTypeEnum.Credit) { + formikProps.setFieldValue( + 'amountCents', + deserializeAmount(invoice.totalDueAmountCents, invoice.currency ?? CurrencyEnum.Usd), + ) + } + }, [invoice]) + + const currency = invoice?.currency ?? CurrencyEnum.Usd + + const [createPayment, { error: createError }] = useCreatePaymentMutation({ + context: { silentErrorCodes: [LagoApiError.UnprocessableEntity] }, + onCompleted({ createPayment: createdPayment }) { + if (!!createdPayment) { + addToast({ + severity: 'success', + translateKey: 'text_173755495088700ivx6izvjv', + }) + // TODO: Update path after LAGO-669 + navigate(generatePath('/', { paymentId: createdPayment?.id })) + } + }, + }) + + useEffect(() => { + if (createError) { + const errorCode = createError.graphQLErrors[0].extensions?.details + + formikProps.setErrors({ + ...formikProps.errors, + ...(errorCode ?? {}), + }) + } + }, [createError]) + + const maxAmount = useCallback( + (value: string) => { + const amount = Number(value) + + return amount > 0 && amount <= deserializeAmount(invoice?.totalDueAmountCents ?? 0, currency) + }, + // eslint-disable-next-line react-hooks/exhaustive-deps + [invoice], + ) + + const remainingAmount = useMemo(() => { + const totalAmount = deserializeAmount(invoice?.totalDueAmountCents ?? 0, currency) + const amount = Number(formikProps.values.amountCents) + + return totalAmount - amount + }, [formikProps.values.amountCents, invoice, currency]) + + const onLeave = () => { + navigate(-1) + } + + const dateTime = intlFormatDateTime(formikProps.values.createdAt, { + timezone, + }) + + return ( + <> + + + + {translate('text_1737473550277wkq2gsbaiab')} + +