payment object
This commit is contained in:
parent
767201ec06
commit
d8ad43a56a
@ -1,5 +1,6 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { Inject, Injectable, Logger } from '@nestjs/common';
|
||||
import { HttpService } from '@nestjs/axios';
|
||||
import axios, { AxiosInstance, AxiosError } from 'axios';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
import {
|
||||
@ -10,27 +11,49 @@ import {
|
||||
ChargeResponse,
|
||||
} from './operator.adapter.interface';
|
||||
import { OrangeTransformer } from '../transformers/orange.transformer';
|
||||
|
||||
import {
|
||||
DEFAULT_ORANGE_CONFIG,
|
||||
COUNTRY_CODE_MAPPING,
|
||||
} from './orange.config';
|
||||
|
||||
import type { OrangeConfig } from './orange.config';
|
||||
|
||||
@Injectable()
|
||||
export class OrangeAdapter implements IOperatorAdapter {
|
||||
private readonly logger = new Logger(OrangeAdapter.name);
|
||||
private config: OrangeConfig;
|
||||
private baseUrl: string;
|
||||
private accessToken: string;
|
||||
private transformer: OrangeTransformer;
|
||||
private tokenExpiresAt: number = 0;
|
||||
private axiosInstance: AxiosInstance;
|
||||
|
||||
constructor(
|
||||
private readonly httpService: HttpService,
|
||||
private readonly configService: ConfigService,
|
||||
private readonly httpService: HttpService,
|
||||
@Inject('ORANGE_CONFIG')config: OrangeConfig,
|
||||
) {
|
||||
this.baseUrl = this.configService.get('ORANGE_API_URL') as string;
|
||||
this.accessToken = this.configService.get('ORANGE_ACCESS_TOKEN') as string;
|
||||
this.config = { ...DEFAULT_ORANGE_CONFIG, ...config } as OrangeConfig;
|
||||
this.axiosInstance = axios.create({
|
||||
baseURL: this.config.baseUrl,
|
||||
timeout: this.config.timeout,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Accept: '*/*',
|
||||
},
|
||||
});
|
||||
this.axiosInstance.interceptors.response.use(
|
||||
response => response,
|
||||
error => this.handleError(error)
|
||||
);
|
||||
|
||||
this.transformer = new OrangeTransformer();
|
||||
|
||||
}
|
||||
|
||||
async initializeAuth(params: AuthInitParams): Promise<AuthInitResponse> {
|
||||
const countryCode = this.getCountryCode(params.country);
|
||||
|
||||
const bizaoRequest = {
|
||||
const hubRequest = {
|
||||
challenge: {
|
||||
method: 'OTP-SMS-AUTH',
|
||||
country: countryCode,
|
||||
@ -64,7 +87,7 @@ export class OrangeAdapter implements IOperatorAdapter {
|
||||
const response = await firstValueFrom(
|
||||
this.httpService.post(
|
||||
`${this.baseUrl}/challenge/v1/challenges`,
|
||||
bizaoRequest,
|
||||
hubRequest,
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${this.accessToken}`,
|
||||
@ -87,7 +110,7 @@ export class OrangeAdapter implements IOperatorAdapter {
|
||||
}
|
||||
|
||||
async validateAuth(params: any): Promise<any> {
|
||||
const bizaoRequest = {
|
||||
const hubRequest = {
|
||||
challenge: {
|
||||
method: 'OTP-SMS-AUTH',
|
||||
country: params.country,
|
||||
@ -113,7 +136,7 @@ export class OrangeAdapter implements IOperatorAdapter {
|
||||
const response = await firstValueFrom(
|
||||
this.httpService.post(
|
||||
`${this.baseUrl}/challenge/v1/challenges/${params.challengeId}`,
|
||||
bizaoRequest,
|
||||
hubRequest,
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${this.accessToken}`,
|
||||
@ -139,7 +162,11 @@ export class OrangeAdapter implements IOperatorAdapter {
|
||||
}
|
||||
|
||||
async charge(params: ChargeParams): Promise<ChargeResponse> {
|
||||
const bizaoRequest = {
|
||||
this.logger.debug(
|
||||
`[orange adapter charge ]: ${JSON.stringify(params, null, 2)}`,
|
||||
);
|
||||
|
||||
const hubRequest = {
|
||||
amountTransaction: {
|
||||
endUserId: 'acr:OrangeAPIToken',
|
||||
paymentAmount: {
|
||||
@ -149,31 +176,38 @@ export class OrangeAdapter implements IOperatorAdapter {
|
||||
description: params.description,
|
||||
},
|
||||
chargingMetaData: {
|
||||
onBehalfOf: 'PaymentHub',
|
||||
onBehalfOf: 'PaymentHub', //from config todo
|
||||
purchaseCategoryCode: 'Service', //todo from config
|
||||
serviceId: 'BIZAO',
|
||||
},
|
||||
},
|
||||
transactionOperationStatus: 'Charged',
|
||||
referenceCode: params.reference,
|
||||
clientCorrelator: `${params.reference}-${Date.now()}`,
|
||||
clientCorrelator: `${params.reference}-${Date.now()}`, //uniquely identifies this create charge request.
|
||||
},
|
||||
};
|
||||
const token = await this.getAccessToken();
|
||||
this.logger.debug(
|
||||
`[requesting to ]: ${this.config.baseUrl}/payment/v1/acr%3AOrangeAPIToken/transactions/amount`,
|
||||
);
|
||||
|
||||
const response = await firstValueFrom(
|
||||
this.httpService.post(
|
||||
`${this.baseUrl}/payment/v1/acr%3AOrangeAPIToken/transactions/amount`,
|
||||
bizaoRequest,
|
||||
`${this.config.baseUrl}}/payment/v1/acr%3AOrangeAPIToken/transactions/amount`,
|
||||
hubRequest,
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${this.accessToken}`,
|
||||
'bizao-token': params.userToken,
|
||||
'bizao-alias': params.userAlias,
|
||||
Authorization: `Bearer ${token}`,
|
||||
'X-Orange-ISE2': params.userToken,
|
||||
'X-Orange-MCO': 'orange', //from country todo
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
this.logger.debug(`[response fromm orange ]: ${JSON.stringify(response.data, null, 2)}`,)
|
||||
|
||||
return this.transformer.transformChargeResponse(response.data);
|
||||
}
|
||||
|
||||
@ -257,4 +291,53 @@ export class OrangeAdapter implements IOperatorAdapter {
|
||||
};
|
||||
return senderMap[country];
|
||||
}
|
||||
|
||||
private async getAccessToken(): Promise<string> {
|
||||
// Vérifier si le token est encore valide (avec une marge de 60 secondes)
|
||||
if (this.accessToken && Date.now() < this.tokenExpiresAt - 60000) {
|
||||
return this.accessToken;
|
||||
}
|
||||
|
||||
try {
|
||||
const auth = Buffer.from(
|
||||
`${this.config.clientId}:${this.config.clientSecret}`,
|
||||
).toString('base64');
|
||||
|
||||
//this.logger.debug( `request to get acces token , ${this.config.baseUrl}${this.config.tokenEndpoint}`)
|
||||
|
||||
const response = await axios.post(
|
||||
`${this.config.baseUrl}${this.config.tokenEndpoint}`,
|
||||
'grant_type=client_credentials',
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Basic ${auth}`,
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
Accept: '*/*',
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
this.accessToken = response.data.access_token;
|
||||
const expiresIn = response.data.expires_in || 3600;
|
||||
this.tokenExpiresAt = Date.now() + expiresIn * 1000;
|
||||
|
||||
return this.accessToken as string;
|
||||
} catch (error) {
|
||||
throw new Error(`Failed to obtain Orange access token: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private handleError(error: AxiosError): never {
|
||||
if (error.response) {
|
||||
const data = error.response.data as any;
|
||||
throw new Error(
|
||||
`Orange API Error: ${data?.error?.message || error.message} (Code: ${data?.error?.code || error.response.status})`
|
||||
);
|
||||
} else if (error.request) {
|
||||
throw new Error(`No response from Orange API: ${error.message}`);
|
||||
} else {
|
||||
throw new Error(`Request error: ${error.message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
46
src/modules/operators/adapters/orange.config.ts
Normal file
46
src/modules/operators/adapters/orange.config.ts
Normal file
@ -0,0 +1,46 @@
|
||||
export interface OrangeConfig {
|
||||
baseUrl: string;
|
||||
partnerId: string;
|
||||
clientId: string;
|
||||
clientSecret: string;
|
||||
defaultService: string;
|
||||
defaultOtpLength: number;
|
||||
defaultSenderName: string;
|
||||
defaultOtpMessage: string;
|
||||
tokenEndpoint: string;
|
||||
challengeEndpoint: string;
|
||||
timeout: number;
|
||||
}
|
||||
|
||||
export const DEFAULT_ORANGE_CONFIG: Partial<OrangeConfig> = {
|
||||
defaultOtpLength: 4,
|
||||
defaultOtpMessage: 'To confirm your purchase please enter the code %OTP%',
|
||||
tokenEndpoint: '/oauth/v3/token',
|
||||
challengeEndpoint: '/challenge/v1/challenges',
|
||||
timeout: 30000, // 30 secondes
|
||||
};
|
||||
|
||||
/**
|
||||
* Mapping des codes pays ISO vers les codes Orange
|
||||
*/
|
||||
export const COUNTRY_CODE_MAPPING: Record<string, string> = {
|
||||
'SN': 'SEN', // Sénégal
|
||||
'CI': 'CIV', // Côte d'Ivoire
|
||||
'CM': 'CMR', // Cameroun
|
||||
'CD': 'COD', // RD Congo
|
||||
'BF': 'BFA', // Burkina Faso
|
||||
'TN': 'TUN', // Tunisie
|
||||
'ML': 'MLI', // Mali
|
||||
'GN': 'GIN', // Guinée
|
||||
'NE': 'NER', // Niger
|
||||
'MG': 'MDG', // Madagascar
|
||||
};
|
||||
|
||||
/**
|
||||
* Mapping des méthodes OTP génériques vers Orange
|
||||
*/
|
||||
export const OTP_METHOD_MAPPING: Record<string, string> = {
|
||||
'SMS': 'OTP-SMS-AUTH',
|
||||
'USSD': 'OTP-USSD-AUTH',
|
||||
'IVR': 'OTP-IVR-AUTH',
|
||||
};
|
||||
@ -8,6 +8,8 @@ import { MTNAdapter } from './adapters/mtn.adapter';
|
||||
import { OrangeTransformer } from './transformers/orange.transformer';
|
||||
import { MTNTransformer } from './transformers/mtn.transformer';
|
||||
import { PrismaService } from '../../shared/services/prisma.service';
|
||||
import { OrangeConfig } from './adapters/orange.config';
|
||||
import { ConfigModule, ConfigService } from '@nestjs/config';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
@ -15,9 +17,32 @@ import { PrismaService } from '../../shared/services/prisma.service';
|
||||
timeout: 30000,
|
||||
maxRedirects: 3,
|
||||
}),
|
||||
ConfigModule
|
||||
|
||||
],
|
||||
controllers: [OperatorsController],
|
||||
providers: [
|
||||
{
|
||||
provide: 'ORANGE_CONFIG',
|
||||
useFactory: (configService: ConfigService): OrangeConfig => ({
|
||||
baseUrl: configService.get<string>('ORANGE_BASE_URL', 'https://webhook.site/69ce9344-f87b-421a-a494-c59eca7c54ce'),
|
||||
//tokenUrl: configService.get<string>('ORANGE_BASE_URL', 'https://webhook.site/69ce9344-f87b-421a-a494-c59eca7c54ce'),
|
||||
partnerId: configService.get<string>('ORANGE_PARTNER_ID', 'PDKSUB'),
|
||||
clientId: configService.get<string>('ORANGE_CLIENT_ID', 'admin'),
|
||||
clientSecret: configService.get<string>('ORANGE_CLIENT_SECRET', 'admin'),
|
||||
defaultService: configService.get<string>('ORANGE_DEFAULT_SERVICE', 'DCB_SERVICE'),
|
||||
defaultOtpLength: configService.get<number>('ORANGE_DEFAULT_OTP_LENGTH', 4),
|
||||
defaultSenderName: configService.get<string>('ORANGE_DEFAULT_SENDER_NAME', 'OTP'),
|
||||
defaultOtpMessage: configService.get<string>(
|
||||
'ORANGE_DEFAULT_OTP_MESSAGE',
|
||||
'To confirm your purchase please enter the code %OTP%'
|
||||
),
|
||||
tokenEndpoint: '/oauth/v3/token',
|
||||
challengeEndpoint: '/challenge/v1/challenges',
|
||||
timeout: configService.get<number>('ORANGE_TIMEOUT', 30000),
|
||||
}),
|
||||
inject: [ConfigService],
|
||||
},
|
||||
OperatorsService,
|
||||
OperatorAdapterFactory,
|
||||
OrangeAdapter,
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
import { BadRequestException, NotFoundException } from "@nestjs/common";
|
||||
import { BadRequestException, Injectable, NotFoundException } from "@nestjs/common";
|
||||
import { ConfigService } from "@nestjs/config";
|
||||
import { PrismaService } from "src/shared/services/prisma.service";
|
||||
import { OperatorAdapterFactory } from "./adapters/operator-adapter.factory";
|
||||
import { HttpService } from "@nestjs/axios";
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
//todo tomaj
|
||||
@Injectable()
|
||||
export class OperatorsService{
|
||||
|
||||
constructor(
|
||||
@ -126,12 +127,6 @@ export class OperatorsService{
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private getCountryName(code: string): string {
|
||||
const countries = {
|
||||
|
||||
@ -36,7 +36,7 @@ export class ChargeDto {
|
||||
@ApiProperty({ required: false, description: 'Subscription ID if recurring' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
subscriptionId?: string;
|
||||
subscriptionId?: number;
|
||||
|
||||
@ApiProperty({ required: false, description: 'Callback URL for notifications' })
|
||||
@IsOptional()
|
||||
@ -49,7 +49,15 @@ export class ChargeDto {
|
||||
|
||||
@ApiProperty({ required: false, description: 'partnerId ' })
|
||||
@IsOptional()
|
||||
partnerId: string;
|
||||
partnerId: number;
|
||||
|
||||
@ApiProperty({ required: false, description: 'country ' })
|
||||
@IsOptional()
|
||||
country: string;
|
||||
|
||||
@ApiProperty({ required: false, description: 'operator ' })
|
||||
@IsOptional()
|
||||
operator: string;
|
||||
}
|
||||
|
||||
export class RefundDto {
|
||||
|
||||
@ -10,6 +10,9 @@ import {
|
||||
HttpCode,
|
||||
HttpStatus,
|
||||
BadRequestException,
|
||||
Headers,
|
||||
Logger,
|
||||
ParseIntPipe,
|
||||
} from '@nestjs/common';
|
||||
import {
|
||||
ApiTags,
|
||||
@ -32,10 +35,12 @@ import { ApiKeyGuard } from '../../common/guards/api-key.guard';
|
||||
@ApiTags('payments')
|
||||
@Controller('payments')
|
||||
export class PaymentsController {
|
||||
private readonly logger = new Logger(PaymentsController.name);
|
||||
|
||||
constructor(private readonly paymentsService: PaymentsService) {}
|
||||
|
||||
@Post('charge')
|
||||
@UseGuards(JwtAuthGuard)
|
||||
//@UseGuards(JwtAuthGuard)
|
||||
@ApiBearerAuth()
|
||||
@HttpCode(HttpStatus.CREATED)
|
||||
@ApiOperation({ summary: 'Create a new charge' })
|
||||
@ -46,10 +51,18 @@ export class PaymentsController {
|
||||
})
|
||||
@ApiResponse({ status: 400, description: 'Bad request' })
|
||||
@ApiResponse({ status: 401, description: 'Unauthorized' })
|
||||
async createCharge(@Request() req, @Body() chargeDto: ChargeDto) {
|
||||
async createCharge(
|
||||
@Headers('X-Merchant-ID') merchantId: string,
|
||||
@Headers('X-COUNTRY') coutnry: string,
|
||||
@Headers('X-OPERATOR') operator: string,
|
||||
@Request() req, @Body() chargeDto: ChargeDto) {
|
||||
this.logger.debug(
|
||||
`[request charge to hub ]: ${JSON.stringify(chargeDto, null, 2)}`,
|
||||
)
|
||||
return this.paymentsService.createCharge({
|
||||
...chargeDto,
|
||||
partnerId: req.user.partnerId,
|
||||
...chargeDto,
|
||||
country: coutnry,
|
||||
operator: operator,
|
||||
});
|
||||
}
|
||||
|
||||
@ -92,7 +105,7 @@ export class PaymentsController {
|
||||
|
||||
|
||||
@Get('reference/:reference')
|
||||
@UseGuards(JwtAuthGuard)
|
||||
//@UseGuards(JwtAuthGuard)
|
||||
@ApiBearerAuth()
|
||||
@ApiOperation({ summary: 'Get payment by reference' })
|
||||
@ApiResponse({
|
||||
@ -111,7 +124,7 @@ export class PaymentsController {
|
||||
}
|
||||
|
||||
@Post(':paymentId/retry')
|
||||
@UseGuards(JwtAuthGuard)
|
||||
// @UseGuards(JwtAuthGuard)
|
||||
@ApiBearerAuth()
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@ApiOperation({ summary: 'Retry a failed payment' })
|
||||
@ -130,7 +143,7 @@ export class PaymentsController {
|
||||
|
||||
|
||||
@Post('validate')
|
||||
@UseGuards(JwtAuthGuard)
|
||||
//@UseGuards(JwtAuthGuard)
|
||||
@ApiBearerAuth()
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@ApiOperation({ summary: 'Validate payment before processing' })
|
||||
@ -143,7 +156,7 @@ export class PaymentsController {
|
||||
|
||||
// Webhook endpoints
|
||||
@Post('webhook/callback')
|
||||
@UseGuards(ApiKeyGuard)
|
||||
//@UseGuards(ApiKeyGuard)
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@ApiOperation({ summary: 'Webhook callback for payment updates' })
|
||||
async handleWebhook(@Request() req, @Body() payload: any) {
|
||||
|
||||
@ -6,6 +6,8 @@ import { PaymentProcessor } from './processors/payment.processor';
|
||||
import { WebhookService } from './services/webhook.service';
|
||||
import { PrismaService } from '../../shared/services/prisma.service';
|
||||
import { OperatorsModule } from '../operators/operators.module';
|
||||
import { Subscription } from 'rxjs';
|
||||
import { SubscriptionsModule } from '../subscriptions/subscriptions.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
@ -16,6 +18,8 @@ import { OperatorsModule } from '../operators/operators.module';
|
||||
name: 'webhooks',
|
||||
}),
|
||||
OperatorsModule,
|
||||
SubscriptionsModule,
|
||||
|
||||
],
|
||||
controllers: [PaymentsController],
|
||||
providers: [PaymentsService, PaymentProcessor, WebhookService, PrismaService],
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { Injectable, BadRequestException } from '@nestjs/common';
|
||||
import { Injectable, BadRequestException, Logger } from '@nestjs/common';
|
||||
import { OperatorsService } from '../operators/operators.service';
|
||||
import { PrismaService } from '../../shared/services/prisma.service';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
@ -8,6 +8,7 @@ import { PaymentType, TransactionStatus } from 'generated/prisma';
|
||||
|
||||
@Injectable()
|
||||
export class PaymentsService {
|
||||
private readonly logger = new Logger(PaymentsService.name);
|
||||
handleWebhook(arg0: { partnerId: any; event: any; payload: any; signature: any; }) {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
@ -33,7 +34,7 @@ export class PaymentsService {
|
||||
) {}
|
||||
|
||||
async createCharge(chargeDto: ChargeDto) {
|
||||
// Récupérer les informations de l'utilisateur
|
||||
/* Récupérer les informations de l'utilisateur
|
||||
const user = await this.prisma.user.findUnique({
|
||||
where: { userToken: chargeDto.userToken },
|
||||
// include: { operator: true },
|
||||
@ -42,12 +43,13 @@ export class PaymentsService {
|
||||
if (!user) {
|
||||
throw new BadRequestException('Invalid user token');
|
||||
}
|
||||
*/
|
||||
|
||||
// Créer la transaction dans la base
|
||||
const payment = await this.prisma.payment.create({
|
||||
|
||||
data: {
|
||||
merchantPartnerId:1, // À remplacer par le bon partnerId
|
||||
merchantPartnerId:chargeDto.partnerId , // À remplacer par le bon partnerId
|
||||
customerId: 1, // todo À remplacer par user.id
|
||||
amount: chargeDto.amount,
|
||||
currency: chargeDto.currency,
|
||||
@ -61,21 +63,29 @@ export class PaymentsService {
|
||||
|
||||
try {
|
||||
// Router vers le bon opérateur
|
||||
this.logger.debug(
|
||||
`[getting adaptator for ]: ${chargeDto.operator}_${chargeDto.country} `)
|
||||
const adapter = this.operatorsService.getAdapter(
|
||||
'user.operator.code',
|
||||
user.country,
|
||||
chargeDto.operator,
|
||||
chargeDto.country,
|
||||
);
|
||||
|
||||
this.logger.debug(`Processing payment ${payment.id} through operator adapter ${adapter.constructor.name}`);
|
||||
|
||||
const chargeParams = {
|
||||
userToken: user.userToken,
|
||||
userAlias: user.userAlias,
|
||||
userToken: chargeDto.userToken,
|
||||
userAlias: chargeDto.userToken,//todo make alias in contrat
|
||||
amount: chargeDto.amount,
|
||||
currency: chargeDto.currency,
|
||||
description: chargeDto.description,
|
||||
reference: 'payment.reference,',//todo À remplacer par payment.reference
|
||||
subscriptionId: chargeDto.subscriptionId,
|
||||
reference: chargeDto.reference +'',//todo make reference in contrat
|
||||
};
|
||||
|
||||
const result = await adapter.charge(chargeParams);
|
||||
this.logger.debug(`result frm adaptaor ${result} for payment ${payment.id}`);
|
||||
|
||||
|
||||
|
||||
// Mettre à jour le paiement
|
||||
const updatedPayment = await this.prisma.payment.update({
|
||||
@ -104,7 +114,7 @@ export class PaymentsService {
|
||||
return updatedPayment;
|
||||
} catch (error) {
|
||||
// En cas d'erreur, marquer comme échoué
|
||||
await this.prisma.payment.update({
|
||||
const resultFinal= await this.prisma.payment.update({
|
||||
where: { id: payment.id },
|
||||
data: {
|
||||
status: TransactionStatus.FAILED,
|
||||
@ -112,7 +122,7 @@ export class PaymentsService {
|
||||
},
|
||||
});
|
||||
|
||||
throw error;
|
||||
return { ...resultFinal };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -11,6 +11,7 @@ import {
|
||||
UseGuards,
|
||||
Request,
|
||||
Logger,
|
||||
ParseIntPipe,
|
||||
} from '@nestjs/common';
|
||||
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
|
||||
import { SubscriptionsService } from './subscriptions.service';
|
||||
@ -37,12 +38,24 @@ export class SubscriptionsController {
|
||||
return this.subscriptionsService.create(merchantId, dto);
|
||||
}
|
||||
|
||||
@Get('/')
|
||||
@ApiOperation({ summary: 'Get subscription list' })
|
||||
async getAll(@Request() req) {
|
||||
return this.subscriptionsService.findAll();
|
||||
}
|
||||
|
||||
@Get('merchant/:merchantId')
|
||||
@ApiOperation({ summary: 'Get subscription list by merchant' })
|
||||
async getAllByMErchant(@Request() req, @Param('merchantId', ParseIntPipe) merchantId: number) {
|
||||
return this.subscriptionsService.findAllByMerchant(merchantId);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Get(':id')
|
||||
@ApiOperation({ summary: 'Get subscription details' })
|
||||
async get(@Request() req, @Param('id') id: string) {
|
||||
return this.subscriptionsService.get(id, req.user.partnerId);
|
||||
async get(@Request() req, @Param('id') id: number) {
|
||||
return this.subscriptionsService.get(id);
|
||||
}
|
||||
|
||||
|
||||
@ -56,9 +69,5 @@ export class SubscriptionsController {
|
||||
return this.subscriptionsService.cancel(id, req.user.partnerId, reason);
|
||||
}
|
||||
|
||||
@Get(':id/invoices')
|
||||
@ApiOperation({ summary: 'Get subscription invoices' })
|
||||
async getInvoices(@Request() req, @Param('id') id: string) {
|
||||
return this.subscriptionsService.getInvoices(id, req.user.partnerId);
|
||||
}
|
||||
|
||||
}
|
||||
@ -18,7 +18,7 @@ import { PaymentsModule } from '../payments/payments.module';
|
||||
BullModule.registerQueue({
|
||||
name: 'billing',
|
||||
}),
|
||||
PaymentsModule,
|
||||
// PaymentsModule,
|
||||
],
|
||||
controllers: [SubscriptionsController],
|
||||
providers: [
|
||||
|
||||
@ -4,23 +4,54 @@ import bull from 'bull';
|
||||
import { PrismaService } from '../../shared/services/prisma.service';
|
||||
import { PaymentsService } from '../payments/payments.service';
|
||||
import { CreateSubscriptionDto, UpdateSubscriptionDto } from './dto/subscription.dto';
|
||||
import { Subscription } from 'generated/prisma';
|
||||
//import { SubscriptionStatus } from '@prisma/client';
|
||||
//import { SubscriptionStatus, Prisma } from '@prisma/client';
|
||||
|
||||
@Injectable()
|
||||
export class SubscriptionsService {
|
||||
get(id: string, partnerId: any) {
|
||||
throw new Error('Method not implemented.');
|
||||
async get(id: number):Promise<any> {
|
||||
const service = await this.prisma.subscription.findUnique({
|
||||
where: { id },
|
||||
|
||||
});
|
||||
|
||||
if (!service) {
|
||||
throw new NotFoundException(`Service with ID ${id} not found`);
|
||||
}
|
||||
|
||||
return service;
|
||||
}
|
||||
list(arg0: { partnerId: any; status: string | undefined; userId: string | undefined; page: number; limit: number; }) {
|
||||
throw new Error('Method not implemented.');
|
||||
|
||||
async findAllByMerchant(merchantId: number): Promise<Subscription[]> {
|
||||
// Check if merchant exists
|
||||
|
||||
return this.prisma.subscription.findMany({
|
||||
where: { merchantPartnerId: merchantId },
|
||||
|
||||
orderBy: {
|
||||
createdAt: 'desc',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async findAll(): Promise<Subscription[]> {
|
||||
// Check if merchant exists
|
||||
|
||||
return this.prisma.subscription.findMany({
|
||||
// where: { merchantPartnerId: merchantId },
|
||||
|
||||
orderBy: {
|
||||
createdAt: 'desc',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
getInvoices(id: string, partnerId: any) {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
constructor(
|
||||
private readonly prisma: PrismaService,
|
||||
private readonly paymentsService: PaymentsService,
|
||||
private readonly prisma: PrismaService,
|
||||
@InjectQueue('subscriptions') private subscriptionQueue: bull.Queue,
|
||||
@InjectQueue('billing') private billingQueue: bull.Queue,
|
||||
) {}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user