Skip to content

Commit

Permalink
feat(medusa/payment-paytr): Finalize paytr payment
Browse files Browse the repository at this point in the history
  • Loading branch information
adrien2p committed Apr 11, 2022
1 parent c5a638f commit e6c9af9
Show file tree
Hide file tree
Showing 7 changed files with 64 additions and 81 deletions.
1 change: 1 addition & 0 deletions packages/medusa/payment-paytr/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ coverage

/api/
/services/
/subscribers/
utils.js
types.js
index.js
Expand Down
18 changes: 9 additions & 9 deletions packages/medusa/payment-paytr/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions packages/medusa/payment-paytr/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
"devDependencies": {
"@medusajs/medusa": "1.2.1",
"@types/express": "^4.17.13",
"@types/jest": "^27.4.0",
"@types/jest": "^27.4.1",
"@types/node": "^17.0.15",
"core-js": "^3.21.0",
"cross-env": "^7.0.3",
Expand All @@ -54,9 +54,9 @@
"typescript": "^4.5.5"
},
"peerDependencies": {
"medusa-interfaces": "^1.2.1",
"@medusajs/medusa": "^1.2.1",
"medusa-core-utils": "^1.1.31",
"@medusajs/medusa": "^1.2.1"
"medusa-interfaces": "^1.2.1"
},
"dependencies": {
"body-parser": "^1.19.1",
Expand Down
13 changes: 4 additions & 9 deletions packages/medusa/payment-paytr/src/api/routes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,9 @@ export default (app: Router): Router => {
};

async function webhook(req: CustomRequest, res: Response): Promise<void> {
try {
const data = req.body;
const data = req.body;

const payTRProviderService = req.scope.resolve('pp_paytr') as PayTRProviderService;
await payTRProviderService.handleCallback(data);

res.send('OK');
} catch (err) {
res.status(400).json({ message: err.message });
}
const payTRProviderService = req.scope.resolve('pp_paytr') as PayTRProviderService;
await payTRProviderService.handleCallback(data);
res.send('OK');
}
27 changes: 12 additions & 15 deletions packages/medusa/payment-paytr/src/services/paytr-provider.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import OrderService from '@medusajs/medusa/dist/services/order';
import TotalsService from '@medusajs/medusa/dist/services/totals';
import { Cart, Payment, PaymentSession } from '@medusajs/medusa/dist';
import { Cart, Payment, PaymentSession, PaymentSessionStatus } from '@medusajs/medusa/dist';
import { CustomerService, RegionService } from '@medusajs/medusa/dist/services';
import { PaymentService } from 'medusa-interfaces';
import { PaymentSessionStatus } from '@medusajs/medusa/dist/models/payment-session';
import { MerchantConfig, PaymentData, PaymentSessionData } from '../types';
import CartService from '@medusajs/medusa/dist/services/cart';
import * as nodeBase64 from 'nodejs-base64-converter';
Expand All @@ -25,14 +23,13 @@ export default class PayTRProviderService extends PaymentService {

readonly #manager: EntityManager;
readonly #paymentSessionRepository: typeof PaymentSessionRepository;
readonly #orderService: OrderService;
readonly #customerService: CustomerService;
readonly #regionService: RegionService;
readonly #totalsService: TotalsService;
readonly #cartService: CartService;

constructor(
{ manager, paymentSessionRepository, cartService, customerService, totalsService, regionService, orderService },
{ manager, paymentSessionRepository, cartService, customerService, totalsService, regionService },
options: MerchantConfig
) {
super();
Expand All @@ -41,7 +38,6 @@ export default class PayTRProviderService extends PaymentService {

this.#manager = manager;
this.#paymentSessionRepository = paymentSessionRepository;
this.#orderService = orderService;
this.#customerService = customerService;
this.#regionService = regionService;
this.#totalsService = totalsService;
Expand Down Expand Up @@ -115,12 +111,19 @@ export default class PayTRProviderService extends PaymentService {
return status === 'success' ? PaymentSessionStatus.AUTHORIZED : PaymentSessionStatus.ERROR;
}

async getPaymentData(sessionData: { data: PaymentSessionData }): Promise<PaymentSessionData> {
async getPaymentData(sessionData: { data: PaymentSessionData }): Promise<PaymentData> {
return sessionData.data;
}

async authorizePayment(paymentSession: PaymentSession): Promise<{ status: string; data: PaymentSessionData }> {
return { status: 'authorized', data: paymentSession.data };
return {
status: !paymentSession.data.status
? PaymentSessionStatus.PENDING
: paymentSession.data.status === 'success'
? PaymentSessionStatus.AUTHORIZED
: PaymentSessionStatus.ERROR,
data: paymentSession.data,
};
}

async updatePayment(
Expand Down Expand Up @@ -194,14 +197,8 @@ export default class PayTRProviderService extends PaymentService {
const paymentSessionRepo = this.#manager.getCustomRepository(this.#paymentSessionRepository);
cart.payment_session.status =
status === 'success' ? PaymentSessionStatus.AUTHORIZED : PaymentSessionStatus.ERROR;
cart.payment_session.data.status = status;
await paymentSessionRepo.save(cart.payment_session);
if (status === 'error') return;

let order = await this.#orderService.retrieveByCartId(cartId);
if (!order) {
order = await this.#orderService.createFromCart(cartId);
}
await this.#orderService.capturePayment(order.id);
}

async retrieveCart(cartId: string): Promise<Cart> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { TotalsServiceMock } from '../../__mock__/totals';
import { cartMockData, CartServiceMock } from '../../__mock__/cart';
import { MerchantConfig } from '../../types';
import { Cart } from '@medusajs/medusa/dist';
import { buildOid, buildPaytrToken, getCartIdFromOid } from '../../utils';
import { buildOid } from '../../utils';
import { PaymentSessionStatus } from '@medusajs/medusa/dist/models/payment-session';

const merchantConfig: MerchantConfig = {
Expand All @@ -35,12 +35,6 @@ const RegionServiceMock = {
retrieve: jest.fn().mockReturnValue(Promise.resolve({ currency_code: 'TL', currency: { symbol: 'TL' } })),
};

const OrderServiceMock = {
retrieveByCartId: jest.fn().mockReturnValue(Promise.resolve()),
createFromCart: jest.fn().mockReturnValue(Promise.resolve({ id: 'or_dzlkfzengzelkgvnz' })),
capturePayment: jest.fn().mockReturnValue(Promise.resolve()),
};

const PaymentMockRepository = MockRepository({
save: jest.fn().mockReturnValue(Promise.resolve()),
});
Expand All @@ -58,7 +52,6 @@ describe('PayTrProvider', () => {
customerService: CustomerServiceMock,
regionService: RegionServiceMock,
totalsService: TotalsServiceMock,
orderService: OrderServiceMock,
},
merchantConfig
);
Expand All @@ -85,41 +78,4 @@ describe('PayTrProvider', () => {
status = await provider.getStatus({ status: 'rejected' });
expect(status).toBe(PaymentSessionStatus.ERROR);
});

describe('on handleCallback calls', () => {
const merchantOid = buildOid(cartMockData.id.split('_').pop());
const getCallbackData = (status: 'success' | 'error') => ({
merchant_oid: merchantOid,
status,
total_amount: 100,
hash: buildPaytrToken(merchantOid + merchantConfig.merchant_salt + status + 100, {
merchant_key: merchantConfig.merchant_key,
}),
});

it('should not create an order on fail', async () => {
await provider.handleCallback(getCallbackData('error'));
expect(PaymentMockRepository.save).toHaveBeenCalledWith(
expect.objectContaining({
status: PaymentSessionStatus.ERROR,
})
);
expect(OrderServiceMock.retrieveByCartId).not.toHaveBeenCalledWith();
expect(OrderServiceMock.createFromCart).not.toHaveBeenCalledWith();
expect(OrderServiceMock.capturePayment).not.toHaveBeenCalledWith();
});

it('should create an order on success', async () => {
await provider.handleCallback(getCallbackData('success'));
expect(PaymentMockRepository.save).toHaveBeenCalledWith(
expect.objectContaining({
status: PaymentSessionStatus.AUTHORIZED,
})
);
const expectedCartId = getCartIdFromOid(merchantOid);
expect(OrderServiceMock.retrieveByCartId).toHaveBeenCalledWith(expectedCartId);
expect(OrderServiceMock.createFromCart).toHaveBeenCalledWith(expectedCartId);
expect(OrderServiceMock.capturePayment).toHaveBeenCalledWith('or_dzlkfzengzelkgvnz');
});
});
});
34 changes: 34 additions & 0 deletions packages/medusa/payment-paytr/src/subscribers/order.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import EventBusService from '@medusajs/medusa/dist/services/event-bus';
import OrderService from '@medusajs/medusa/dist/services/order';
import CartService from '@medusajs/medusa/dist/services/cart';
import PaymentProviderService from '@medusajs/medusa/dist/services/payment-provider';
import { PaymentSessionStatus } from '@medusajs/medusa/dist';

export default class OrderSubscriber {
readonly #orderService: OrderService;
readonly #cartService: CartService;
readonly #paymentProviderService: PaymentProviderService;
readonly #eventBus: EventBusService;

constructor({ orderService, cartService, eventBusService, paymentProviderService }) {
this.#eventBus = eventBusService;
this.#orderService = orderService;
this.#paymentProviderService = paymentProviderService;
this.#cartService = cartService;

this.#eventBus.subscribe(OrderService.Events.PLACED, async ({ id }) => {
return await this.onOrderPlaces(id);
});
}

async onOrderPlaces(id: string) {
const order = await this.#orderService.retrieve(id);
const cart = await this.#cartService.retrieve(order.cart_id, {
relations: ['payment'],
});
const paymentStatus = await this.#paymentProviderService.getStatus(cart.payment);
if (paymentStatus === PaymentSessionStatus.AUTHORIZED) {
return await this.#orderService.capturePayment(id);
}
}
}

0 comments on commit e6c9af9

Please sign in to comment.