Skip to content

Commit

Permalink
ADD payments (#47)
Browse files Browse the repository at this point in the history
* ADD Payments

* ADD payments

* UPDATE refund result

* fix : conflict

---------

Co-authored-by: STEVE <ymyd.steve@gmail.com>
  • Loading branch information
hayasha and STEVE authored Jul 14, 2023
1 parent b7d6aec commit 1cb8950
Show file tree
Hide file tree
Showing 33 changed files with 785 additions and 111 deletions.
2 changes: 1 addition & 1 deletion vet_nest/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ CMD ["yarn", "test"]


FROM base as prod
CMD [ "npm", "run", "start:prod" ]
CMD [ "npm", "run", "start:dev" ]

# 개발 환경에서는 start:dev로 주석을 해제
# 배포 환경에서는 start:pod을 주석 해제
Expand Down
12 changes: 6 additions & 6 deletions vet_nest/config/config.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { User } from '../src/users/entity/users.entity';
import { Reservation } from './../src/reservations/entity/reservation.entity';
import { Pet } from '../src/pets/entity/pet.entity';
import { Vet } from '../src/vets/entity/vet.entity';
import { User } from '../src/users/entity/users.entity';
import { TimeSlot } from '../src/vets/entity/timeslot.entity';
import { Reservation } from '../src/reservations/entity/reservation.entity';
import { Payment } from '../src/reservations/entity/payment.entity';
import * as dotenv from 'dotenv';
dotenv.config({ path: './../.env' });
Expand All @@ -11,9 +11,10 @@ export default () => ({
MODE: process.env.REACT_APP_ENV,
DB: {
type: process.env.DB_TYPE === 'mariadb' ? 'mariadb' : 'mysql',
host: process.env.REACT_APP_ENV === 'local'
? process.env.DB_HOST
: process.env.DB_HOST,
host:
process.env.REACT_APP_ENV === 'local'
? process.env.DB_HOST
: process.env.DB_HOST,
port: parseInt(process.env.DB_PORT),
username: process.env.DB_USERNAME,
password: process.env.DB_PASSWORD,
Expand Down Expand Up @@ -45,4 +46,3 @@ export default () => ({
AZURE_INSTRUMENT_KEY: process.env.AZURE_INSTRUMENT_KEY,
},
});

4 changes: 3 additions & 1 deletion vet_nest/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,10 @@
"test:e2e": "jest --config ./test/jest-e2e.json"
},
"dependencies": {
"@nestjs/axios": "^3.0.0",
"@nestjs/common": "^10.0.5",
"@automapper/core": "^8.7.7",
"@automapper/nestjs": "^8.7.7",
"@nestjs/common": "^9.2.1",
"@nestjs/config": "^2.2.0",
"@nestjs/core": "^9.2.1",
"@nestjs/jwt": "^10.1.0",
Expand All @@ -40,6 +41,7 @@
"@types/redis": "^4.0.11",
"@types/winston": "^2.4.4",
"@willsoto/nestjs-prometheus": "^5.2.0",
"axios": "^1.4.0",
"applicationinsights": "^2.7.0",
"body-parser": "^1.20.1",
"class-transformer": "^0.5.1",
Expand Down
4 changes: 4 additions & 0 deletions vet_nest/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ import { UsersRepository } from '../users/repository/users.repository';
import { JwtService } from '@nestjs/jwt';
import { ExceptionsService } from '../exceptions/exceptions.service';
import { currentModeProviders } from './providers/currentMode.provider';
import { PaymentsRepository } from '../payments/repository/payments.repository';
import { HttpModule } from '@nestjs/axios';

@Module({
imports: [
Expand Down Expand Up @@ -61,6 +63,7 @@ import { currentModeProviders } from './providers/currentMode.provider';
PaymentsModule,
UsersModule,
ExceptionsModule,
HttpModule,
],
controllers: [
AppController,
Expand All @@ -76,6 +79,7 @@ import { currentModeProviders } from './providers/currentMode.provider';
PetsRepository,
VetsService,
PaymentsService,
PaymentsRepository,
UsersService,
DiagnosisService,
UsersRepository,
Expand Down
2 changes: 1 addition & 1 deletion vet_nest/src/database/typeorm-maria-testing.module.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { DataSource, DataSourceOptions } from 'typeorm';
import { Payment } from './../reservations/entity/payment.entity';
import { Payment } from '../payments/entity/payments.entity';
import { Reservation } from './../reservations/entity/reservation.entity';
import { TypeOrmModule } from '@nestjs/typeorm';
import { User, UserLevel, UserStatus } from '../users/entity/users.entity';
Expand Down
1 change: 0 additions & 1 deletion vet_nest/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import { AppModule } from './app/app.module';
import dotenv = require('dotenv');
import { AllExceptionsFilter } from './diagnosis/exceptions/all-http-exception.filter';
dotenv.config();
import { AllExceptionsFilter } from './diagnosis/exceptions/all-http-exception.filter';


async function nestFactoryCreate() {
Expand Down
80 changes: 80 additions & 0 deletions vet_nest/src/payments/__test__/payments.controller.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { Test, TestingModule } from '@nestjs/testing';
import { HttpStatus, INestApplication } from '@nestjs/common';
import * as request from 'supertest';

const LOCAL_HOST = 'http://localhost:3001';

describe('CREATE PAYMENT', () => {
let app: INestApplication;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({}).compile();

app = module.createNestApplication();
await app.init;
});

test('POST /payments creates a new payment', () => {
const createPaymentDto = {
reservationId: 1,
amount: 100,
};

request(LOCAL_HOST)
.post('/payments')
.send(createPaymentDto)
.then((res: request.Response) => {
expect(res.statusCode).toEqual(HttpStatus.CREATED);
});
});

test('POST /payments fails with invalid data', () => {
const invalidDto = {
amount: 100,
};

request(LOCAL_HOST)
.post('/payments')
.send(invalidDto)
.then((res: request.Response) => {
expect(res.statusCode).toEqual(HttpStatus.BAD_REQUEST);
expect(res.body.message).toEqual('invalid data');
});
});
});

describe('REFUND PAYMENT', () => {
let app: INestApplication;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({}).compile();

app = module.createNestApplication();
await app.init;
});

test('POST /payments/refund refunds', () => {
const refundPaymentDto = { reservationId: 1 };

request(LOCAL_HOST)
.post('/payments/refund')
.send(refundPaymentDto)
.then((res: request.Response) => {
expect(res.statusCode).toEqual(HttpStatus.OK);
});
});

test('POST /payments/refund fails with invalid data', () => {
const invalidDto = {
amount: 100,
};

request(LOCAL_HOST)
.post('/payments/refund')
.send(invalidDto)
.then((res: request.Response) => {
expect(res.statusCode).toEqual(HttpStatus.BAD_REQUEST);
expect(res.body.message).toEqual('paymentId is required');
});
});
});
152 changes: 152 additions & 0 deletions vet_nest/src/payments/__test__/payments.service.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
import { Test, TestingModule } from '@nestjs/testing';
import { PaymentsService } from '../payments.service';
import { PaymentsRepositoryMock } from '../repository/payments.repository.mock';
import { PaymentsRepository } from '../repository/payments.repository';
import { HttpService, HttpModule } from '@nestjs/axios';
import { of } from 'rxjs';
import { AxiosResponse } from 'axios';

// 여기만 하면 된다..
describe('CREATE PAYMENT', () => {
let service: PaymentsService;
let httpService: HttpService;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
imports: [HttpModule],
providers: [
{
provide: PaymentsRepository,
useClass: PaymentsRepositoryMock,
},
PaymentsService,
{
provide: HttpService,
useFactory: () => ({
post: jest.fn(),
}),
},
],
}).compile();
service = module.get<PaymentsService>(PaymentsService);
httpService = module.get<HttpService>(HttpService);
});

test('invalid data fails', async () => {
const createPaymentDto = {
reservationId: null,
amount: 100,
};

try {
await service.create(createPaymentDto);
} catch (error) {
expect(error).toBeInstanceOf(Error);
}

expect.assertions(1);
});

test('duplicate payment fails', async () => {
const createPaymentDto = {
reservationId: 2,
amount: 50,
};

try {
await service.create(createPaymentDto);
} catch (error) {
expect(error).toBeInstanceOf(Error);
}

expect.assertions(1);
});

test('create passes with valid payment data', async () => {
const createPaymentDto = {
reservationId: 1,
amount: 200,
};
const createdPayment = {
reservationId: 1,
paymentId: 1,
appId: 'PG1',
amount: 200,
status: 'done',
};

jest.spyOn(httpService, 'post').mockImplementation(() => {
const test = of({
data: {
result: { code: 200, appId: 'PG1' },
},
status: 200,
statusText: 'OK',
headers: {},
config: {},
} as AxiosResponse<any>);

console.log(typeof test);
console.log(test);
});

const result = await service.create(createPaymentDto);

expect(result).toEqual(createdPayment);
});
});

