refactor use cases
This commit is contained in:
@@ -5,7 +5,6 @@ import type { IPaymentRepository } from '@core/payments/domain/repositories/IPay
|
||||
import type { IMembershipFeeRepository, IMemberPaymentRepository } from '@core/payments/domain/repositories/IMembershipFeeRepository';
|
||||
import type { IPrizeRepository } from '@core/payments/domain/repositories/IPrizeRepository';
|
||||
import type { IWalletRepository, ITransactionRepository } from '@core/payments/domain/repositories/IWalletRepository';
|
||||
import type { UseCaseOutputPort } from '@core/shared/application';
|
||||
|
||||
// Import use cases
|
||||
import { GetPaymentsUseCase } from '@core/payments/application/use-cases/GetPaymentsUseCase';
|
||||
@@ -24,20 +23,6 @@ import { ProcessWalletTransactionUseCase } from '@core/payments/application/use-
|
||||
// Import concrete in-memory implementations
|
||||
import { ConsoleLogger } from '@adapters/logging/ConsoleLogger';
|
||||
|
||||
// Presenters
|
||||
import { GetPaymentsPresenter } from './presenters/GetPaymentsPresenter';
|
||||
import { CreatePaymentPresenter } from './presenters/CreatePaymentPresenter';
|
||||
import { UpdatePaymentStatusPresenter } from './presenters/UpdatePaymentStatusPresenter';
|
||||
import { GetMembershipFeesPresenter } from './presenters/GetMembershipFeesPresenter';
|
||||
import { UpsertMembershipFeePresenter } from './presenters/UpsertMembershipFeePresenter';
|
||||
import { UpdateMemberPaymentPresenter } from './presenters/UpdateMemberPaymentPresenter';
|
||||
import { GetPrizesPresenter } from './presenters/GetPrizesPresenter';
|
||||
import { CreatePrizePresenter } from './presenters/CreatePrizePresenter';
|
||||
import { AwardPrizePresenter } from './presenters/AwardPrizePresenter';
|
||||
import { DeletePrizePresenter } from './presenters/DeletePrizePresenter';
|
||||
import { GetWalletPresenter } from './presenters/GetWalletPresenter';
|
||||
import { ProcessWalletTransactionPresenter } from './presenters/ProcessWalletTransactionPresenter';
|
||||
|
||||
import {
|
||||
PAYMENT_REPOSITORY_TOKEN,
|
||||
MEMBERSHIP_FEE_REPOSITORY_TOKEN,
|
||||
@@ -58,88 +43,12 @@ import {
|
||||
DELETE_PRIZE_USE_CASE_TOKEN,
|
||||
GET_WALLET_USE_CASE_TOKEN,
|
||||
PROCESS_WALLET_TRANSACTION_USE_CASE_TOKEN,
|
||||
GET_PAYMENTS_OUTPUT_PORT_TOKEN,
|
||||
CREATE_PAYMENT_OUTPUT_PORT_TOKEN,
|
||||
UPDATE_PAYMENT_STATUS_OUTPUT_PORT_TOKEN,
|
||||
GET_MEMBERSHIP_FEES_OUTPUT_PORT_TOKEN,
|
||||
UPSERT_MEMBERSHIP_FEE_OUTPUT_PORT_TOKEN,
|
||||
UPDATE_MEMBER_PAYMENT_OUTPUT_PORT_TOKEN,
|
||||
GET_PRIZES_OUTPUT_PORT_TOKEN,
|
||||
CREATE_PRIZE_OUTPUT_PORT_TOKEN,
|
||||
AWARD_PRIZE_OUTPUT_PORT_TOKEN,
|
||||
DELETE_PRIZE_OUTPUT_PORT_TOKEN,
|
||||
GET_WALLET_OUTPUT_PORT_TOKEN,
|
||||
PROCESS_WALLET_TRANSACTION_OUTPUT_PORT_TOKEN,
|
||||
} from './PaymentsTokens';
|
||||
|
||||
export * from './PaymentsTokens';
|
||||
|
||||
export const PaymentsProviders: Provider[] = [
|
||||
|
||||
// Presenters
|
||||
GetPaymentsPresenter,
|
||||
CreatePaymentPresenter,
|
||||
UpdatePaymentStatusPresenter,
|
||||
GetMembershipFeesPresenter,
|
||||
UpsertMembershipFeePresenter,
|
||||
UpdateMemberPaymentPresenter,
|
||||
GetPrizesPresenter,
|
||||
CreatePrizePresenter,
|
||||
AwardPrizePresenter,
|
||||
DeletePrizePresenter,
|
||||
GetWalletPresenter,
|
||||
ProcessWalletTransactionPresenter,
|
||||
|
||||
// Output ports
|
||||
{
|
||||
provide: GET_PAYMENTS_OUTPUT_PORT_TOKEN,
|
||||
useExisting: GetPaymentsPresenter,
|
||||
},
|
||||
{
|
||||
provide: CREATE_PAYMENT_OUTPUT_PORT_TOKEN,
|
||||
useExisting: CreatePaymentPresenter,
|
||||
},
|
||||
{
|
||||
provide: UPDATE_PAYMENT_STATUS_OUTPUT_PORT_TOKEN,
|
||||
useExisting: UpdatePaymentStatusPresenter,
|
||||
},
|
||||
{
|
||||
provide: GET_MEMBERSHIP_FEES_OUTPUT_PORT_TOKEN,
|
||||
useExisting: GetMembershipFeesPresenter,
|
||||
},
|
||||
{
|
||||
provide: UPSERT_MEMBERSHIP_FEE_OUTPUT_PORT_TOKEN,
|
||||
useExisting: UpsertMembershipFeePresenter,
|
||||
},
|
||||
{
|
||||
provide: UPDATE_MEMBER_PAYMENT_OUTPUT_PORT_TOKEN,
|
||||
useExisting: UpdateMemberPaymentPresenter,
|
||||
},
|
||||
{
|
||||
provide: GET_PRIZES_OUTPUT_PORT_TOKEN,
|
||||
useExisting: GetPrizesPresenter,
|
||||
},
|
||||
{
|
||||
provide: CREATE_PRIZE_OUTPUT_PORT_TOKEN,
|
||||
useExisting: CreatePrizePresenter,
|
||||
},
|
||||
{
|
||||
provide: AWARD_PRIZE_OUTPUT_PORT_TOKEN,
|
||||
useExisting: AwardPrizePresenter,
|
||||
},
|
||||
{
|
||||
provide: DELETE_PRIZE_OUTPUT_PORT_TOKEN,
|
||||
useExisting: DeletePrizePresenter,
|
||||
},
|
||||
{
|
||||
provide: GET_WALLET_OUTPUT_PORT_TOKEN,
|
||||
useExisting: GetWalletPresenter,
|
||||
},
|
||||
{
|
||||
provide: PROCESS_WALLET_TRANSACTION_OUTPUT_PORT_TOKEN,
|
||||
useExisting: ProcessWalletTransactionPresenter,
|
||||
},
|
||||
|
||||
// Logger
|
||||
{
|
||||
provide: LOGGER_TOKEN,
|
||||
@@ -151,66 +60,66 @@ export const PaymentsProviders: Provider[] = [
|
||||
// Use cases (use cases receive repositories, services receive use cases)
|
||||
{
|
||||
provide: GET_PAYMENTS_USE_CASE_TOKEN,
|
||||
useFactory: (paymentRepo: IPaymentRepository, output: UseCaseOutputPort<unknown>) => new GetPaymentsUseCase(paymentRepo, output),
|
||||
inject: [PAYMENT_REPOSITORY_TOKEN, GET_PAYMENTS_OUTPUT_PORT_TOKEN],
|
||||
useFactory: (paymentRepo: IPaymentRepository) => new GetPaymentsUseCase(paymentRepo),
|
||||
inject: [PAYMENT_REPOSITORY_TOKEN],
|
||||
},
|
||||
{
|
||||
provide: CREATE_PAYMENT_USE_CASE_TOKEN,
|
||||
useFactory: (paymentRepo: IPaymentRepository, output: UseCaseOutputPort<unknown>) => new CreatePaymentUseCase(paymentRepo, output),
|
||||
inject: [PAYMENT_REPOSITORY_TOKEN, CREATE_PAYMENT_OUTPUT_PORT_TOKEN],
|
||||
useFactory: (paymentRepo: IPaymentRepository) => new CreatePaymentUseCase(paymentRepo),
|
||||
inject: [PAYMENT_REPOSITORY_TOKEN],
|
||||
},
|
||||
{
|
||||
provide: UPDATE_PAYMENT_STATUS_USE_CASE_TOKEN,
|
||||
useFactory: (paymentRepo: IPaymentRepository, output: UseCaseOutputPort<unknown>) => new UpdatePaymentStatusUseCase(paymentRepo, output),
|
||||
inject: [PAYMENT_REPOSITORY_TOKEN, UPDATE_PAYMENT_STATUS_OUTPUT_PORT_TOKEN],
|
||||
useFactory: (paymentRepo: IPaymentRepository) => new UpdatePaymentStatusUseCase(paymentRepo),
|
||||
inject: [PAYMENT_REPOSITORY_TOKEN],
|
||||
},
|
||||
{
|
||||
provide: GET_MEMBERSHIP_FEES_USE_CASE_TOKEN,
|
||||
useFactory: (membershipFeeRepo: IMembershipFeeRepository, memberPaymentRepo: IMemberPaymentRepository, output: UseCaseOutputPort<unknown>) =>
|
||||
new GetMembershipFeesUseCase(membershipFeeRepo, memberPaymentRepo, output),
|
||||
inject: [MEMBERSHIP_FEE_REPOSITORY_TOKEN, MEMBER_PAYMENT_REPOSITORY_TOKEN, GET_MEMBERSHIP_FEES_OUTPUT_PORT_TOKEN],
|
||||
useFactory: (membershipFeeRepo: IMembershipFeeRepository, memberPaymentRepo: IMemberPaymentRepository) =>
|
||||
new GetMembershipFeesUseCase(membershipFeeRepo, memberPaymentRepo),
|
||||
inject: [MEMBERSHIP_FEE_REPOSITORY_TOKEN, MEMBER_PAYMENT_REPOSITORY_TOKEN],
|
||||
},
|
||||
{
|
||||
provide: UPSERT_MEMBERSHIP_FEE_USE_CASE_TOKEN,
|
||||
useFactory: (membershipFeeRepo: IMembershipFeeRepository, output: UseCaseOutputPort<unknown>) => new UpsertMembershipFeeUseCase(membershipFeeRepo, output),
|
||||
inject: [MEMBERSHIP_FEE_REPOSITORY_TOKEN, UPSERT_MEMBERSHIP_FEE_OUTPUT_PORT_TOKEN],
|
||||
useFactory: (membershipFeeRepo: IMembershipFeeRepository) => new UpsertMembershipFeeUseCase(membershipFeeRepo),
|
||||
inject: [MEMBERSHIP_FEE_REPOSITORY_TOKEN],
|
||||
},
|
||||
{
|
||||
provide: UPDATE_MEMBER_PAYMENT_USE_CASE_TOKEN,
|
||||
useFactory: (membershipFeeRepo: IMembershipFeeRepository, memberPaymentRepo: IMemberPaymentRepository, output: UseCaseOutputPort<unknown>) =>
|
||||
new UpdateMemberPaymentUseCase(membershipFeeRepo, memberPaymentRepo, output),
|
||||
inject: [MEMBERSHIP_FEE_REPOSITORY_TOKEN, MEMBER_PAYMENT_REPOSITORY_TOKEN, UPDATE_MEMBER_PAYMENT_OUTPUT_PORT_TOKEN],
|
||||
useFactory: (membershipFeeRepo: IMembershipFeeRepository, memberPaymentRepo: IMemberPaymentRepository) =>
|
||||
new UpdateMemberPaymentUseCase(membershipFeeRepo, memberPaymentRepo),
|
||||
inject: [MEMBERSHIP_FEE_REPOSITORY_TOKEN, MEMBER_PAYMENT_REPOSITORY_TOKEN],
|
||||
},
|
||||
{
|
||||
provide: GET_PRIZES_USE_CASE_TOKEN,
|
||||
useFactory: (prizeRepo: IPrizeRepository, output: UseCaseOutputPort<unknown>) => new GetPrizesUseCase(prizeRepo, output),
|
||||
inject: [PRIZE_REPOSITORY_TOKEN, GET_PRIZES_OUTPUT_PORT_TOKEN],
|
||||
useFactory: (prizeRepo: IPrizeRepository) => new GetPrizesUseCase(prizeRepo),
|
||||
inject: [PRIZE_REPOSITORY_TOKEN],
|
||||
},
|
||||
{
|
||||
provide: CREATE_PRIZE_USE_CASE_TOKEN,
|
||||
useFactory: (prizeRepo: IPrizeRepository, output: UseCaseOutputPort<unknown>) => new CreatePrizeUseCase(prizeRepo, output),
|
||||
inject: [PRIZE_REPOSITORY_TOKEN, CREATE_PRIZE_OUTPUT_PORT_TOKEN],
|
||||
useFactory: (prizeRepo: IPrizeRepository) => new CreatePrizeUseCase(prizeRepo),
|
||||
inject: [PRIZE_REPOSITORY_TOKEN],
|
||||
},
|
||||
{
|
||||
provide: AWARD_PRIZE_USE_CASE_TOKEN,
|
||||
useFactory: (prizeRepo: IPrizeRepository, output: UseCaseOutputPort<unknown>) => new AwardPrizeUseCase(prizeRepo, output),
|
||||
inject: [PRIZE_REPOSITORY_TOKEN, AWARD_PRIZE_OUTPUT_PORT_TOKEN],
|
||||
useFactory: (prizeRepo: IPrizeRepository) => new AwardPrizeUseCase(prizeRepo),
|
||||
inject: [PRIZE_REPOSITORY_TOKEN],
|
||||
},
|
||||
{
|
||||
provide: DELETE_PRIZE_USE_CASE_TOKEN,
|
||||
useFactory: (prizeRepo: IPrizeRepository, output: UseCaseOutputPort<unknown>) => new DeletePrizeUseCase(prizeRepo, output),
|
||||
inject: [PRIZE_REPOSITORY_TOKEN, DELETE_PRIZE_OUTPUT_PORT_TOKEN],
|
||||
useFactory: (prizeRepo: IPrizeRepository) => new DeletePrizeUseCase(prizeRepo),
|
||||
inject: [PRIZE_REPOSITORY_TOKEN],
|
||||
},
|
||||
{
|
||||
provide: GET_WALLET_USE_CASE_TOKEN,
|
||||
useFactory: (walletRepo: IWalletRepository, transactionRepo: ITransactionRepository, output: UseCaseOutputPort<unknown>) =>
|
||||
new GetWalletUseCase(walletRepo, transactionRepo, output),
|
||||
inject: [WALLET_REPOSITORY_TOKEN, TRANSACTION_REPOSITORY_TOKEN, GET_WALLET_OUTPUT_PORT_TOKEN],
|
||||
useFactory: (walletRepo: IWalletRepository, transactionRepo: ITransactionRepository) =>
|
||||
new GetWalletUseCase(walletRepo, transactionRepo),
|
||||
inject: [WALLET_REPOSITORY_TOKEN, TRANSACTION_REPOSITORY_TOKEN],
|
||||
},
|
||||
{
|
||||
provide: PROCESS_WALLET_TRANSACTION_USE_CASE_TOKEN,
|
||||
useFactory: (walletRepo: IWalletRepository, transactionRepo: ITransactionRepository, output: UseCaseOutputPort<unknown>) =>
|
||||
new ProcessWalletTransactionUseCase(walletRepo, transactionRepo, output),
|
||||
inject: [WALLET_REPOSITORY_TOKEN, TRANSACTION_REPOSITORY_TOKEN, PROCESS_WALLET_TRANSACTION_OUTPUT_PORT_TOKEN],
|
||||
useFactory: (walletRepo: IWalletRepository, transactionRepo: ITransactionRepository) =>
|
||||
new ProcessWalletTransactionUseCase(walletRepo, transactionRepo),
|
||||
inject: [WALLET_REPOSITORY_TOKEN, TRANSACTION_REPOSITORY_TOKEN],
|
||||
},
|
||||
];
|
||||
@@ -6,42 +6,23 @@ describe('PaymentsService', () => {
|
||||
const logger = { debug: vi.fn(), info: vi.fn(), warn: vi.fn(), error: vi.fn() };
|
||||
|
||||
function makeService(overrides?: Partial<Record<string, any>>) {
|
||||
const getPaymentsUseCase = overrides?.getPaymentsUseCase ?? { execute: vi.fn(async () => Result.ok(undefined)) };
|
||||
const createPaymentUseCase = overrides?.createPaymentUseCase ?? { execute: vi.fn(async () => Result.ok(undefined)) };
|
||||
const getPaymentsUseCase = overrides?.getPaymentsUseCase ?? { execute: vi.fn(async () => Result.ok({ payments: [] })) };
|
||||
const createPaymentUseCase = overrides?.createPaymentUseCase ?? { execute: vi.fn(async () => Result.ok({ paymentId: 'p1' })) };
|
||||
const updatePaymentStatusUseCase =
|
||||
overrides?.updatePaymentStatusUseCase ?? { execute: vi.fn(async () => Result.ok(undefined)) };
|
||||
overrides?.updatePaymentStatusUseCase ?? { execute: vi.fn(async () => Result.ok({ success: true })) };
|
||||
const getMembershipFeesUseCase =
|
||||
overrides?.getMembershipFeesUseCase ?? { execute: vi.fn(async () => Result.ok(undefined)) };
|
||||
overrides?.getMembershipFeesUseCase ?? { execute: vi.fn(async () => Result.ok({ fee: null, payments: [] })) };
|
||||
const upsertMembershipFeeUseCase =
|
||||
overrides?.upsertMembershipFeeUseCase ?? { execute: vi.fn(async () => Result.ok(undefined)) };
|
||||
overrides?.upsertMembershipFeeUseCase ?? { execute: vi.fn(async () => Result.ok({ success: true })) };
|
||||
const updateMemberPaymentUseCase =
|
||||
overrides?.updateMemberPaymentUseCase ?? { execute: vi.fn(async () => Result.ok(undefined)) };
|
||||
const getPrizesUseCase = overrides?.getPrizesUseCase ?? { execute: vi.fn(async () => Result.ok(undefined)) };
|
||||
const createPrizeUseCase = overrides?.createPrizeUseCase ?? { execute: vi.fn(async () => Result.ok(undefined)) };
|
||||
const awardPrizeUseCase = overrides?.awardPrizeUseCase ?? { execute: vi.fn(async () => Result.ok(undefined)) };
|
||||
const deletePrizeUseCase = overrides?.deletePrizeUseCase ?? { execute: vi.fn(async () => Result.ok(undefined)) };
|
||||
const getWalletUseCase = overrides?.getWalletUseCase ?? { execute: vi.fn(async () => Result.ok(undefined)) };
|
||||
overrides?.updateMemberPaymentUseCase ?? { execute: vi.fn(async () => Result.ok({ success: true })) };
|
||||
const getPrizesUseCase = overrides?.getPrizesUseCase ?? { execute: vi.fn(async () => Result.ok({ prizes: [] })) };
|
||||
const createPrizeUseCase = overrides?.createPrizeUseCase ?? { execute: vi.fn(async () => Result.ok({ success: true })) };
|
||||
const awardPrizeUseCase = overrides?.awardPrizeUseCase ?? { execute: vi.fn(async () => Result.ok({ success: true })) };
|
||||
const deletePrizeUseCase = overrides?.deletePrizeUseCase ?? { execute: vi.fn(async () => Result.ok({ success: true })) };
|
||||
const getWalletUseCase = overrides?.getWalletUseCase ?? { execute: vi.fn(async () => Result.ok({ balance: 0 })) };
|
||||
const processWalletTransactionUseCase =
|
||||
overrides?.processWalletTransactionUseCase ?? { execute: vi.fn(async () => Result.ok(undefined)) };
|
||||
|
||||
const getPaymentsPresenter = overrides?.getPaymentsPresenter ?? { getResponseModel: vi.fn(() => ({ payments: [] })) };
|
||||
const createPaymentPresenter =
|
||||
overrides?.createPaymentPresenter ?? { getResponseModel: vi.fn(() => ({ paymentId: 'p1' })) };
|
||||
const updatePaymentStatusPresenter =
|
||||
overrides?.updatePaymentStatusPresenter ?? { getResponseModel: vi.fn(() => ({ success: true })) };
|
||||
|
||||
const getMembershipFeesPresenter = overrides?.getMembershipFeesPresenter ?? { viewModel: { fee: null, payments: [] } };
|
||||
const upsertMembershipFeePresenter = overrides?.upsertMembershipFeePresenter ?? { viewModel: { success: true } };
|
||||
const updateMemberPaymentPresenter = overrides?.updateMemberPaymentPresenter ?? { viewModel: { success: true } };
|
||||
|
||||
const getPrizesPresenter = overrides?.getPrizesPresenter ?? { viewModel: { prizes: [] } };
|
||||
const createPrizePresenter = overrides?.createPrizePresenter ?? { viewModel: { success: true } };
|
||||
const awardPrizePresenter = overrides?.awardPrizePresenter ?? { viewModel: { success: true } };
|
||||
const deletePrizePresenter = overrides?.deletePrizePresenter ?? { viewModel: { success: true } };
|
||||
|
||||
const getWalletPresenter = overrides?.getWalletPresenter ?? { viewModel: { balance: 0 } };
|
||||
const processWalletTransactionPresenter =
|
||||
overrides?.processWalletTransactionPresenter ?? { viewModel: { success: true } };
|
||||
overrides?.processWalletTransactionUseCase ?? { execute: vi.fn(async () => Result.ok({ success: true })) };
|
||||
|
||||
const service = new PaymentsService(
|
||||
getPaymentsUseCase as any,
|
||||
@@ -57,18 +38,6 @@ describe('PaymentsService', () => {
|
||||
getWalletUseCase as any,
|
||||
processWalletTransactionUseCase as any,
|
||||
logger as any,
|
||||
getPaymentsPresenter as any,
|
||||
createPaymentPresenter as any,
|
||||
updatePaymentStatusPresenter as any,
|
||||
getMembershipFeesPresenter as any,
|
||||
upsertMembershipFeePresenter as any,
|
||||
updateMemberPaymentPresenter as any,
|
||||
getPrizesPresenter as any,
|
||||
createPrizePresenter as any,
|
||||
awardPrizePresenter as any,
|
||||
deletePrizePresenter as any,
|
||||
getWalletPresenter as any,
|
||||
processWalletTransactionPresenter as any,
|
||||
);
|
||||
|
||||
return {
|
||||
@@ -85,26 +54,13 @@ describe('PaymentsService', () => {
|
||||
deletePrizeUseCase,
|
||||
getWalletUseCase,
|
||||
processWalletTransactionUseCase,
|
||||
getPaymentsPresenter,
|
||||
createPaymentPresenter,
|
||||
updatePaymentStatusPresenter,
|
||||
getMembershipFeesPresenter,
|
||||
upsertMembershipFeePresenter,
|
||||
updateMemberPaymentPresenter,
|
||||
getPrizesPresenter,
|
||||
createPrizePresenter,
|
||||
awardPrizePresenter,
|
||||
deletePrizePresenter,
|
||||
getWalletPresenter,
|
||||
processWalletTransactionPresenter,
|
||||
};
|
||||
}
|
||||
|
||||
it('getPayments returns presenter model on success', async () => {
|
||||
const { service, getPaymentsUseCase, getPaymentsPresenter } = makeService();
|
||||
const { service, getPaymentsUseCase } = makeService();
|
||||
await expect(service.getPayments({ leagueId: 'l1' } as any)).resolves.toEqual({ payments: [] });
|
||||
expect(getPaymentsUseCase.execute).toHaveBeenCalledWith({ leagueId: 'l1' });
|
||||
expect(getPaymentsPresenter.getResponseModel).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('getPayments throws when use case returns error (code message)', async () => {
|
||||
@@ -115,12 +71,9 @@ describe('PaymentsService', () => {
|
||||
});
|
||||
|
||||
it('createPayment returns presenter model on success', async () => {
|
||||
const { service, createPaymentUseCase, createPaymentPresenter } = makeService({
|
||||
createPaymentPresenter: { getResponseModel: vi.fn(() => ({ paymentId: 'p1' })) },
|
||||
});
|
||||
const { service, createPaymentUseCase } = makeService();
|
||||
await expect(service.createPayment({ leagueId: 'l1' } as any)).resolves.toEqual({ paymentId: 'p1' });
|
||||
expect(createPaymentUseCase.execute).toHaveBeenCalledWith({ leagueId: 'l1' });
|
||||
expect(createPaymentPresenter.getResponseModel).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('createPayment throws when use case returns error', async () => {
|
||||
@@ -131,12 +84,9 @@ describe('PaymentsService', () => {
|
||||
});
|
||||
|
||||
it('updatePaymentStatus returns presenter model on success', async () => {
|
||||
const { service, updatePaymentStatusUseCase, updatePaymentStatusPresenter } = makeService({
|
||||
updatePaymentStatusPresenter: { getResponseModel: vi.fn(() => ({ success: true })) },
|
||||
});
|
||||
const { service, updatePaymentStatusUseCase } = makeService();
|
||||
await expect(service.updatePaymentStatus({ paymentId: 'p1' } as any)).resolves.toEqual({ success: true });
|
||||
expect(updatePaymentStatusUseCase.execute).toHaveBeenCalledWith({ paymentId: 'p1' });
|
||||
expect(updatePaymentStatusPresenter.getResponseModel).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('updatePaymentStatus throws when use case returns error', async () => {
|
||||
@@ -147,8 +97,8 @@ describe('PaymentsService', () => {
|
||||
});
|
||||
|
||||
it('getMembershipFees returns viewModel on success', async () => {
|
||||
const { service, getMembershipFeesUseCase, getMembershipFeesPresenter } = makeService({
|
||||
getMembershipFeesPresenter: { viewModel: { fee: { amount: 1 }, payments: [] } },
|
||||
const { service, getMembershipFeesUseCase } = makeService({
|
||||
getMembershipFeesUseCase: { execute: vi.fn(async () => Result.ok({ fee: { amount: 1 }, payments: [] })) }
|
||||
});
|
||||
|
||||
await expect(service.getMembershipFees({ leagueId: 'l1', driverId: 'd1' } as any)).resolves.toEqual({
|
||||
@@ -156,7 +106,6 @@ describe('PaymentsService', () => {
|
||||
payments: [],
|
||||
});
|
||||
expect(getMembershipFeesUseCase.execute).toHaveBeenCalledWith({ leagueId: 'l1', driverId: 'd1' });
|
||||
expect(getMembershipFeesPresenter.viewModel).toBeDefined();
|
||||
});
|
||||
|
||||
it('getMembershipFees throws when use case returns error', async () => {
|
||||
@@ -167,9 +116,7 @@ describe('PaymentsService', () => {
|
||||
});
|
||||
|
||||
it('upsertMembershipFee returns viewModel on success', async () => {
|
||||
const { service, upsertMembershipFeeUseCase } = makeService({
|
||||
upsertMembershipFeePresenter: { viewModel: { success: true } },
|
||||
});
|
||||
const { service, upsertMembershipFeeUseCase } = makeService();
|
||||
|
||||
await expect(service.upsertMembershipFee({ leagueId: 'l1' } as any)).resolves.toEqual({ success: true });
|
||||
expect(upsertMembershipFeeUseCase.execute).toHaveBeenCalledWith({ leagueId: 'l1' });
|
||||
@@ -186,9 +133,7 @@ describe('PaymentsService', () => {
|
||||
});
|
||||
|
||||
it('updateMemberPayment returns viewModel on success', async () => {
|
||||
const { service, updateMemberPaymentUseCase } = makeService({
|
||||
updateMemberPaymentPresenter: { viewModel: { success: true } },
|
||||
});
|
||||
const { service, updateMemberPaymentUseCase } = makeService();
|
||||
|
||||
await expect(service.updateMemberPayment({ leagueId: 'l1' } as any)).resolves.toEqual({ success: true });
|
||||
expect(updateMemberPaymentUseCase.execute).toHaveBeenCalledWith({ leagueId: 'l1' });
|
||||
@@ -203,10 +148,9 @@ describe('PaymentsService', () => {
|
||||
});
|
||||
|
||||
it('getPrizes maps seasonId optional', async () => {
|
||||
const getPrizesUseCase = { execute: vi.fn(async () => Result.ok(undefined)) };
|
||||
const getPrizesUseCase = { execute: vi.fn(async () => Result.ok({ prizes: [] })) };
|
||||
const { service } = makeService({
|
||||
getPrizesUseCase,
|
||||
getPrizesPresenter: { viewModel: { prizes: [] } },
|
||||
});
|
||||
|
||||
await expect(service.getPrizes({ leagueId: 'l1' } as any)).resolves.toEqual({ prizes: [] });
|
||||
@@ -217,10 +161,9 @@ describe('PaymentsService', () => {
|
||||
});
|
||||
|
||||
it('createPrize calls use case and returns viewModel', async () => {
|
||||
const createPrizeUseCase = { execute: vi.fn(async () => Result.ok(undefined)) };
|
||||
const createPrizeUseCase = { execute: vi.fn(async () => Result.ok({ success: true })) };
|
||||
const { service } = makeService({
|
||||
createPrizeUseCase,
|
||||
createPrizePresenter: { viewModel: { success: true } },
|
||||
});
|
||||
|
||||
await expect(service.createPrize({ leagueId: 'l1' } as any)).resolves.toEqual({ success: true });
|
||||
@@ -228,10 +171,9 @@ describe('PaymentsService', () => {
|
||||
});
|
||||
|
||||
it('awardPrize calls use case and returns viewModel', async () => {
|
||||
const awardPrizeUseCase = { execute: vi.fn(async () => Result.ok(undefined)) };
|
||||
const awardPrizeUseCase = { execute: vi.fn(async () => Result.ok({ success: true })) };
|
||||
const { service } = makeService({
|
||||
awardPrizeUseCase,
|
||||
awardPrizePresenter: { viewModel: { success: true } },
|
||||
});
|
||||
|
||||
await expect(service.awardPrize({ prizeId: 'p1' } as any)).resolves.toEqual({ success: true });
|
||||
@@ -239,10 +181,9 @@ describe('PaymentsService', () => {
|
||||
});
|
||||
|
||||
it('deletePrize calls use case and returns viewModel', async () => {
|
||||
const deletePrizeUseCase = { execute: vi.fn(async () => Result.ok(undefined)) };
|
||||
const deletePrizeUseCase = { execute: vi.fn(async () => Result.ok({ success: true })) };
|
||||
const { service } = makeService({
|
||||
deletePrizeUseCase,
|
||||
deletePrizePresenter: { viewModel: { success: true } },
|
||||
});
|
||||
|
||||
await expect(service.deletePrize({ prizeId: 'p1' } as any)).resolves.toEqual({ success: true });
|
||||
@@ -250,10 +191,9 @@ describe('PaymentsService', () => {
|
||||
});
|
||||
|
||||
it('getWallet calls use case and returns viewModel', async () => {
|
||||
const getWalletUseCase = { execute: vi.fn(async () => Result.ok(undefined)) };
|
||||
const getWalletUseCase = { execute: vi.fn(async () => Result.ok({ balance: 10 })) };
|
||||
const { service } = makeService({
|
||||
getWalletUseCase,
|
||||
getWalletPresenter: { viewModel: { balance: 10 } },
|
||||
});
|
||||
|
||||
await expect(service.getWallet({ leagueId: 'l1' } as any)).resolves.toEqual({ balance: 10 });
|
||||
@@ -261,10 +201,9 @@ describe('PaymentsService', () => {
|
||||
});
|
||||
|
||||
it('processWalletTransaction calls use case and returns viewModel', async () => {
|
||||
const processWalletTransactionUseCase = { execute: vi.fn(async () => Result.ok(undefined)) };
|
||||
const processWalletTransactionUseCase = { execute: vi.fn(async () => Result.ok({ success: true })) };
|
||||
const { service } = makeService({
|
||||
processWalletTransactionUseCase,
|
||||
processWalletTransactionPresenter: { viewModel: { success: true } },
|
||||
});
|
||||
|
||||
await expect(service.processWalletTransaction({ leagueId: 'l1' } as any)).resolves.toEqual({ success: true });
|
||||
|
||||
@@ -15,20 +15,6 @@ import type { UpdateMemberPaymentUseCase } from '@core/payments/application/use-
|
||||
import type { UpdatePaymentStatusUseCase } from '@core/payments/application/use-cases/UpdatePaymentStatusUseCase';
|
||||
import type { UpsertMembershipFeeUseCase } from '@core/payments/application/use-cases/UpsertMembershipFeeUseCase';
|
||||
|
||||
// Presenters
|
||||
import { AwardPrizePresenter } from './presenters/AwardPrizePresenter';
|
||||
import { CreatePaymentPresenter } from './presenters/CreatePaymentPresenter';
|
||||
import { CreatePrizePresenter } from './presenters/CreatePrizePresenter';
|
||||
import { DeletePrizePresenter } from './presenters/DeletePrizePresenter';
|
||||
import { GetMembershipFeesPresenter } from './presenters/GetMembershipFeesPresenter';
|
||||
import { GetPaymentsPresenter } from './presenters/GetPaymentsPresenter';
|
||||
import { GetPrizesPresenter } from './presenters/GetPrizesPresenter';
|
||||
import { GetWalletPresenter } from './presenters/GetWalletPresenter';
|
||||
import { ProcessWalletTransactionPresenter } from './presenters/ProcessWalletTransactionPresenter';
|
||||
import { UpdateMemberPaymentPresenter } from './presenters/UpdateMemberPaymentPresenter';
|
||||
import { UpdatePaymentStatusPresenter } from './presenters/UpdatePaymentStatusPresenter';
|
||||
import { UpsertMembershipFeePresenter } from './presenters/UpsertMembershipFeePresenter';
|
||||
|
||||
// DTOs
|
||||
import type {
|
||||
AwardPrizeInput,
|
||||
@@ -90,18 +76,6 @@ export class PaymentsService {
|
||||
@Inject(GET_WALLET_USE_CASE_TOKEN) private readonly getWalletUseCase: GetWalletUseCase,
|
||||
@Inject(PROCESS_WALLET_TRANSACTION_USE_CASE_TOKEN) private readonly processWalletTransactionUseCase: ProcessWalletTransactionUseCase,
|
||||
@Inject(LOGGER_TOKEN) private readonly logger: Logger,
|
||||
private readonly getPaymentsPresenter: GetPaymentsPresenter,
|
||||
private readonly createPaymentPresenter: CreatePaymentPresenter,
|
||||
private readonly updatePaymentStatusPresenter: UpdatePaymentStatusPresenter,
|
||||
private readonly getMembershipFeesPresenter: GetMembershipFeesPresenter,
|
||||
private readonly upsertMembershipFeePresenter: UpsertMembershipFeePresenter,
|
||||
private readonly updateMemberPaymentPresenter: UpdateMemberPaymentPresenter,
|
||||
private readonly getPrizesPresenter: GetPrizesPresenter,
|
||||
private readonly createPrizePresenter: CreatePrizePresenter,
|
||||
private readonly awardPrizePresenter: AwardPrizePresenter,
|
||||
private readonly deletePrizePresenter: DeletePrizePresenter,
|
||||
private readonly getWalletPresenter: GetWalletPresenter,
|
||||
private readonly processWalletTransactionPresenter: ProcessWalletTransactionPresenter,
|
||||
) {}
|
||||
|
||||
async getPayments(query: GetPaymentsQuery): Promise<GetPaymentsOutput> {
|
||||
@@ -111,7 +85,11 @@ export class PaymentsService {
|
||||
if (result.isErr()) {
|
||||
throw new Error(result.unwrapErr().code ?? 'Failed to get payments');
|
||||
}
|
||||
return this.getPaymentsPresenter.getResponseModel();
|
||||
const value = result.value;
|
||||
if (!value) {
|
||||
throw new Error('Failed to get payments: no value returned');
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
async createPayment(input: CreatePaymentInput): Promise<CreatePaymentOutput> {
|
||||
@@ -121,7 +99,11 @@ export class PaymentsService {
|
||||
if (result.isErr()) {
|
||||
throw new Error(result.unwrapErr().code ?? 'Failed to create payment');
|
||||
}
|
||||
return this.createPaymentPresenter.getResponseModel();
|
||||
const value = result.value;
|
||||
if (!value) {
|
||||
throw new Error('Failed to create payment: no value returned');
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
async updatePaymentStatus(input: UpdatePaymentStatusInput): Promise<UpdatePaymentStatusOutput> {
|
||||
@@ -131,7 +113,11 @@ export class PaymentsService {
|
||||
if (result.isErr()) {
|
||||
throw new Error(result.unwrapErr().code ?? 'Failed to update payment status');
|
||||
}
|
||||
return this.updatePaymentStatusPresenter.getResponseModel();
|
||||
const value = result.value;
|
||||
if (!value) {
|
||||
throw new Error('Failed to update payment status: no value returned');
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
async getMembershipFees(query: GetMembershipFeesQuery): Promise<GetMembershipFeesOutput> {
|
||||
@@ -141,7 +127,11 @@ export class PaymentsService {
|
||||
if (result.isErr()) {
|
||||
throw new Error(result.unwrapErr().code ?? 'Failed to get membership fees');
|
||||
}
|
||||
return this.getMembershipFeesPresenter.viewModel;
|
||||
const value = result.value;
|
||||
if (!value) {
|
||||
throw new Error('Failed to get membership fees: no value returned');
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
async upsertMembershipFee(input: UpsertMembershipFeeInput): Promise<UpsertMembershipFeeOutput> {
|
||||
@@ -153,7 +143,11 @@ export class PaymentsService {
|
||||
// but we keep the check for consistency
|
||||
throw new Error('Failed to upsert membership fee');
|
||||
}
|
||||
return this.upsertMembershipFeePresenter.viewModel;
|
||||
const value = result.value;
|
||||
if (!value) {
|
||||
throw new Error('Failed to upsert membership fee: no value returned');
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
async updateMemberPayment(input: UpdateMemberPaymentInput): Promise<UpdateMemberPaymentOutput> {
|
||||
@@ -163,7 +157,11 @@ export class PaymentsService {
|
||||
if (result.isErr()) {
|
||||
throw new Error(result.unwrapErr().code ?? 'Failed to update member payment');
|
||||
}
|
||||
return this.updateMemberPaymentPresenter.viewModel;
|
||||
const value = result.value;
|
||||
if (!value) {
|
||||
throw new Error('Failed to update member payment: no value returned');
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
async getPrizes(query: GetPrizesQuery): Promise<GetPrizesOutput> {
|
||||
@@ -175,42 +173,89 @@ export class PaymentsService {
|
||||
if (query.seasonId !== undefined) {
|
||||
input.seasonId = query.seasonId;
|
||||
}
|
||||
await this.getPrizesUseCase.execute(input);
|
||||
return this.getPrizesPresenter.viewModel;
|
||||
const result = await this.getPrizesUseCase.execute(input);
|
||||
if (result.isErr()) {
|
||||
throw new Error('Failed to get prizes');
|
||||
}
|
||||
const value = result.value;
|
||||
if (!value) {
|
||||
throw new Error('Failed to get prizes: no value returned');
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
async createPrize(input: CreatePrizeInput): Promise<CreatePrizeOutput> {
|
||||
this.logger.debug('[PaymentsService] Creating prize', { input });
|
||||
|
||||
await this.createPrizeUseCase.execute(input);
|
||||
return this.createPrizePresenter.viewModel;
|
||||
const result = await this.createPrizeUseCase.execute(input);
|
||||
if (result.isErr()) {
|
||||
const err = result.unwrapErr();
|
||||
throw new Error(err.code ?? 'Failed to create prize');
|
||||
}
|
||||
const value = result.value;
|
||||
if (!value) {
|
||||
throw new Error('Failed to create prize: no value returned');
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
async awardPrize(input: AwardPrizeInput): Promise<AwardPrizeOutput> {
|
||||
this.logger.debug('[PaymentsService] Awarding prize', { input });
|
||||
|
||||
await this.awardPrizeUseCase.execute(input);
|
||||
return this.awardPrizePresenter.viewModel;
|
||||
const result = await this.awardPrizeUseCase.execute(input);
|
||||
if (result.isErr()) {
|
||||
const err = result.unwrapErr();
|
||||
throw new Error(err.code ?? 'Failed to award prize');
|
||||
}
|
||||
const value = result.value;
|
||||
if (!value) {
|
||||
throw new Error('Failed to award prize: no value returned');
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
async deletePrize(input: DeletePrizeInput): Promise<DeletePrizeOutput> {
|
||||
this.logger.debug('[PaymentsService] Deleting prize', { input });
|
||||
|
||||
await this.deletePrizeUseCase.execute(input);
|
||||
return this.deletePrizePresenter.viewModel;
|
||||
const result = await this.deletePrizeUseCase.execute(input);
|
||||
if (result.isErr()) {
|
||||
const err = result.unwrapErr();
|
||||
throw new Error(err.code ?? 'Failed to delete prize');
|
||||
}
|
||||
const value = result.value;
|
||||
if (!value) {
|
||||
throw new Error('Failed to delete prize: no value returned');
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
async getWallet(query: GetWalletQuery): Promise<GetWalletOutput> {
|
||||
this.logger.debug('[PaymentsService] Getting wallet', { query });
|
||||
|
||||
await this.getWalletUseCase.execute({ leagueId: query.leagueId! });
|
||||
return this.getWalletPresenter.viewModel;
|
||||
const result = await this.getWalletUseCase.execute({ leagueId: query.leagueId! });
|
||||
if (result.isErr()) {
|
||||
const err = result.unwrapErr();
|
||||
throw new Error(err.code ?? 'Failed to get wallet');
|
||||
}
|
||||
const value = result.value;
|
||||
if (!value) {
|
||||
throw new Error('Failed to get wallet: no value returned');
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
async processWalletTransaction(input: ProcessWalletTransactionInput): Promise<ProcessWalletTransactionOutput> {
|
||||
this.logger.debug('[PaymentsService] Processing wallet transaction', { input });
|
||||
|
||||
await this.processWalletTransactionUseCase.execute(input);
|
||||
return this.processWalletTransactionPresenter.viewModel;
|
||||
const result = await this.processWalletTransactionUseCase.execute(input);
|
||||
if (result.isErr()) {
|
||||
const err = result.unwrapErr();
|
||||
throw new Error(err.code ?? 'Failed to process wallet transaction');
|
||||
}
|
||||
const value = result.value;
|
||||
if (!value) {
|
||||
throw new Error('Failed to process wallet transaction: no value returned');
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@@ -27,17 +27,4 @@ export const CREATE_PRIZE_USE_CASE_TOKEN = 'CreatePrizeUseCase';
|
||||
export const AWARD_PRIZE_USE_CASE_TOKEN = 'AwardPrizeUseCase';
|
||||
export const DELETE_PRIZE_USE_CASE_TOKEN = 'DeletePrizeUseCase';
|
||||
export const GET_WALLET_USE_CASE_TOKEN = 'GetWalletUseCase';
|
||||
export const PROCESS_WALLET_TRANSACTION_USE_CASE_TOKEN = 'ProcessWalletTransactionUseCase';
|
||||
|
||||
export const GET_PAYMENTS_OUTPUT_PORT_TOKEN = 'GetPaymentsOutputPort_TOKEN';
|
||||
export const CREATE_PAYMENT_OUTPUT_PORT_TOKEN = 'CreatePaymentOutputPort_TOKEN';
|
||||
export const UPDATE_PAYMENT_STATUS_OUTPUT_PORT_TOKEN = 'UpdatePaymentStatusOutputPort_TOKEN';
|
||||
export const GET_MEMBERSHIP_FEES_OUTPUT_PORT_TOKEN = 'GetMembershipFeesOutputPort_TOKEN';
|
||||
export const UPSERT_MEMBERSHIP_FEE_OUTPUT_PORT_TOKEN = 'UpsertMembershipFeeOutputPort_TOKEN';
|
||||
export const UPDATE_MEMBER_PAYMENT_OUTPUT_PORT_TOKEN = 'UpdateMemberPaymentOutputPort_TOKEN';
|
||||
export const GET_PRIZES_OUTPUT_PORT_TOKEN = 'GetPrizesOutputPort_TOKEN';
|
||||
export const CREATE_PRIZE_OUTPUT_PORT_TOKEN = 'CreatePrizeOutputPort_TOKEN';
|
||||
export const AWARD_PRIZE_OUTPUT_PORT_TOKEN = 'AwardPrizeOutputPort_TOKEN';
|
||||
export const DELETE_PRIZE_OUTPUT_PORT_TOKEN = 'DeletePrizeOutputPort_TOKEN';
|
||||
export const GET_WALLET_OUTPUT_PORT_TOKEN = 'GetWalletOutputPort_TOKEN';
|
||||
export const PROCESS_WALLET_TRANSACTION_OUTPUT_PORT_TOKEN = 'ProcessWalletTransactionOutputPort_TOKEN';
|
||||
export const PROCESS_WALLET_TRANSACTION_USE_CASE_TOKEN = 'ProcessWalletTransactionUseCase';
|
||||
Reference in New Issue
Block a user