159 lines
4.4 KiB
JavaScript
159 lines
4.4 KiB
JavaScript
class AdyenSubscriber {
|
|
constructor(container) {
|
|
/** @private @const {CartService} */
|
|
this.cartService_ = container.cartService
|
|
|
|
/** @private @const {OrderService} */
|
|
this.orderService_ = container.orderService
|
|
|
|
/** @private @const {EventBusService} */
|
|
this.eventBus_ = container.eventBusService
|
|
|
|
/** @private @const {PaymentRepository} */
|
|
this.paymentRepository_ = container.paymentRepository
|
|
|
|
this.manager_ = container.manager
|
|
|
|
this.eventBus_.subscribe(
|
|
"adyen.notification_received",
|
|
async (notification) => this.handleAdyenNotification(notification)
|
|
)
|
|
}
|
|
|
|
/**
|
|
* Webhook handler for Adyen payment.
|
|
* @param {object} notification - webhook notification object
|
|
* @returns {string} the status of the payment intent
|
|
*/
|
|
async handleAdyenNotification(notification) {
|
|
switch (true) {
|
|
case notification.success === "true" &&
|
|
notification.eventCode === "AUTHORISATION": {
|
|
this.handleAuthorization_(notification)
|
|
break
|
|
}
|
|
case notification.success === "false" &&
|
|
notification.eventCode === "AUTHORISATION": {
|
|
this.handleFailedAuthorization_(notification)
|
|
break
|
|
}
|
|
case notification.success === "true" &&
|
|
notification.eventCode === "CAPTURE_FAILED": {
|
|
this.handleFailedCapture_(notification)
|
|
break
|
|
}
|
|
case notification.success === "false" &&
|
|
notification.eventCode === "CAPTURE": {
|
|
this.handleFailedCapture_(notification)
|
|
break
|
|
}
|
|
case notification.success === "false" &&
|
|
notification.eventCode === "REFUND": {
|
|
this.handleFailedRefund_(notification)
|
|
break
|
|
}
|
|
default:
|
|
break
|
|
}
|
|
}
|
|
|
|
async handleFailedAuthorization_(notification) {
|
|
const cartId = notification.additionalData["metadata.cart_id"]
|
|
const cart = await this.cartService_.retrieve(cartId, {
|
|
relations: ["payment_sessions"],
|
|
})
|
|
|
|
const { payment_session } = cart
|
|
|
|
const updated = {
|
|
...payment_session,
|
|
status: "error",
|
|
data: {
|
|
...payment_session.data,
|
|
pspReference: notification.pspReference,
|
|
},
|
|
}
|
|
|
|
await this.cartService_.updatePaymentSession(cart.id, updated)
|
|
}
|
|
|
|
async handleAuthorization_(notification) {
|
|
const cartId = notification.additionalData["metadata.cart_id"]
|
|
const paymentRepository = this.manager_.getCustomRepository(
|
|
this.paymentRepository_
|
|
)
|
|
|
|
// We need to ensure, that an order is created in situations, where the
|
|
// customer might have closed their browser prior to order creation
|
|
try {
|
|
const orderPayment = await paymentRepository.findOne({
|
|
where: { cart_id: cartId },
|
|
})
|
|
|
|
if (!orderPayment) {
|
|
throw new Error("Payment not found")
|
|
}
|
|
|
|
const updatedPayment = {
|
|
...orderPayment,
|
|
data: {
|
|
...orderPayment.data,
|
|
resultCode: "Authorised",
|
|
pspReference: notification.pspReference,
|
|
},
|
|
}
|
|
|
|
await this.paymentRepository_.save(updatedPayment)
|
|
} catch (error) {
|
|
await this.manager_.transaction(async (manager) => {
|
|
const session = {
|
|
pspReference: notification.pspReference,
|
|
resultCode: "Authorised",
|
|
}
|
|
|
|
await this.cartService_
|
|
.withTransaction(manager)
|
|
.updatePaymentSession(cartId, session)
|
|
|
|
await this.cartService_
|
|
.withTransaction(manager)
|
|
.authorizePayment(cartId)
|
|
|
|
await this.orderService_.withTransaction(manager).createFromCart(cartId)
|
|
})
|
|
}
|
|
}
|
|
|
|
async handleFailedCapture_(notification) {
|
|
const cartId = notification.additionalData["metadata.cart_id"]
|
|
|
|
const order = await this.orderService_.retrieveByCartId(cartId)
|
|
|
|
await this.orderService_.update(order.id, {
|
|
payment_status: "requires_action",
|
|
})
|
|
|
|
await this.eventBus_.emit("order.payment_capture_failed", {
|
|
order,
|
|
error: new Error(`Adyen payment capture: ${notification.reason}`),
|
|
})
|
|
}
|
|
|
|
async handleFailedRefund_(notification) {
|
|
const cartId = notification.additionalData["metadata.cart_id"]
|
|
|
|
const order = await this.orderService_.retrieveByCartId(cartId)
|
|
|
|
await this.orderService_.update(order.id, {
|
|
payment_status: "requires_action",
|
|
})
|
|
|
|
await this.eventBus_.emit("order.refund_failed", {
|
|
order,
|
|
error: new Error(`Adyen payment capture: ${notification.reason}`),
|
|
})
|
|
}
|
|
}
|
|
|
|
export default AdyenSubscriber
|