describe('REFUND PAYMENT', () => {
let service: PaymentsService;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
{
provide: PaymentsRepository,
useClass: PaymentsRepositoryMock,
},
PaymentsService,
],
}).compile();

service = module.get<PaymentsService>(PaymentsService);
});

test('refund fails when paymentId is missing', async () => {
const cancelPaymentDto = { paymentId: null };

try {
await service.refund(cancelPaymentDto);
} catch (error) {
expect(error).toBeInstanceOf(Error);
}

expect.assertions(1);
});

test('refund fails when payment is not done', async () => {
const cancelPaymentDto = { paymentId: 2 };

try {
await service.refund(cancelPaymentDto);
} catch (error) {
expect(error).toBeInstanceOf(Error);
}

expect.assertions(1);
});

test('refund passes with valid data', async () => {
const refundPaymentDto = { paymentId: 3 };
const refunded = {
paymentId: 3,
amount: 200,
status: 'refund',
};

const result = await service.refund(refundPaymentDto);

expect(result).toEqual(refunded);
});
});
35 changes: 35 additions & 0 deletions vet_nest/src/payments/entity/payments.entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { PrimaryGeneratedColumn, Entity, Column, ManyToOne } from 'typeorm';
import { Reservation } from '../../reservations/entity/reservation.entity';

@Entity()
export class Payment {
@PrimaryGeneratedColumn()
paymentId: number;

@Column({ nullable: true })
appId: string;

@Column()
method: string;

@Column()
amount: number;

@Column()
status: string;

@Column({ default: () => 'CURRENT_TIMESTAMP' })
createdAt: Date;

@Column({ nullable: true })
canceledAt?: Date | null;

@Column()
reservationId: number;

@ManyToOne(() => Reservation, (reservation) => reservation.payments, {
nullable: false,
onDelete: 'CASCADE',
})
reservation: Reservation;
}
18 changes: 0 additions & 18 deletions vet_nest/src/payments/payments.controller.spec.ts

This file was deleted.

Loading

0 comments on commit 1cb8950

Please sign in to comment.