mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-19 14:20:31 +00:00
feat: Stripe connect using OAuth
This commit is contained in:
@@ -13,6 +13,13 @@ export class StripeIntegrationController extends BaseController {
|
|||||||
public router() {
|
public router() {
|
||||||
const router = Router();
|
const router = Router();
|
||||||
|
|
||||||
|
router.get('/link', this.getStripeConnectLink.bind(this));
|
||||||
|
router.post(
|
||||||
|
'/callback',
|
||||||
|
[body('code').exists()],
|
||||||
|
this.validationResult,
|
||||||
|
this.exchangeOAuth.bind(this)
|
||||||
|
);
|
||||||
router.post('/account', asyncMiddleware(this.createAccount.bind(this)));
|
router.post('/account', asyncMiddleware(this.createAccount.bind(this)));
|
||||||
router.post(
|
router.post(
|
||||||
'/account_link',
|
'/account_link',
|
||||||
@@ -27,6 +34,47 @@ export class StripeIntegrationController extends BaseController {
|
|||||||
return router;
|
return router;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves Stripe OAuth2 connect link.
|
||||||
|
* @param {Request} req
|
||||||
|
* @param {Response} res
|
||||||
|
* @param {NextFunction} next
|
||||||
|
* @returns {Promise<Response|void>}
|
||||||
|
*/
|
||||||
|
public async getStripeConnectLink(
|
||||||
|
req: Request,
|
||||||
|
res: Response,
|
||||||
|
next: NextFunction
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
const authorizationUri = this.stripePaymentApp.getStripeConnectLink();
|
||||||
|
|
||||||
|
return res.status(200).send({ url: authorizationUri });
|
||||||
|
} catch (error) {
|
||||||
|
next(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exchanges the given Stripe authorization code to Stripe user id and access token.
|
||||||
|
* @param {Request} req
|
||||||
|
* @param {Response} res
|
||||||
|
* @param {NextFunction} next
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
public async exchangeOAuth(req: Request, res: Response, next: NextFunction) {
|
||||||
|
const { tenantId } = req;
|
||||||
|
const { code } = this.matchedBodyData(req);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await this.stripePaymentApp.exchangeStripeOAuthToken(tenantId, code);
|
||||||
|
|
||||||
|
return res.status(200).send({});
|
||||||
|
} catch (error) {
|
||||||
|
next(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a Stripe checkout session for the given payment link id.
|
* Creates a Stripe checkout session for the given payment link id.
|
||||||
* @param {Request} req
|
* @param {Request} req
|
||||||
|
|||||||
@@ -268,6 +268,8 @@ module.exports = {
|
|||||||
stripePayment: {
|
stripePayment: {
|
||||||
secretKey: process.env.STRIPE_PAYMENT_SECRET_KEY || '',
|
secretKey: process.env.STRIPE_PAYMENT_SECRET_KEY || '',
|
||||||
publishableKey: process.env.STRIPE_PAYMENT_PUBLISHABLE_KEY || '',
|
publishableKey: process.env.STRIPE_PAYMENT_PUBLISHABLE_KEY || '',
|
||||||
|
clientId: process.env.STRIPE_PAYMENT_CLIENT_ID || '',
|
||||||
|
redirectTo: process.env.STRIPE_PAYMENT_REDIRECT_URL || '',
|
||||||
webhooksSecret: process.env.STRIPE_PAYMENT_WEBHOOKS_SECRET || '',
|
webhooksSecret: process.env.STRIPE_PAYMENT_WEBHOOKS_SECRET || '',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ exports.up = function (knex) {
|
|||||||
table.string('service');
|
table.string('service');
|
||||||
table.string('name');
|
table.string('name');
|
||||||
table.string('slug');
|
table.string('slug');
|
||||||
table.boolean('active').defaultTo(false);
|
table.boolean('payment_enabled').defaultTo(false);
|
||||||
|
table.boolean('payout_enabled').defaultTo(false);
|
||||||
table.string('account_id');
|
table.string('account_id');
|
||||||
table.json('options');
|
table.json('options');
|
||||||
table.timestamps();
|
table.timestamps();
|
||||||
|
|||||||
@@ -31,6 +31,17 @@ export const PrepardExpenses = {
|
|||||||
predefined: true,
|
predefined: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const StripeClearingAccount = {
|
||||||
|
name: 'Stripe Clearing',
|
||||||
|
slug: 'stripe-clearing',
|
||||||
|
account_type: 'other-current-liability',
|
||||||
|
parent_account_id: null,
|
||||||
|
code: '50006',
|
||||||
|
active: true,
|
||||||
|
index: 1,
|
||||||
|
predefined: true,
|
||||||
|
}
|
||||||
|
|
||||||
export default [
|
export default [
|
||||||
{
|
{
|
||||||
name: 'Bank Account',
|
name: 'Bank Account',
|
||||||
|
|||||||
@@ -120,6 +120,7 @@ import { SeedInitialDemoAccountDataOnOrgBuild } from '@/services/OneClickDemo/ev
|
|||||||
import { EventsTrackerListeners } from '@/services/EventsTracker/events/events';
|
import { EventsTrackerListeners } from '@/services/EventsTracker/events/events';
|
||||||
import { InvoicePaymentIntegrationSubscriber } from '@/services/Sales/Invoices/subscribers/InvoicePaymentIntegrationSubscriber';
|
import { InvoicePaymentIntegrationSubscriber } from '@/services/Sales/Invoices/subscribers/InvoicePaymentIntegrationSubscriber';
|
||||||
import { StripeWebhooksSubscriber } from '@/services/StripePayment/events/StripeWebhooksSubscriber';
|
import { StripeWebhooksSubscriber } from '@/services/StripePayment/events/StripeWebhooksSubscriber';
|
||||||
|
import { SeedStripeAccountsOnOAuthGrantedSubscriber } from '@/services/StripePayment/events/SeedStripeAccounts';
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
return new EventPublisher();
|
return new EventPublisher();
|
||||||
@@ -294,6 +295,7 @@ export const susbcribers = () => {
|
|||||||
// Stripe Payment
|
// Stripe Payment
|
||||||
InvoicePaymentIntegrationSubscriber,
|
InvoicePaymentIntegrationSubscriber,
|
||||||
StripeWebhooksSubscriber,
|
StripeWebhooksSubscriber,
|
||||||
|
SeedStripeAccountsOnOAuthGrantedSubscriber,
|
||||||
|
|
||||||
...EventsTrackerListeners
|
...EventsTrackerListeners
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
import { Model } from 'objection';
|
import { Model } from 'objection';
|
||||||
import TenantModel from 'models/TenantModel';
|
import TenantModel from 'models/TenantModel';
|
||||||
|
|
||||||
export class PaymentIntegration extends TenantModel {
|
export class PaymentIntegration extends Model {
|
||||||
|
paymentEnabled!: boolean;
|
||||||
|
payoutEnabled!: boolean;
|
||||||
|
|
||||||
static get tableName() {
|
static get tableName() {
|
||||||
return 'payment_integrations';
|
return 'payment_integrations';
|
||||||
}
|
}
|
||||||
@@ -10,16 +13,35 @@ export class PaymentIntegration extends TenantModel {
|
|||||||
return 'id';
|
return 'id';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static get virtualAttributes() {
|
||||||
|
return ['fullEnabled'];
|
||||||
|
}
|
||||||
|
|
||||||
|
static get jsonAttributes() {
|
||||||
|
return ['options'];
|
||||||
|
}
|
||||||
|
|
||||||
|
get fullEnabled() {
|
||||||
|
return this.paymentEnabled && this.payoutEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
static get jsonSchema() {
|
static get jsonSchema() {
|
||||||
return {
|
return {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
required: ['name', 'service', 'active'],
|
required: ['name', 'service'],
|
||||||
properties: {
|
properties: {
|
||||||
id: { type: 'integer' },
|
id: { type: 'integer' },
|
||||||
service: { type: 'string' },
|
service: { type: 'string' },
|
||||||
active: { type: 'boolean' },
|
paymentEnabled: { type: 'boolean' },
|
||||||
|
payoutEnabled: { type: 'boolean' },
|
||||||
accountId: { type: 'string' },
|
accountId: { type: 'string' },
|
||||||
options: { type: 'object' },
|
options: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
bankAccountId: { type: 'number' },
|
||||||
|
clearingAccountId: { type: 'number' },
|
||||||
|
},
|
||||||
|
},
|
||||||
createdAt: { type: 'string', format: 'date-time' },
|
createdAt: { type: 'string', format: 'date-time' },
|
||||||
updatedAt: { type: 'string', format: 'date-time' },
|
updatedAt: { type: 'string', format: 'date-time' },
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { IAccount } from '@/interfaces';
|
|||||||
import { Knex } from 'knex';
|
import { Knex } from 'knex';
|
||||||
import {
|
import {
|
||||||
PrepardExpenses,
|
PrepardExpenses,
|
||||||
|
StripeClearingAccount,
|
||||||
TaxPayableAccount,
|
TaxPayableAccount,
|
||||||
UnearnedRevenueAccount,
|
UnearnedRevenueAccount,
|
||||||
} from '@/database/seeds/data/accounts';
|
} from '@/database/seeds/data/accounts';
|
||||||
@@ -247,4 +248,37 @@ export default class AccountRepository extends TenantRepository {
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds or creates the stripe clearing account.
|
||||||
|
* @param {Record<string, string>} extraAttrs
|
||||||
|
* @param {Knex.Transaction} trx
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
public async findOrCreateStripeClearing(
|
||||||
|
extraAttrs: Record<string, string> = {},
|
||||||
|
trx?: Knex.Transaction
|
||||||
|
) {
|
||||||
|
// Retrieves the given tenant metadata.
|
||||||
|
const tenantMeta = await TenantMetadata.query().findOne({
|
||||||
|
tenantId: this.tenantId,
|
||||||
|
});
|
||||||
|
const _extraAttrs = {
|
||||||
|
currencyCode: tenantMeta.baseCurrency,
|
||||||
|
...extraAttrs,
|
||||||
|
};
|
||||||
|
|
||||||
|
let result = await this.model
|
||||||
|
.query(trx)
|
||||||
|
.findOne({ slug: StripeClearingAccount.slug, ..._extraAttrs });
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
result = await this.model.query(trx).insertAndFetch({
|
||||||
|
...StripeClearingAccount,
|
||||||
|
..._extraAttrs,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,12 +3,16 @@ import HasTenancyService from '../Tenancy/TenancyService';
|
|||||||
import { GetPaymentMethodsPOJO } from './types';
|
import { GetPaymentMethodsPOJO } from './types';
|
||||||
import config from '@/config';
|
import config from '@/config';
|
||||||
import { isStripePaymentConfigured } from './utils';
|
import { isStripePaymentConfigured } from './utils';
|
||||||
|
import { GetStripeAuthorizationLinkService } from '../StripePayment/GetStripeAuthorizationLink';
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export class GetPaymentMethodsStateService {
|
export class GetPaymentMethodsStateService {
|
||||||
@Inject()
|
@Inject()
|
||||||
private tenancy: HasTenancyService;
|
private tenancy: HasTenancyService;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
private getStripeAuthorizationLinkService: GetStripeAuthorizationLinkService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the payment state provising state.
|
* Retrieves the payment state provising state.
|
||||||
* @param {number} tenantId
|
* @param {number} tenantId
|
||||||
@@ -25,7 +29,9 @@ export class GetPaymentMethodsStateService {
|
|||||||
service: 'Stripe',
|
service: 'Stripe',
|
||||||
});
|
});
|
||||||
const isStripeAccountCreated = !!stripePayment;
|
const isStripeAccountCreated = !!stripePayment;
|
||||||
const isStripePaymentActive = !!(stripePayment?.active || null);
|
const isStripePaymentEnabled = stripePayment?.paymentEnabled;
|
||||||
|
const isStripePayoutEnabled = stripePayment?.payoutEnabled;
|
||||||
|
const isStripeEnabled = stripePayment?.fullEnabled;
|
||||||
|
|
||||||
const stripePaymentMethodId = stripePayment?.id || null;
|
const stripePaymentMethodId = stripePayment?.id || null;
|
||||||
const stripeAccountId = stripePayment?.accountId || null;
|
const stripeAccountId = stripePayment?.accountId || null;
|
||||||
@@ -33,16 +39,21 @@ export class GetPaymentMethodsStateService {
|
|||||||
const stripeCurrencies = ['USD', 'EUR'];
|
const stripeCurrencies = ['USD', 'EUR'];
|
||||||
const stripeRedirectUrl = 'https://your-stripe-redirect-url.com';
|
const stripeRedirectUrl = 'https://your-stripe-redirect-url.com';
|
||||||
const isStripeServerConfigured = isStripePaymentConfigured();
|
const isStripeServerConfigured = isStripePaymentConfigured();
|
||||||
|
const stripeAuthLink =
|
||||||
|
this.getStripeAuthorizationLinkService.getStripeAuthLink();
|
||||||
|
|
||||||
const paymentMethodPOJO: GetPaymentMethodsPOJO = {
|
const paymentMethodPOJO: GetPaymentMethodsPOJO = {
|
||||||
stripe: {
|
stripe: {
|
||||||
isStripeAccountCreated,
|
isStripeAccountCreated,
|
||||||
isStripePaymentActive,
|
isStripePaymentEnabled,
|
||||||
|
isStripePayoutEnabled,
|
||||||
|
isStripeEnabled,
|
||||||
isStripeServerConfigured,
|
isStripeServerConfigured,
|
||||||
stripeAccountId,
|
stripeAccountId,
|
||||||
stripePaymentMethodId,
|
stripePaymentMethodId,
|
||||||
stripePublishableKey,
|
stripePublishableKey,
|
||||||
stripeCurrencies,
|
stripeCurrencies,
|
||||||
|
stripeAuthLink,
|
||||||
stripeRedirectUrl,
|
stripeRedirectUrl,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -16,11 +16,17 @@ export interface EditPaymentMethodDTO {
|
|||||||
export interface GetPaymentMethodsPOJO {
|
export interface GetPaymentMethodsPOJO {
|
||||||
stripe: {
|
stripe: {
|
||||||
isStripeAccountCreated: boolean;
|
isStripeAccountCreated: boolean;
|
||||||
isStripePaymentActive: boolean;
|
|
||||||
|
isStripePaymentEnabled: boolean;
|
||||||
|
isStripePayoutEnabled: boolean;
|
||||||
|
isStripeEnabled: boolean;
|
||||||
|
|
||||||
isStripeServerConfigured: boolean;
|
isStripeServerConfigured: boolean;
|
||||||
|
|
||||||
stripeAccountId: string | null;
|
stripeAccountId: string | null;
|
||||||
stripePaymentMethodId: number | null;
|
stripePaymentMethodId: number | null;
|
||||||
stripePublishableKey: string | null;
|
stripePublishableKey: string | null;
|
||||||
|
stripeAuthLink: string;
|
||||||
stripeCurrencies: Array<string>;
|
stripeCurrencies: Array<string>;
|
||||||
stripeRedirectUrl: string | null;
|
stripeRedirectUrl: string | null;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -35,7 +35,8 @@ export class GetSaleInvoice {
|
|||||||
.withGraphFetched('customer')
|
.withGraphFetched('customer')
|
||||||
.withGraphFetched('branch')
|
.withGraphFetched('branch')
|
||||||
.withGraphFetched('taxes.taxRate')
|
.withGraphFetched('taxes.taxRate')
|
||||||
.withGraphFetched('attachments');
|
.withGraphFetched('attachments')
|
||||||
|
.withGraphFetched('paymentMethods');
|
||||||
|
|
||||||
// Validates the given sale invoice existance.
|
// Validates the given sale invoice existance.
|
||||||
this.validators.validateInvoiceExistance(saleInvoice);
|
this.validators.validateInvoiceExistance(saleInvoice);
|
||||||
|
|||||||
@@ -0,0 +1,73 @@
|
|||||||
|
import { Inject, Service } from 'typedi';
|
||||||
|
import { StripePaymentService } from './StripePaymentService';
|
||||||
|
import events from '@/subscribers/events';
|
||||||
|
import HasTenancyService from '../Tenancy/TenancyService';
|
||||||
|
import { EventPublisher } from '@/lib/EventPublisher/EventPublisher';
|
||||||
|
import UnitOfWork from '../UnitOfWork';
|
||||||
|
import { Knex } from 'knex';
|
||||||
|
import { StripeOAuthCodeGrantedEventPayload } from './types';
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export class ExchangeStripeOAuthTokenService {
|
||||||
|
@Inject()
|
||||||
|
private stripePaymentService: StripePaymentService;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
private tenancy: HasTenancyService;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
private eventPublisher: EventPublisher;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
private uow: UnitOfWork;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exchange stripe oauth authorization code to access token and user id.
|
||||||
|
* @param {number} tenantId
|
||||||
|
* @param {string} authorizationCode
|
||||||
|
*/
|
||||||
|
public async excahngeStripeOAuthToken(
|
||||||
|
tenantId: number,
|
||||||
|
authorizationCode: string
|
||||||
|
) {
|
||||||
|
const { PaymentIntegration } = this.tenancy.models(tenantId);
|
||||||
|
const stripe = this.stripePaymentService.stripe;
|
||||||
|
|
||||||
|
const response = await stripe.oauth.token({
|
||||||
|
grant_type: 'authorization_code',
|
||||||
|
code: authorizationCode,
|
||||||
|
});
|
||||||
|
// const accessToken = response.access_token;
|
||||||
|
// const refreshToken = response.refresh_token;
|
||||||
|
const stripeUserId = response.stripe_user_id;
|
||||||
|
|
||||||
|
// Retrieves details of the Stripe account.
|
||||||
|
const account = await stripe.accounts.retrieve(stripeUserId, {
|
||||||
|
expand: ['business_profile'],
|
||||||
|
});
|
||||||
|
const companyName = account.business_profile?.name || 'Unknow name';
|
||||||
|
const paymentEnabled = account.charges_enabled;
|
||||||
|
const payoutEnabled = account.payouts_enabled;
|
||||||
|
|
||||||
|
//
|
||||||
|
return this.uow.withTransaction(tenantId, async (trx: Knex.Transaction) => {
|
||||||
|
// Stores the details of the Stripe account.
|
||||||
|
const paymentIntegration = await PaymentIntegration.query(trx).insert({
|
||||||
|
name: companyName,
|
||||||
|
service: 'Stripe',
|
||||||
|
accountId: stripeUserId,
|
||||||
|
paymentEnabled,
|
||||||
|
payoutEnabled,
|
||||||
|
});
|
||||||
|
// Triggers `onStripeOAuthCodeGranted` event.
|
||||||
|
await this.eventPublisher.emitAsync(
|
||||||
|
events.stripeIntegration.onOAuthCodeGranted,
|
||||||
|
{
|
||||||
|
tenantId,
|
||||||
|
paymentIntegrationId: paymentIntegration.id,
|
||||||
|
trx,
|
||||||
|
} as StripeOAuthCodeGrantedEventPayload
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import { Service } from 'typedi';
|
||||||
|
import config from '@/config';
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export class GetStripeAuthorizationLinkService {
|
||||||
|
public getStripeAuthLink() {
|
||||||
|
const clientId = config.stripePayment.clientId;
|
||||||
|
const redirectUrl = config.stripePayment.redirectTo;
|
||||||
|
|
||||||
|
const authorizationUri = `https://connect.stripe.com/oauth/v2/authorize?response_type=code&client_id=${clientId}&scope=read_write&redirect_uri=${redirectUrl}`;
|
||||||
|
|
||||||
|
return authorizationUri;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,6 +4,8 @@ import { StripeInvoiceCheckoutSessionPOJO } from '@/interfaces/StripePayment';
|
|||||||
import { CreateStripeAccountService } from './CreateStripeAccountService';
|
import { CreateStripeAccountService } from './CreateStripeAccountService';
|
||||||
import { CreateStripeAccountLinkService } from './CreateStripeAccountLink';
|
import { CreateStripeAccountLinkService } from './CreateStripeAccountLink';
|
||||||
import { CreateStripeAccountDTO } from './types';
|
import { CreateStripeAccountDTO } from './types';
|
||||||
|
import { ExchangeStripeOAuthTokenService } from './ExchangeStripeOauthToken';
|
||||||
|
import { GetStripeAuthorizationLinkService } from './GetStripeAuthorizationLink';
|
||||||
|
|
||||||
export class StripePaymentApplication {
|
export class StripePaymentApplication {
|
||||||
@Inject()
|
@Inject()
|
||||||
@@ -15,6 +17,12 @@ export class StripePaymentApplication {
|
|||||||
@Inject()
|
@Inject()
|
||||||
private createInvoiceCheckoutSessionService: CreateInvoiceCheckoutSession;
|
private createInvoiceCheckoutSessionService: CreateInvoiceCheckoutSession;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
private exchangeStripeOAuthTokenService: ExchangeStripeOAuthTokenService;
|
||||||
|
|
||||||
|
@Inject()
|
||||||
|
private getStripeConnectLinkService: GetStripeAuthorizationLinkService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new Stripe account for Bigcapital.
|
* Creates a new Stripe account for Bigcapital.
|
||||||
* @param {number} tenantId
|
* @param {number} tenantId
|
||||||
@@ -58,4 +66,24 @@ export class StripePaymentApplication {
|
|||||||
paymentLinkId
|
paymentLinkId
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves Stripe OAuth2 connect link.
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
public getStripeConnectLink() {
|
||||||
|
return this.getStripeConnectLinkService.getStripeAuthLink();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exchanges the given Stripe authorization code to Stripe user id and access token.
|
||||||
|
* @param {string} authorizationCode
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
public exchangeStripeOAuthToken(tenantId: number, authorizationCode: string) {
|
||||||
|
return this.exchangeStripeOAuthTokenService.excahngeStripeOAuthToken(
|
||||||
|
tenantId,
|
||||||
|
authorizationCode
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,11 +2,11 @@ import { Service } from 'typedi';
|
|||||||
import stripe from 'stripe';
|
import stripe from 'stripe';
|
||||||
import config from '@/config';
|
import config from '@/config';
|
||||||
|
|
||||||
const origin = 'http://localhost:4000';
|
const origin = 'https://cfdf-102-164-97-88.ngrok-free.app';
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export class StripePaymentService {
|
export class StripePaymentService {
|
||||||
public stripe;
|
public stripe: stripe;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.stripe = new stripe(config.stripePayment.secretKey, {
|
this.stripe = new stripe(config.stripePayment.secretKey, {
|
||||||
@@ -62,8 +62,9 @@ export class StripePaymentService {
|
|||||||
*/
|
*/
|
||||||
public async createAccount(): Promise<string> {
|
public async createAccount(): Promise<string> {
|
||||||
try {
|
try {
|
||||||
const account = await this.stripe.accounts.create({});
|
const account = await this.stripe.accounts.create({
|
||||||
|
type: 'standard',
|
||||||
|
});
|
||||||
return account;
|
return account;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
export const STRIPE_PAYMENT_LINK_REDIRECT = 'https://your_redirect_url.com';
|
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
import { Inject, Service } from 'typedi';
|
||||||
|
import events from '@/subscribers/events';
|
||||||
|
import HasTenancyService from '@/services/Tenancy/TenancyService';
|
||||||
|
import { StripeOAuthCodeGrantedEventPayload } from '../types';
|
||||||
|
|
||||||
|
@Service()
|
||||||
|
export class SeedStripeAccountsOnOAuthGrantedSubscriber {
|
||||||
|
@Inject()
|
||||||
|
private tenancy: HasTenancyService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attaches the subscriber to the event dispatcher.
|
||||||
|
*/
|
||||||
|
public attach(bus) {
|
||||||
|
bus.subscribe(
|
||||||
|
events.stripeIntegration.onOAuthCodeGranted,
|
||||||
|
this.handleSeedStripeAccount.bind(this)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Seeds the default integration settings once oauth authorization code granted.
|
||||||
|
* @param {StripeCheckoutSessionCompletedEventPayload} payload -
|
||||||
|
*/
|
||||||
|
async handleSeedStripeAccount({
|
||||||
|
tenantId,
|
||||||
|
paymentIntegrationId,
|
||||||
|
trx,
|
||||||
|
}: StripeOAuthCodeGrantedEventPayload) {
|
||||||
|
const { PaymentIntegration } = this.tenancy.models(tenantId);
|
||||||
|
const { accountRepository } = this.tenancy.repositories(tenantId);
|
||||||
|
|
||||||
|
const clearingAccount = await accountRepository.findOrCreateStripeClearing(
|
||||||
|
{},
|
||||||
|
trx
|
||||||
|
);
|
||||||
|
const bankAccount = await accountRepository.findBySlug('bank-account');
|
||||||
|
|
||||||
|
// Patch the Stripe integration default settings.
|
||||||
|
await PaymentIntegration.query(trx)
|
||||||
|
.findById(paymentIntegrationId)
|
||||||
|
.patch({
|
||||||
|
options: {
|
||||||
|
bankAccountId: bankAccount.id,
|
||||||
|
clearingAccountId: clearingAccount.id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,11 @@
|
|||||||
|
import { Knex } from 'knex';
|
||||||
|
|
||||||
|
|
||||||
export interface CreateStripeAccountDTO {
|
export interface CreateStripeAccountDTO {
|
||||||
name?: string;
|
name?: string;
|
||||||
}
|
}
|
||||||
|
export interface StripeOAuthCodeGrantedEventPayload {
|
||||||
|
tenantId: number;
|
||||||
|
paymentIntegrationId: number;
|
||||||
|
trx?: Knex.Transaction
|
||||||
|
}
|
||||||
@@ -723,7 +723,9 @@ export default {
|
|||||||
onAccountDeleted: 'onStripeIntegrationAccountDeleted',
|
onAccountDeleted: 'onStripeIntegrationAccountDeleted',
|
||||||
|
|
||||||
onPaymentLinkCreated: 'onStripePaymentLinkCreated',
|
onPaymentLinkCreated: 'onStripePaymentLinkCreated',
|
||||||
onPaymentLinkInactivated: 'onStripePaymentLinkInactivated'
|
onPaymentLinkInactivated: 'onStripePaymentLinkInactivated',
|
||||||
|
|
||||||
|
onOAuthCodeGranted: 'onStripeOAuthCodeGranted',
|
||||||
},
|
},
|
||||||
|
|
||||||
// Stripe Payment Webhooks
|
// Stripe Payment Webhooks
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { useEffect } from 'react';
|
||||||
|
import { useHistory, useLocation } from 'react-router-dom';
|
||||||
|
import { useSetStripeAccountCallback } from '@/hooks/query/stripe-integration';
|
||||||
|
|
||||||
|
function useQuery() {
|
||||||
|
const { search } = useLocation();
|
||||||
|
|
||||||
|
return React.useMemo(() => new URLSearchParams(search), [search]);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function PreferencesStripeCallback() {
|
||||||
|
const query = useQuery();
|
||||||
|
const code = query.get('code') as string;
|
||||||
|
const { mutateAsync: stripeAccountCallback } = useSetStripeAccountCallback();
|
||||||
|
|
||||||
|
const history = useHistory();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
stripeAccountCallback({ code }).then(() => {
|
||||||
|
history.push('/preferences/payment-methods')
|
||||||
|
});
|
||||||
|
}, [history, stripeAccountCallback, code]);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
@@ -10,8 +10,9 @@ import {
|
|||||||
Popover,
|
Popover,
|
||||||
Tag,
|
Tag,
|
||||||
Text,
|
Text,
|
||||||
|
Tooltip,
|
||||||
} from '@blueprintjs/core';
|
} from '@blueprintjs/core';
|
||||||
import { AppToaster, Box, Card, Group, Stack } from '@/components';
|
import { Box, Card, Group, Stack } from '@/components';
|
||||||
import { StripeLogo } from '@/icons/StripeLogo';
|
import { StripeLogo } from '@/icons/StripeLogo';
|
||||||
import { usePaymentMethodsBoot } from './PreferencesPaymentMethodsBoot';
|
import { usePaymentMethodsBoot } from './PreferencesPaymentMethodsBoot';
|
||||||
import { DialogsName } from '@/constants/dialogs';
|
import { DialogsName } from '@/constants/dialogs';
|
||||||
@@ -20,7 +21,6 @@ import {
|
|||||||
useDialogActions,
|
useDialogActions,
|
||||||
useDrawerActions,
|
useDrawerActions,
|
||||||
} from '@/hooks/state';
|
} from '@/hooks/state';
|
||||||
import { useCreateStripeAccountLink } from '@/hooks/query/stripe-integration';
|
|
||||||
import { DRAWERS } from '@/constants/drawers';
|
import { DRAWERS } from '@/constants/drawers';
|
||||||
import { MoreIcon } from '@/icons/More';
|
import { MoreIcon } from '@/icons/More';
|
||||||
import { STRIPE_PRICING_LINK } from './constants';
|
import { STRIPE_PRICING_LINK } from './constants';
|
||||||
@@ -34,39 +34,17 @@ export function StripePaymentMethod() {
|
|||||||
const stripeState = paymentMethodsState?.stripe;
|
const stripeState = paymentMethodsState?.stripe;
|
||||||
|
|
||||||
const isAccountCreated = stripeState?.isStripeAccountCreated;
|
const isAccountCreated = stripeState?.isStripeAccountCreated;
|
||||||
const isAccountActive = stripeState?.isStripePaymentActive;
|
const isPaymentEnabled = stripeState?.isStripePaymentEnabled;
|
||||||
const stripeAccountId = stripeState?.stripeAccountId;
|
const isPayoutEnabled = stripeState?.isStripePayoutEnabled;
|
||||||
|
const isStripeEnabled = stripeState?.isStripeEnabled;
|
||||||
const stripePaymentMethodId = stripeState?.stripePaymentMethodId;
|
const stripePaymentMethodId = stripeState?.stripePaymentMethodId;
|
||||||
const isStripeServerConfigured = stripeState?.isStripeServerConfigured;
|
const isStripeServerConfigured = stripeState?.isStripeServerConfigured;
|
||||||
|
|
||||||
const {
|
|
||||||
mutateAsync: createStripeAccountLink,
|
|
||||||
isLoading: isCreateStripeLinkLoading,
|
|
||||||
} = useCreateStripeAccountLink();
|
|
||||||
|
|
||||||
// Handle Stripe setup button click.
|
// Handle Stripe setup button click.
|
||||||
const handleSetUpBtnClick = () => {
|
const handleSetUpBtnClick = () => {
|
||||||
openDialog(DialogsName.StripeSetup);
|
openDialog(DialogsName.StripeSetup);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Handle complete Stripe setup button click.
|
|
||||||
const handleCompleteSetUpBtnClick = () => {
|
|
||||||
createStripeAccountLink({ stripeAccountId })
|
|
||||||
.then((res) => {
|
|
||||||
const { clientSecret } = res;
|
|
||||||
|
|
||||||
if (clientSecret.url) {
|
|
||||||
window.open(clientSecret.url, '_blank');
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
AppToaster.show({
|
|
||||||
message: 'Something went wrong.',
|
|
||||||
intent: Intent.DANGER,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// Handle edit button click.
|
// Handle edit button click.
|
||||||
const handleEditBtnClick = () => {
|
const handleEditBtnClick = () => {
|
||||||
openDrawer(DRAWERS.STRIPE_PAYMENT_INTEGRATION_EDIT, {
|
openDrawer(DRAWERS.STRIPE_PAYMENT_INTEGRATION_EDIT, {
|
||||||
@@ -87,14 +65,30 @@ export function StripePaymentMethod() {
|
|||||||
<Group>
|
<Group>
|
||||||
<StripeLogo />
|
<StripeLogo />
|
||||||
|
|
||||||
{isAccountActive && (
|
<Group spacing={10}>
|
||||||
<Tag minimal intent={Intent.SUCCESS}>
|
{isStripeEnabled && (
|
||||||
Active
|
<Tag minimal intent={Intent.SUCCESS}>
|
||||||
</Tag>
|
Active
|
||||||
)}
|
</Tag>
|
||||||
|
)}
|
||||||
|
{!isPaymentEnabled && isAccountCreated && (
|
||||||
|
<Tooltip content="The account cannot accept payments because verification may be incomplete, there may be legal or compliance issues, or required documents haven't been submitted or verified.">
|
||||||
|
<Tag minimal intent={Intent.DANGER}>
|
||||||
|
Payment Not Enabled
|
||||||
|
</Tag>
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
|
{!isPayoutEnabled && isAccountCreated && (
|
||||||
|
<Tooltip content="The account cannot receive payouts due to incomplete or invalid bank details, pending identity verification, or compliance restrictions.">
|
||||||
|
<Tag minimal intent={Intent.DANGER}>
|
||||||
|
Payout Not Enabled
|
||||||
|
</Tag>
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
|
</Group>
|
||||||
</Group>
|
</Group>
|
||||||
<Group spacing={10}>
|
<Group spacing={10}>
|
||||||
{isAccountActive && (
|
{isAccountCreated && (
|
||||||
<Button small onClick={handleEditBtnClick}>
|
<Button small onClick={handleEditBtnClick}>
|
||||||
Edit
|
Edit
|
||||||
</Button>
|
</Button>
|
||||||
@@ -104,16 +98,6 @@ export function StripePaymentMethod() {
|
|||||||
Set it Up
|
Set it Up
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
{isAccountCreated && !isAccountActive && (
|
|
||||||
<Button
|
|
||||||
intent={Intent.PRIMARY}
|
|
||||||
small
|
|
||||||
onClick={handleCompleteSetUpBtnClick}
|
|
||||||
loading={isCreateStripeLinkLoading}
|
|
||||||
>
|
|
||||||
Complete Stripe Set Up
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
{isAccountCreated && (
|
{isAccountCreated && (
|
||||||
<Popover
|
<Popover
|
||||||
content={
|
content={
|
||||||
|
|||||||
@@ -1,53 +1,32 @@
|
|||||||
|
import { useState } from 'react';
|
||||||
import { Button, DialogBody, DialogFooter, Intent } from '@blueprintjs/core';
|
import { Button, DialogBody, DialogFooter, Intent } from '@blueprintjs/core';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import { Stack } from '@/components';
|
import { Stack } from '@/components';
|
||||||
import { useDialogContext } from '@/components/Dialog/DialogProvider';
|
import { useDialogContext } from '@/components/Dialog/DialogProvider';
|
||||||
import {
|
|
||||||
useCreateStripeAccount,
|
|
||||||
useCreateStripeAccountLink,
|
|
||||||
} from '@/hooks/query/stripe-integration';
|
|
||||||
import { useDialogActions } from '@/hooks/state';
|
import { useDialogActions } from '@/hooks/state';
|
||||||
import { CreditCard2Icon } from '@/icons/CreditCard2';
|
import { CreditCard2Icon } from '@/icons/CreditCard2';
|
||||||
import { DollarIcon } from '@/icons/Dollar';
|
import { DollarIcon } from '@/icons/Dollar';
|
||||||
import { LayoutAutoIcon } from '@/icons/LayoutAuto';
|
import { LayoutAutoIcon } from '@/icons/LayoutAuto';
|
||||||
import { SwitchIcon } from '@/icons/SwitchIcon';
|
import { SwitchIcon } from '@/icons/SwitchIcon';
|
||||||
|
import { usePaymentMethodsBoot } from '../../PreferencesPaymentMethodsBoot';
|
||||||
|
|
||||||
export function StripePreSetupDialogContent() {
|
export function StripePreSetupDialogContent() {
|
||||||
const { name } = useDialogContext();
|
const { name } = useDialogContext();
|
||||||
const { closeDialog } = useDialogActions();
|
const { closeDialog } = useDialogActions();
|
||||||
|
const { paymentMethodsState } = usePaymentMethodsBoot();
|
||||||
const {
|
const [isRedirecting, setIsRedirecting] = useState<boolean>(false);
|
||||||
mutateAsync: createStripeAccount,
|
|
||||||
isLoading: isCreateStripeAccountLoading,
|
|
||||||
} = useCreateStripeAccount();
|
|
||||||
|
|
||||||
const {
|
|
||||||
mutateAsync: createStripeAccountLink,
|
|
||||||
isLoading: isCreateStripeLinkLoading,
|
|
||||||
} = useCreateStripeAccountLink();
|
|
||||||
|
|
||||||
const handleSetUpBtnClick = () => {
|
const handleSetUpBtnClick = () => {
|
||||||
createStripeAccount({})
|
if (paymentMethodsState?.stripe.stripeAuthLink) {
|
||||||
.then((response) => {
|
setIsRedirecting(true);
|
||||||
const { account_id: accountId } = response;
|
window.location.href = paymentMethodsState?.stripe.stripeAuthLink;
|
||||||
|
}
|
||||||
return createStripeAccountLink({ stripeAccountId: accountId });
|
|
||||||
})
|
|
||||||
.then((res) => {
|
|
||||||
const { clientSecret } = res;
|
|
||||||
|
|
||||||
if (clientSecret.url) {
|
|
||||||
window.location.href = clientSecret.url;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
// Handle cancel button click.
|
||||||
const handleCancelBtnClick = () => {
|
const handleCancelBtnClick = () => {
|
||||||
closeDialog(name);
|
closeDialog(name);
|
||||||
};
|
};
|
||||||
|
|
||||||
const isLoading = isCreateStripeAccountLoading || isCreateStripeLinkLoading;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<DialogBody>
|
<DialogBody>
|
||||||
@@ -92,7 +71,7 @@ export function StripePreSetupDialogContent() {
|
|||||||
<Button
|
<Button
|
||||||
intent={Intent.PRIMARY}
|
intent={Intent.PRIMARY}
|
||||||
onClick={handleSetUpBtnClick}
|
onClick={handleSetUpBtnClick}
|
||||||
loading={isLoading}
|
loading={isRedirecting}
|
||||||
>
|
>
|
||||||
Set Up Stripe
|
Set Up Stripe
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { Button, Intent } from '@blueprintjs/core';
|
|||||||
import { useFormikContext } from 'formik';
|
import { useFormikContext } from 'formik';
|
||||||
import { useDrawerContext } from '@/components/Drawer/DrawerProvider';
|
import { useDrawerContext } from '@/components/Drawer/DrawerProvider';
|
||||||
import { useDrawerActions } from '@/hooks/state';
|
import { useDrawerActions } from '@/hooks/state';
|
||||||
|
import { ACCOUNT_TYPE } from '@/constants';
|
||||||
|
|
||||||
export function StripeIntegrationEditFormContent() {
|
export function StripeIntegrationEditFormContent() {
|
||||||
const { accounts } = useStripeIntegrationEditBoot();
|
const { accounts } = useStripeIntegrationEditBoot();
|
||||||
@@ -19,6 +20,7 @@ export function StripeIntegrationEditFormContent() {
|
|||||||
<AccountsSelect
|
<AccountsSelect
|
||||||
name={'bankAccountId'}
|
name={'bankAccountId'}
|
||||||
items={accounts}
|
items={accounts}
|
||||||
|
filterByTypes={[ACCOUNT_TYPE.CASH, ACCOUNT_TYPE.BANK]}
|
||||||
fastField
|
fastField
|
||||||
fill
|
fill
|
||||||
allowCreate
|
allowCreate
|
||||||
@@ -35,6 +37,7 @@ export function StripeIntegrationEditFormContent() {
|
|||||||
<AccountsSelect
|
<AccountsSelect
|
||||||
name={'clearingAccountId'}
|
name={'clearingAccountId'}
|
||||||
items={accounts}
|
items={accounts}
|
||||||
|
filterByTypes={[ACCOUNT_TYPE.OTHER_CURRENT_LIABILITY]}
|
||||||
fastField
|
fastField
|
||||||
fill
|
fill
|
||||||
allowCreate
|
allowCreate
|
||||||
|
|||||||
@@ -108,6 +108,7 @@ export function transformToEditForm(invoice) {
|
|||||||
: TaxType.Exclusive,
|
: TaxType.Exclusive,
|
||||||
entries,
|
entries,
|
||||||
attachments: transformAttachmentsToForm(invoice),
|
attachments: transformAttachmentsToForm(invoice),
|
||||||
|
payment_methods: transformPaymentMethodsToForm(invoice?.payment_methods),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,6 +229,11 @@ export function transformValueToRequest(values) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transformes the form payment methods to request.
|
||||||
|
* @param {Record<string, { enable: boolean }>} paymentMethods
|
||||||
|
* @returns {Array<{ payment_integration_id: string; enable: boolean }>}
|
||||||
|
*/
|
||||||
const transformPaymentMethodsToRequest = (
|
const transformPaymentMethodsToRequest = (
|
||||||
paymentMethods: Record<string, { enable: boolean }>,
|
paymentMethods: Record<string, { enable: boolean }>,
|
||||||
): Array<{ payment_integration_id: string; enable: boolean }> => {
|
): Array<{ payment_integration_id: string; enable: boolean }> => {
|
||||||
@@ -237,6 +243,20 @@ const transformPaymentMethodsToRequest = (
|
|||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transformes payment methods from request to form.
|
||||||
|
* @param {Array<{ payment_integration_id: number; enable: boolean }>} paymentMethods
|
||||||
|
* @returns {Record<string, { enable: boolean }>}
|
||||||
|
*/
|
||||||
|
const transformPaymentMethodsToForm = (
|
||||||
|
paymentMethods: Array<{ payment_integration_id: number; enable: boolean }>,
|
||||||
|
): Record<string, { enable: boolean }> => {
|
||||||
|
return paymentMethods?.reduce((acc, method) => {
|
||||||
|
acc[method.payment_integration_id] = { enable: method.enable };
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
};
|
||||||
|
|
||||||
export const useSetPrimaryWarehouseToForm = () => {
|
export const useSetPrimaryWarehouseToForm = () => {
|
||||||
const { setFieldValue } = useFormikContext();
|
const { setFieldValue } = useFormikContext();
|
||||||
const { warehouses, isWarehousesSuccess } = useInvoiceFormContext();
|
const { warehouses, isWarehousesSuccess } = useInvoiceFormContext();
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import { transformToCamelCase, transfromToSnakeCase } from '@/utils';
|
|||||||
const PaymentServicesQueryKey = 'PaymentServices';
|
const PaymentServicesQueryKey = 'PaymentServices';
|
||||||
const PaymentServicesStateQueryKey = 'PaymentServicesState';
|
const PaymentServicesStateQueryKey = 'PaymentServicesState';
|
||||||
|
|
||||||
|
|
||||||
// # Get payment services.
|
// # Get payment services.
|
||||||
// -----------------------------------------
|
// -----------------------------------------
|
||||||
export interface GetPaymentServicesResponse {}
|
export interface GetPaymentServicesResponse {}
|
||||||
@@ -48,12 +47,15 @@ export const useGetPaymentServices = (
|
|||||||
export interface GetPaymentServicesStateResponse {
|
export interface GetPaymentServicesStateResponse {
|
||||||
stripe: {
|
stripe: {
|
||||||
isStripeAccountCreated: boolean;
|
isStripeAccountCreated: boolean;
|
||||||
isStripePaymentActive: boolean;
|
isStripePaymentEnabled: boolean;
|
||||||
|
isStripePayoutEnabled: boolean;
|
||||||
|
isStripeEnabled: boolean;
|
||||||
isStripeServerConfigured: boolean;
|
isStripeServerConfigured: boolean;
|
||||||
stripeAccountId: string | null;
|
stripeAccountId: string | null;
|
||||||
stripePaymentMethodId: number | null;
|
stripePaymentMethodId: number | null;
|
||||||
stripeCurrencies: string[];
|
stripeCurrencies: string[];
|
||||||
stripePublishableKey: string;
|
stripePublishableKey: string;
|
||||||
|
stripeAuthLink: string;
|
||||||
stripeRedirectUrl: string;
|
stripeRedirectUrl: string;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import {
|
|||||||
import useApiRequest from '../useRequest';
|
import useApiRequest from '../useRequest';
|
||||||
import { transformToCamelCase } from '@/utils';
|
import { transformToCamelCase } from '@/utils';
|
||||||
|
|
||||||
|
|
||||||
// Create Stripe Account Link.
|
// Create Stripe Account Link.
|
||||||
// ------------------------------------
|
// ------------------------------------
|
||||||
interface StripeAccountLinkResponse {
|
interface StripeAccountLinkResponse {
|
||||||
@@ -47,7 +46,6 @@ export const useCreateStripeAccountLink = (
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// Create Stripe Account Session.
|
// Create Stripe Account Session.
|
||||||
// ------------------------------------
|
// ------------------------------------
|
||||||
interface AccountSessionValues {
|
interface AccountSessionValues {
|
||||||
@@ -149,3 +147,70 @@ export const useCreateStripeCheckoutSession = (
|
|||||||
{ ...options },
|
{ ...options },
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Create Stripe Account OAuth Link.
|
||||||
|
// ------------------------------------
|
||||||
|
interface StripeAccountLinkResponse {
|
||||||
|
clientSecret: {
|
||||||
|
created: number;
|
||||||
|
expiresAt: number;
|
||||||
|
object: string;
|
||||||
|
url: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface StripeAccountLinkValues {
|
||||||
|
stripeAccountId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useGetStripeAccountLink = (
|
||||||
|
options?: UseQueryOptions<StripeAccountLinkResponse, Error>,
|
||||||
|
): UseQueryResult<StripeAccountLinkResponse, Error> => {
|
||||||
|
const apiRequest = useApiRequest();
|
||||||
|
return useQuery(
|
||||||
|
'getStripeAccountLink',
|
||||||
|
() => {
|
||||||
|
return apiRequest
|
||||||
|
.get('/stripe_integration/link')
|
||||||
|
.then((res) => transformToCamelCase(res.data));
|
||||||
|
},
|
||||||
|
{ ...options },
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get Stripe Account OAuth Callback Mutation.
|
||||||
|
// ------------------------------------
|
||||||
|
interface StripeAccountCallbackMutationValues {
|
||||||
|
code: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface StripeAccountCallbackMutationResponse {
|
||||||
|
success: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useSetStripeAccountCallback = (
|
||||||
|
options?: UseMutationOptions<
|
||||||
|
StripeAccountCallbackMutationResponse,
|
||||||
|
Error,
|
||||||
|
StripeAccountCallbackMutationValues
|
||||||
|
>,
|
||||||
|
): UseMutationResult<
|
||||||
|
StripeAccountCallbackMutationResponse,
|
||||||
|
Error,
|
||||||
|
StripeAccountCallbackMutationValues
|
||||||
|
> => {
|
||||||
|
const apiRequest = useApiRequest();
|
||||||
|
return useMutation(
|
||||||
|
(values: StripeAccountCallbackMutationValues) => {
|
||||||
|
return apiRequest
|
||||||
|
.post(`/stripe_integration/callback`, values)
|
||||||
|
.then(
|
||||||
|
(res) =>
|
||||||
|
transformToCamelCase(
|
||||||
|
res.data,
|
||||||
|
) as StripeAccountCallbackMutationResponse,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
{ ...options },
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|||||||
@@ -28,6 +28,13 @@ export const getPreferenceRoutes = () => [
|
|||||||
),
|
),
|
||||||
exact: true,
|
exact: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: `${BASE_URL}/payment-methods/stripe/callback`,
|
||||||
|
component: lazy(
|
||||||
|
() => import('../containers/Preferences/PaymentMethods/PreferencesStripeCallback'),
|
||||||
|
),
|
||||||
|
exact: true,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: `${BASE_URL}/credit-notes`,
|
path: `${BASE_URL}/credit-notes`,
|
||||||
component: lazy(() =>
|
component: lazy(() =>
|
||||||
|
|||||||
Reference in New Issue
Block a user