зеркало из https://github.com/mozilla/fxa.git
Merge pull request #16607 from mozilla/FXA-8939
feat(payments-paypal): Create PaypalManager getCustomerBillingAgreementId
This commit is contained in:
Коммит
500b2a0b09
|
@ -21,6 +21,11 @@ import {
|
|||
import { PayPalClient } from './paypal.client';
|
||||
import { PayPalManager } from './paypal.manager';
|
||||
import { BillingAgreementStatus } from './paypal.types';
|
||||
import {
|
||||
PaypalCustomerNotFoundError,
|
||||
PaypalCustomerMultipleRecordsError,
|
||||
} from './paypalCustomer/paypalCustomer.error';
|
||||
import { ResultPaypalCustomerFactory } from './paypalCustomer/paypalCustomer.factories';
|
||||
import { PaypalCustomerManager } from './paypalCustomer/paypalCustomer.manager';
|
||||
|
||||
describe('PaypalManager', () => {
|
||||
|
@ -147,6 +152,48 @@ describe('PaypalManager', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('getCustomerBillingAgreementId', () => {
|
||||
it("returns the customer's current PayPal billing agreement ID", async () => {
|
||||
const mockPayPalCustomer = ResultPaypalCustomerFactory();
|
||||
const mockStripeCustomer = CustomerFactory();
|
||||
|
||||
paypalCustomerManager.fetchPaypalCustomersByUid = jest
|
||||
.fn()
|
||||
.mockResolvedValueOnce([mockPayPalCustomer]);
|
||||
|
||||
const result = await paypalManager.getCustomerBillingAgreementId(
|
||||
mockStripeCustomer
|
||||
);
|
||||
expect(result).toEqual(mockPayPalCustomer.billingAgreementId);
|
||||
});
|
||||
|
||||
it('throws PaypalCustomerNotFoundError if no PayPal customer record', async () => {
|
||||
const mockStripeCustomer = CustomerFactory();
|
||||
|
||||
paypalCustomerManager.fetchPaypalCustomersByUid = jest
|
||||
.fn()
|
||||
.mockResolvedValueOnce([]);
|
||||
|
||||
expect(
|
||||
paypalManager.getCustomerBillingAgreementId(mockStripeCustomer)
|
||||
).rejects.toBeInstanceOf(PaypalCustomerNotFoundError);
|
||||
});
|
||||
|
||||
it('throws PaypalCustomerMultipleRecordsError if more than one PayPal customer found', async () => {
|
||||
const mockPayPalCustomer1 = ResultPaypalCustomerFactory();
|
||||
const mockPayPalCustomer2 = ResultPaypalCustomerFactory();
|
||||
const mockStripeCustomer = CustomerFactory();
|
||||
|
||||
paypalCustomerManager.fetchPaypalCustomersByUid = jest
|
||||
.fn()
|
||||
.mockResolvedValueOnce([mockPayPalCustomer1, mockPayPalCustomer2]);
|
||||
|
||||
expect(
|
||||
paypalManager.getCustomerBillingAgreementId(mockStripeCustomer)
|
||||
).rejects.toBeInstanceOf(PaypalCustomerMultipleRecordsError);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getCustomerPayPalSubscriptions', () => {
|
||||
it('return customer subscriptions where collection method is send_invoice', async () => {
|
||||
const mockPayPalSubscription = SubscriptionFactory({
|
||||
|
|
|
@ -12,6 +12,10 @@ import {
|
|||
import { AccountDatabase } from '@fxa/shared/db/mysql/account';
|
||||
import { PayPalClient } from './paypal.client';
|
||||
import { BillingAgreement, BillingAgreementStatus } from './paypal.types';
|
||||
import {
|
||||
PaypalCustomerNotFoundError,
|
||||
PaypalCustomerMultipleRecordsError,
|
||||
} from './paypalCustomer/paypalCustomer.error';
|
||||
import { PaypalCustomerManager } from './paypalCustomer/paypalCustomer.manager';
|
||||
|
||||
@Injectable()
|
||||
|
@ -54,11 +58,27 @@ export class PayPalManager {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the customer’s current paypal billing agreement ID from the
|
||||
* auth database via the Paypal repository
|
||||
*/
|
||||
async getCustomerBillingAgreementId(customer: Stripe.Customer) {
|
||||
const paypalCustomer =
|
||||
await this.paypalCustomerManager.fetchPaypalCustomersByUid(
|
||||
customer.metadata.userid
|
||||
);
|
||||
const firstRecord = paypalCustomer.at(0);
|
||||
|
||||
if (!firstRecord)
|
||||
throw new PaypalCustomerNotFoundError(customer.metadata.uid);
|
||||
if (paypalCustomer.length > 1)
|
||||
throw new PaypalCustomerMultipleRecordsError(customer.metadata.uid);
|
||||
|
||||
return firstRecord.billingAgreementId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves PayPal subscriptions
|
||||
*
|
||||
* @param customer
|
||||
* @returns
|
||||
*/
|
||||
async getCustomerPayPalSubscriptions(customer: Stripe.Customer) {
|
||||
const subscriptions = await this.stripeManager.getSubscriptions(
|
||||
|
@ -82,10 +102,6 @@ export class PayPalManager {
|
|||
|
||||
/**
|
||||
* Process an invoice when amount is greater than minimum amount
|
||||
*
|
||||
* @param customer
|
||||
* @param invoice
|
||||
* @param ipaddress
|
||||
*/
|
||||
async processNonZeroInvoice(
|
||||
customer: Stripe.Customer,
|
||||
|
@ -99,8 +115,6 @@ export class PayPalManager {
|
|||
|
||||
/**
|
||||
* Finalize and process a draft invoice that has no amounted owed.
|
||||
*
|
||||
* @param invoice
|
||||
*/
|
||||
async processZeroInvoice(invoiceId: string) {
|
||||
// It appears for subscriptions that do not require payment, the invoice
|
||||
|
@ -113,8 +127,6 @@ export class PayPalManager {
|
|||
* Process an invoice
|
||||
* If amount is less than minimum amount, call processZeroInvoice
|
||||
* If amount is greater than minimum amount, call processNonZeroInvoice (legacy PaypalHelper processInvoice)
|
||||
*
|
||||
* @param invoice
|
||||
*/
|
||||
async processInvoice(invoice: Stripe.Invoice) {
|
||||
const amountInCents = invoice.amount_due;
|
||||
|
|
|
@ -23,7 +23,7 @@ export class PaypalCustomerNotCreatedError extends PaypalCustomerManagerError {
|
|||
}
|
||||
|
||||
export class PaypalCustomerNotFoundError extends PaypalCustomerManagerError {
|
||||
constructor(uid: string, cause: Error) {
|
||||
constructor(uid: string, cause?: Error) {
|
||||
super('PaypalCustomer not found', {
|
||||
info: {
|
||||
uid,
|
||||
|
@ -60,3 +60,14 @@ export class PaypalCustomerNotDeletedError extends PaypalCustomerManagerError {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class PaypalCustomerMultipleRecordsError extends PaypalCustomerManagerError {
|
||||
constructor(uid: string, cause?: Error) {
|
||||
super('Multiple PaypalCustomer records', {
|
||||
info: {
|
||||
uid,
|
||||
},
|
||||
cause,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,9 +20,6 @@ export class StripeClient {
|
|||
|
||||
/**
|
||||
* Retrieves a customer record directly from Stripe
|
||||
*
|
||||
* @param customerId The Stripe customer ID of the customer to fetch
|
||||
* @returns The customer record for the customerId provided
|
||||
*/
|
||||
async fetchCustomer(customerId: string) {
|
||||
return this.stripe.customers.retrieve(customerId);
|
||||
|
@ -44,9 +41,6 @@ export class StripeClient {
|
|||
|
||||
/**
|
||||
* Retrieves subscriptions directly from Stripe
|
||||
*
|
||||
* @param customerId
|
||||
* @returns
|
||||
*/
|
||||
async fetchSubscriptions(customerId: string) {
|
||||
return this.stripe.subscriptions.list({
|
||||
|
|
|
@ -22,9 +22,6 @@ export class StripeManager {
|
|||
|
||||
/**
|
||||
* Retrieves a customer record
|
||||
*
|
||||
* @param customerId
|
||||
* @returns
|
||||
*/
|
||||
async fetchActiveCustomer(customerId: string) {
|
||||
const customer = await this.client.fetchCustomer(customerId);
|
||||
|
@ -44,9 +41,6 @@ export class StripeManager {
|
|||
/**
|
||||
* Returns minimum amount for valid currency
|
||||
* Throws error for invalid currency
|
||||
*
|
||||
* @param currency
|
||||
* @returns
|
||||
*/
|
||||
getMinimumAmount(currency: string): number {
|
||||
if (STRIPE_MINIMUM_CHARGE_AMOUNTS[currency]) {
|
||||
|
@ -58,8 +52,6 @@ export class StripeManager {
|
|||
|
||||
/**
|
||||
* Retrieves subscriptions
|
||||
*
|
||||
* @param customerId
|
||||
*/
|
||||
async getSubscriptions(customerId: string) {
|
||||
return this.client.fetchSubscriptions(customerId);
|
||||
|
|
Загрузка…
Ссылка в новой задаче