Skip to content

Commit

Permalink
Remove Callback module, service, and controller; add callback handlin…
Browse files Browse the repository at this point in the history
…g in MpesaExpressController with Redis integration for payment status updates
  • Loading branch information
Domains18 committed Oct 25, 2024
1 parent c3b0ba1 commit 8be9efd
Show file tree
Hide file tree
Showing 7 changed files with 64 additions and 6,445 deletions.
6,421 changes: 0 additions & 6,421 deletions pnpm-lock.yaml

This file was deleted.

2 changes: 0 additions & 2 deletions src/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
import { Module, MiddlewareConsumer, NestModule } from '@nestjs/common';
import { LoggerMiddleware } from './logger/logger.middleware';
import { MpesaExpressModule } from './mpesa-express/mpesa-express.module';
import { CallbackModule } from './callback/callback.module';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { RedisModule } from '@liaoliaots/nestjs-redis';


@Module({
imports: [MpesaExpressModule,
CallbackModule,
ConfigModule.forRoot({ isGlobal: true }),
RedisModule.forRootAsync({
useFactory: (configService: ConfigService) => configService.get('REDIS_URL'),
Expand Down
7 changes: 0 additions & 7 deletions src/callback/callback.controller.ts

This file was deleted.

9 changes: 0 additions & 9 deletions src/callback/callback.module.ts

This file was deleted.

4 changes: 0 additions & 4 deletions src/callback/callback.service.ts

This file was deleted.

40 changes: 38 additions & 2 deletions src/mpesa-express/mpesa-express.controller.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,49 @@
import { Controller, Get, Post, Body, Patch, Param, Delete } from '@nestjs/common';
import { Controller, Get, Post, Body, Patch, Param, Delete, Logger } from '@nestjs/common';
import { MpesaExpressService } from './mpesa-express.service';
import { CreateMpesaExpressDto } from './dto/create-mpesa-express.dto';
import Redis from 'ioredis';
import { RedisService } from '@liaoliaots/nestjs-redis';

@Controller('mpesa')
export class MpesaExpressController {
constructor(private readonly mpesaExpressService: MpesaExpressService) {}
private readonly redis: Redis | null;
private logger = new Logger('MpesaExpressController');
constructor(
private mpesaExpressService: MpesaExpressService,
private readonly redisService: RedisService
) {}

@Post('/stkpush')
create(@Body() createMpesaExpressDto: CreateMpesaExpressDto) {
return this.mpesaExpressService.stkPush(createMpesaExpressDto);
}

@Post('/callback')
async handleCallback(@Body() callBackData: any) {
this.logger.debug(`Callback data: ${JSON.stringify(callBackData)}`);
const redisClient = this.redisService.getOrThrow();

const { Body: { stkCallback } } = callBackData;

const { MerchantRequestID, CheckoutRequestID, ResultCode, ResultDesc } = stkCallback;

const payment = await redisClient.get(MerchantRequestID);
// if (!payment || payment === null || payment === undefined) {
// this.logger.error('Payment not found, was it cached?');
// }

if (payment) {
this.logger.debug(`Payment found: ${payment}`);
const parsedData = JSON.parse(payment);

if(ResultCode === 0) {
parsedData.status = 'COMPLETED';
} else {
parsedData.status = 'FAILED';
}
await redisClient.set(MerchantRequestID, JSON.stringify(parsedData));
} else {
this.logger.error('Payment not found, was it cached?');
}
}
}
26 changes: 26 additions & 0 deletions src/mpesa-express/mpesa-express.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export class MpesaExpressService {

private readonly redis: Redis | null;
private logger = new Logger('MpesaExpressService');


private async generateTimestamp(): Promise<string> {
const date = new Date();
Expand All @@ -27,8 +28,33 @@ export class MpesaExpressService {
('0' + date.getSeconds()).slice(-2);
}


async validateDto(createMpesaExpressDto: CreateMpesaExpressDto): Promise<void> {
const obeysPhoneNum = createMpesaExpressDto.phoneNum.match(/^2547\d{8}$/);
if (!obeysPhoneNum) {
this.logger.warn("The phone number does not obey the format");
throw new HttpException('Phone number must be in the format 2547XXXXXXXX"', 400);
}

const obeysAccountRef = createMpesaExpressDto.accountRef.match(/^[a-zA-Z0-9]{1,12}$/);
if (!obeysAccountRef) {
this.logger.warn("The account reference does not obey the format");
throw new HttpException('Account reference must be alphanumeric and not more than 12 characters', 400);
}

const obeysAmount = createMpesaExpressDto.amount > 0;
if (!obeysAmount) {
this.logger.warn("The amount does not obey the format");
throw new HttpException('Amount must be greater than 0', 400);
}

return;
}

async stkPush(createMpesaExpressDto: CreateMpesaExpressDto): Promise<void> {

await this.validateDto(createMpesaExpressDto);

const shortcode = "174379";
const passkey = this.configService.get('PASS_KEY');

Expand Down

0 comments on commit 8be9efd

Please sign in to comment.