mirror of
https://github.com/bitwarden/browser
synced 2025-12-12 22:33:35 +00:00
[PM-24964] Stripe-hosted bank account verification (#16220)
* Implement bank account hosted URL verification with webhook handling notification * [PM-25491] Create org/provider bank account warning needs to be updated
This commit is contained in:
@@ -19,6 +19,7 @@ import {
|
|||||||
take,
|
take,
|
||||||
takeUntil,
|
takeUntil,
|
||||||
tap,
|
tap,
|
||||||
|
withLatestFrom,
|
||||||
} from "rxjs";
|
} from "rxjs";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -31,6 +32,7 @@ import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
|||||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||||
import { DialogService } from "@bitwarden/components";
|
import { DialogService } from "@bitwarden/components";
|
||||||
|
import { CommandDefinition, MessageListener } from "@bitwarden/messaging";
|
||||||
import { SubscriberBillingClient } from "@bitwarden/web-vault/app/billing/clients";
|
import { SubscriberBillingClient } from "@bitwarden/web-vault/app/billing/clients";
|
||||||
import { OrganizationFreeTrialWarningComponent } from "@bitwarden/web-vault/app/billing/organizations/warnings/components";
|
import { OrganizationFreeTrialWarningComponent } from "@bitwarden/web-vault/app/billing/organizations/warnings/components";
|
||||||
import { OrganizationWarningsService } from "@bitwarden/web-vault/app/billing/organizations/warnings/services";
|
import { OrganizationWarningsService } from "@bitwarden/web-vault/app/billing/organizations/warnings/services";
|
||||||
@@ -67,6 +69,10 @@ type View = {
|
|||||||
taxIdWarning: TaxIdWarningType | null;
|
taxIdWarning: TaxIdWarningType | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const BANK_ACCOUNT_VERIFIED_COMMAND = new CommandDefinition<{ organizationId: string }>(
|
||||||
|
"organizationBankAccountVerified",
|
||||||
|
);
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
templateUrl: "./organization-payment-details.component.html",
|
templateUrl: "./organization-payment-details.component.html",
|
||||||
standalone: true,
|
standalone: true,
|
||||||
@@ -150,6 +156,7 @@ export class OrganizationPaymentDetailsComponent implements OnInit, OnDestroy {
|
|||||||
private activatedRoute: ActivatedRoute,
|
private activatedRoute: ActivatedRoute,
|
||||||
private configService: ConfigService,
|
private configService: ConfigService,
|
||||||
private dialogService: DialogService,
|
private dialogService: DialogService,
|
||||||
|
private messageListener: MessageListener,
|
||||||
private organizationService: OrganizationService,
|
private organizationService: OrganizationService,
|
||||||
private organizationWarningsService: OrganizationWarningsService,
|
private organizationWarningsService: OrganizationWarningsService,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
@@ -195,6 +202,30 @@ export class OrganizationPaymentDetailsComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.messageListener
|
||||||
|
.messages$(BANK_ACCOUNT_VERIFIED_COMMAND)
|
||||||
|
.pipe(
|
||||||
|
withLatestFrom(this.view$),
|
||||||
|
filter(([message, view]) => message.organizationId === view.organization.data.id),
|
||||||
|
switchMap(
|
||||||
|
async ([_, view]) =>
|
||||||
|
await Promise.all([
|
||||||
|
this.subscriberBillingClient.getPaymentMethod(view.organization),
|
||||||
|
this.subscriberBillingClient.getBillingAddress(view.organization),
|
||||||
|
]),
|
||||||
|
),
|
||||||
|
tap(async ([paymentMethod, billingAddress]) => {
|
||||||
|
if (paymentMethod) {
|
||||||
|
await this.setPaymentMethod(paymentMethod);
|
||||||
|
}
|
||||||
|
if (billingAddress) {
|
||||||
|
this.setBillingAddress(billingAddress);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
takeUntil(this.destroy$),
|
||||||
|
)
|
||||||
|
.subscribe();
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import { BitwardenSubscriber } from "../../types";
|
|||||||
import { MaskedPaymentMethod } from "../types";
|
import { MaskedPaymentMethod } from "../types";
|
||||||
|
|
||||||
import { ChangePaymentMethodDialogComponent } from "./change-payment-method-dialog.component";
|
import { ChangePaymentMethodDialogComponent } from "./change-payment-method-dialog.component";
|
||||||
import { VerifyBankAccountComponent } from "./verify-bank-account.component";
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: "app-display-payment-method",
|
selector: "app-display-payment-method",
|
||||||
@@ -18,18 +17,23 @@ import { VerifyBankAccountComponent } from "./verify-bank-account.component";
|
|||||||
@if (paymentMethod) {
|
@if (paymentMethod) {
|
||||||
@switch (paymentMethod.type) {
|
@switch (paymentMethod.type) {
|
||||||
@case ("bankAccount") {
|
@case ("bankAccount") {
|
||||||
@if (!paymentMethod.verified) {
|
@if (paymentMethod.hostedVerificationUrl) {
|
||||||
<app-verify-bank-account
|
<p>
|
||||||
[subscriber]="subscriber"
|
{{ "verifyBankAccountWithStripe" | i18n }}
|
||||||
(verified)="onBankAccountVerified($event)"
|
<a
|
||||||
>
|
bitLink
|
||||||
</app-verify-bank-account>
|
rel="noreferrer"
|
||||||
|
target="_blank"
|
||||||
|
[attr.href]="paymentMethod.hostedVerificationUrl"
|
||||||
|
>{{ "verifyNow" | i18n }}</a
|
||||||
|
>
|
||||||
|
</p>
|
||||||
}
|
}
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<i class="bwi bwi-fw bwi-billing"></i>
|
<i class="bwi bwi-fw bwi-billing"></i>
|
||||||
{{ paymentMethod.bankName }}, *{{ paymentMethod.last4 }}
|
{{ paymentMethod.bankName }}, *{{ paymentMethod.last4 }}
|
||||||
@if (!paymentMethod.verified) {
|
@if (paymentMethod.hostedVerificationUrl) {
|
||||||
<span>- {{ "unverified" | i18n }}</span>
|
<span>- {{ "unverified" | i18n }}</span>
|
||||||
}
|
}
|
||||||
</p>
|
</p>
|
||||||
@@ -63,7 +67,7 @@ import { VerifyBankAccountComponent } from "./verify-bank-account.component";
|
|||||||
</bit-section>
|
</bit-section>
|
||||||
`,
|
`,
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [SharedModule, VerifyBankAccountComponent],
|
imports: [SharedModule],
|
||||||
})
|
})
|
||||||
export class DisplayPaymentMethodComponent {
|
export class DisplayPaymentMethodComponent {
|
||||||
@Input({ required: true }) subscriber!: BitwardenSubscriber;
|
@Input({ required: true }) subscriber!: BitwardenSubscriber;
|
||||||
@@ -96,8 +100,6 @@ export class DisplayPaymentMethodComponent {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
onBankAccountVerified = (paymentMethod: MaskedPaymentMethod) => this.updated.emit(paymentMethod);
|
|
||||||
|
|
||||||
protected getBrandIconForCard = (): string | null => {
|
protected getBrandIconForCard = (): string | null => {
|
||||||
if (this.paymentMethod?.type !== "card") {
|
if (this.paymentMethod?.type !== "card") {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ type PaymentMethodFormGroup = FormGroup<{
|
|||||||
@case ("bankAccount") {
|
@case ("bankAccount") {
|
||||||
<ng-container>
|
<ng-container>
|
||||||
<bit-callout type="warning" title="{{ 'verifyBankAccount' | i18n }}">
|
<bit-callout type="warning" title="{{ 'verifyBankAccount' | i18n }}">
|
||||||
{{ "verifyBankAccountWarning" | i18n }}
|
{{ "requiredToVerifyBankAccountWithStripe" | i18n }}
|
||||||
</bit-callout>
|
</bit-callout>
|
||||||
<div class="tw-grid tw-grid-cols-2 tw-gap-4 tw-mb-4" formGroupName="bankAccount">
|
<div class="tw-grid tw-grid-cols-2 tw-gap-4 tw-mb-4" formGroupName="bankAccount">
|
||||||
<bit-form-field class="tw-col-span-1" [disableMargin]="true">
|
<bit-form-field class="tw-col-span-1" [disableMargin]="true">
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ type MaskedBankAccount = {
|
|||||||
type: BankAccountPaymentMethod;
|
type: BankAccountPaymentMethod;
|
||||||
bankName: string;
|
bankName: string;
|
||||||
last4: string;
|
last4: string;
|
||||||
verified: boolean;
|
hostedVerificationUrl?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
type MaskedCard = {
|
type MaskedCard = {
|
||||||
@@ -73,7 +73,7 @@ class MaskedBankAccountResponse extends BaseResponse implements MaskedBankAccoun
|
|||||||
type: BankAccountPaymentMethod;
|
type: BankAccountPaymentMethod;
|
||||||
bankName: string;
|
bankName: string;
|
||||||
last4: string;
|
last4: string;
|
||||||
verified: boolean;
|
hostedVerificationUrl?: string;
|
||||||
|
|
||||||
constructor(response: any) {
|
constructor(response: any) {
|
||||||
super(response);
|
super(response);
|
||||||
@@ -81,7 +81,7 @@ class MaskedBankAccountResponse extends BaseResponse implements MaskedBankAccoun
|
|||||||
this.type = "bankAccount";
|
this.type = "bankAccount";
|
||||||
this.bankName = this.getResponseProperty("BankName");
|
this.bankName = this.getResponseProperty("BankName");
|
||||||
this.last4 = this.getResponseProperty("Last4");
|
this.last4 = this.getResponseProperty("Last4");
|
||||||
this.verified = this.getResponseProperty("Verified");
|
this.hostedVerificationUrl = this.getResponseProperty("HostedVerificationUrl");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -81,7 +81,7 @@
|
|||||||
<!-- Bank Account -->
|
<!-- Bank Account -->
|
||||||
<ng-container *ngIf="showBankAccount && usingBankAccount">
|
<ng-container *ngIf="showBankAccount && usingBankAccount">
|
||||||
<bit-callout type="warning" title="{{ 'verifyBankAccount' | i18n }}">
|
<bit-callout type="warning" title="{{ 'verifyBankAccount' | i18n }}">
|
||||||
{{ bankAccountWarning }}
|
{{ "requiredToVerifyBankAccountWithStripe" | i18n }}
|
||||||
</bit-callout>
|
</bit-callout>
|
||||||
<div class="tw-grid tw-grid-cols-2 tw-gap-4 tw-mb-4" formGroupName="bankInformation">
|
<div class="tw-grid tw-grid-cols-2 tw-gap-4 tw-mb-4" formGroupName="bankInformation">
|
||||||
<bit-form-field class="tw-col-span-1" disableMargin>
|
<bit-form-field class="tw-col-span-1" disableMargin>
|
||||||
|
|||||||
@@ -212,12 +212,4 @@ export class PaymentComponent implements OnInit, OnDestroy {
|
|||||||
private get usingStripe(): boolean {
|
private get usingStripe(): boolean {
|
||||||
return this.usingBankAccount || this.usingCard;
|
return this.usingBankAccount || this.usingCard;
|
||||||
}
|
}
|
||||||
|
|
||||||
get bankAccountWarning(): string {
|
|
||||||
if (this.bankAccountWarningOverride) {
|
|
||||||
return this.bankAccountWarningOverride;
|
|
||||||
} else {
|
|
||||||
return this.i18nService.t("verifyBankAccountWithStatementDescriptorWarning");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11244,5 +11244,14 @@
|
|||||||
},
|
},
|
||||||
"confirmKeyConnectorDomain": {
|
"confirmKeyConnectorDomain": {
|
||||||
"message": "Confirm Key Connector domain"
|
"message": "Confirm Key Connector domain"
|
||||||
|
},
|
||||||
|
"requiredToVerifyBankAccountWithStripe": {
|
||||||
|
"message": "Payment with a bank account is only available to customers in the United States. You will be required to verify your bank account. We will make a micro-deposit within the next 1-2 business days. Failure to verify the bank account will result in a missed payment and your subscription being suspended."
|
||||||
|
},
|
||||||
|
"verifyBankAccountWithStripe": {
|
||||||
|
"message": "We have made a micro-deposit to your bank account. This may take 1-2 business days. When you see the deposit in your account, you can verify your bank account. Failure to verify your bank account will result in a missed payment and your subscription will be suspended."
|
||||||
|
},
|
||||||
|
"verifyNow": {
|
||||||
|
"message": "Verify now."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,13 +17,18 @@ import {
|
|||||||
take,
|
take,
|
||||||
takeUntil,
|
takeUntil,
|
||||||
tap,
|
tap,
|
||||||
|
withLatestFrom,
|
||||||
} from "rxjs";
|
} from "rxjs";
|
||||||
import { catchError } from "rxjs/operators";
|
import { catchError } from "rxjs/operators";
|
||||||
|
|
||||||
import { ProviderService } from "@bitwarden/common/admin-console/abstractions/provider.service";
|
import { ProviderService } from "@bitwarden/common/admin-console/abstractions/provider.service";
|
||||||
import { Provider } from "@bitwarden/common/admin-console/models/domain/provider";
|
import { Provider } from "@bitwarden/common/admin-console/models/domain/provider";
|
||||||
|
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||||
|
import { getUserId } from "@bitwarden/common/auth/services/account.service";
|
||||||
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||||
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||||
|
import { CommandDefinition, MessageListener } from "@bitwarden/messaging";
|
||||||
|
import { UserId } from "@bitwarden/user-core";
|
||||||
import { SubscriberBillingClient } from "@bitwarden/web-vault/app/billing/clients";
|
import { SubscriberBillingClient } from "@bitwarden/web-vault/app/billing/clients";
|
||||||
import {
|
import {
|
||||||
DisplayAccountCreditComponent,
|
DisplayAccountCreditComponent,
|
||||||
@@ -52,6 +57,7 @@ class RedirectError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type View = {
|
type View = {
|
||||||
|
activeUserId: UserId;
|
||||||
provider: BitwardenSubscriber;
|
provider: BitwardenSubscriber;
|
||||||
paymentMethod: MaskedPaymentMethod | null;
|
paymentMethod: MaskedPaymentMethod | null;
|
||||||
billingAddress: BillingAddress | null;
|
billingAddress: BillingAddress | null;
|
||||||
@@ -59,6 +65,11 @@ type View = {
|
|||||||
taxIdWarning: TaxIdWarningType | null;
|
taxIdWarning: TaxIdWarningType | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const BANK_ACCOUNT_VERIFIED_COMMAND = new CommandDefinition<{
|
||||||
|
providerId: string;
|
||||||
|
adminId: string;
|
||||||
|
}>("providerBankAccountVerified");
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
templateUrl: "./provider-payment-details.component.html",
|
templateUrl: "./provider-payment-details.component.html",
|
||||||
imports: [
|
imports: [
|
||||||
@@ -94,15 +105,20 @@ export class ProviderPaymentDetailsComponent implements OnInit, OnDestroy {
|
|||||||
const getTaxIdWarning = firstValueFrom(
|
const getTaxIdWarning = firstValueFrom(
|
||||||
this.providerWarningsService.getTaxIdWarning$(provider.data as Provider),
|
this.providerWarningsService.getTaxIdWarning$(provider.data as Provider),
|
||||||
);
|
);
|
||||||
|
const getActiveUserId = firstValueFrom(this.accountService.activeAccount$.pipe(getUserId));
|
||||||
|
|
||||||
const [paymentMethod, billingAddress, credit, taxIdWarning] = await Promise.all([
|
const [activeUserId, paymentMethod, billingAddress, credit, taxIdWarning] = await Promise.all(
|
||||||
this.billingClient.getPaymentMethod(provider),
|
[
|
||||||
this.billingClient.getBillingAddress(provider),
|
getActiveUserId,
|
||||||
this.billingClient.getCredit(provider),
|
this.billingClient.getPaymentMethod(provider),
|
||||||
getTaxIdWarning,
|
this.billingClient.getBillingAddress(provider),
|
||||||
]);
|
this.billingClient.getCredit(provider),
|
||||||
|
getTaxIdWarning,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
activeUserId,
|
||||||
provider,
|
provider,
|
||||||
paymentMethod,
|
paymentMethod,
|
||||||
billingAddress,
|
billingAddress,
|
||||||
@@ -131,9 +147,11 @@ export class ProviderPaymentDetailsComponent implements OnInit, OnDestroy {
|
|||||||
protected enableTaxIdWarning!: boolean;
|
protected enableTaxIdWarning!: boolean;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
private accountService: AccountService,
|
||||||
private activatedRoute: ActivatedRoute,
|
private activatedRoute: ActivatedRoute,
|
||||||
private billingClient: SubscriberBillingClient,
|
private billingClient: SubscriberBillingClient,
|
||||||
private configService: ConfigService,
|
private configService: ConfigService,
|
||||||
|
private messageListener: MessageListener,
|
||||||
private providerService: ProviderService,
|
private providerService: ProviderService,
|
||||||
private providerWarningsService: ProviderWarningsService,
|
private providerWarningsService: ProviderWarningsService,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
@@ -169,6 +187,33 @@ export class ProviderPaymentDetailsComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.messageListener
|
||||||
|
.messages$(BANK_ACCOUNT_VERIFIED_COMMAND)
|
||||||
|
.pipe(
|
||||||
|
withLatestFrom(this.view$),
|
||||||
|
filter(
|
||||||
|
([message, view]) =>
|
||||||
|
message.providerId === view.provider.data.id && message.adminId === view.activeUserId,
|
||||||
|
),
|
||||||
|
switchMap(
|
||||||
|
async ([_, view]) =>
|
||||||
|
await Promise.all([
|
||||||
|
this.subscriberBillingClient.getPaymentMethod(view.provider),
|
||||||
|
this.subscriberBillingClient.getBillingAddress(view.provider),
|
||||||
|
]),
|
||||||
|
),
|
||||||
|
tap(async ([paymentMethod, billingAddress]) => {
|
||||||
|
if (paymentMethod) {
|
||||||
|
await this.setPaymentMethod(paymentMethod);
|
||||||
|
}
|
||||||
|
if (billingAddress) {
|
||||||
|
this.setBillingAddress(billingAddress);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
takeUntil(this.destroy$),
|
||||||
|
)
|
||||||
|
.subscribe();
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
|
|||||||
@@ -30,4 +30,7 @@ export enum NotificationType {
|
|||||||
NotificationStatus = 21,
|
NotificationStatus = 21,
|
||||||
|
|
||||||
RefreshSecurityTasks = 22,
|
RefreshSecurityTasks = 22,
|
||||||
|
|
||||||
|
OrganizationBankAccountVerified = 23,
|
||||||
|
ProviderBankAccountVerified = 24,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,6 +63,12 @@ export class NotificationResponse extends BaseResponse {
|
|||||||
case NotificationType.NotificationStatus:
|
case NotificationType.NotificationStatus:
|
||||||
this.payload = new EndUserNotificationResponse(payload);
|
this.payload = new EndUserNotificationResponse(payload);
|
||||||
break;
|
break;
|
||||||
|
case NotificationType.OrganizationBankAccountVerified:
|
||||||
|
this.payload = new OrganizationBankAccountVerifiedPushNotification(payload);
|
||||||
|
break;
|
||||||
|
case NotificationType.ProviderBankAccountVerified:
|
||||||
|
this.payload = new ProviderBankAccountVerifiedPushNotification(payload);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -158,3 +164,23 @@ export class OrganizationCollectionSettingChangedPushNotification extends BaseRe
|
|||||||
this.limitCollectionDeletion = this.getResponseProperty("LimitCollectionDeletion");
|
this.limitCollectionDeletion = this.getResponseProperty("LimitCollectionDeletion");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class OrganizationBankAccountVerifiedPushNotification extends BaseResponse {
|
||||||
|
organizationId: string;
|
||||||
|
|
||||||
|
constructor(response: any) {
|
||||||
|
super(response);
|
||||||
|
this.organizationId = this.getResponseProperty("OrganizationId");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ProviderBankAccountVerifiedPushNotification extends BaseResponse {
|
||||||
|
providerId: string;
|
||||||
|
adminId: string;
|
||||||
|
|
||||||
|
constructor(response: any) {
|
||||||
|
super(response);
|
||||||
|
this.providerId = this.getResponseProperty("ProviderId");
|
||||||
|
this.adminId = this.getResponseProperty("AdminId");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -298,6 +298,17 @@ export class DefaultServerNotificationsService implements ServerNotificationsSer
|
|||||||
case NotificationType.SyncOrganizationCollectionSettingChanged:
|
case NotificationType.SyncOrganizationCollectionSettingChanged:
|
||||||
await this.syncService.fullSync(true);
|
await this.syncService.fullSync(true);
|
||||||
break;
|
break;
|
||||||
|
case NotificationType.OrganizationBankAccountVerified:
|
||||||
|
this.messagingService.send("organizationBankAccountVerified", {
|
||||||
|
organizationId: notification.payload.organizationId,
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case NotificationType.ProviderBankAccountVerified:
|
||||||
|
this.messagingService.send("providerBankAccountVerified", {
|
||||||
|
providerId: notification.payload.providerId,
|
||||||
|
adminId: notification.payload.adminId,
|
||||||
|
});
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user