feat(medusa): manage payment sessions from payment collection (#2402)

* feat: manage payment sessions from payment collection
This commit is contained in:
Carlos R. L. Rodrigues
2022-11-02 13:34:29 -03:00
committed by GitHub
parent a014e3623c
commit c3f8297599
28 changed files with 2002 additions and 1315 deletions
@@ -1,8 +1,10 @@
import { MedusaError } from "medusa-core-utils"
export default async (req, res) => {
const { klarna_order_id } = req.query
function isPaymentCollection(id) {
return id && id.startsWith("paycol")
}
try {
const orderService = req.scope.resolve("orderService")
const klarnaProviderService = req.scope.resolve("pp_klarna")
@@ -11,10 +13,18 @@ export default async (req, res) => {
klarna_order_id
)
const cartId = klarnaOrder.merchant_data
const order = await orderService.retrieveByCartId(cartId)
const resourceId = klarnaOrder.merchant_data
await klarnaProviderService.acknowledgeOrder(klarnaOrder.order_id, order.id)
if (isPaymentCollection(resourceId)) {
await klarnaProviderService.acknowledgeOrder(klarnaOrder.order_id)
} else {
const order = await orderService.retrieveByCartId(resourceId)
await klarnaProviderService.acknowledgeOrder(
klarnaOrder.order_id,
order.id
)
}
res.sendStatus(200)
} catch (error) {
@@ -230,6 +230,84 @@ class KlarnaProviderService extends PaymentService {
return order
}
validateKlarnaOrderUrls(property) {
const required = ["terms", "checkout", "confirmation"]
const isMissing = required.some((prop) => !this.options_[property]?.[prop])
if (isMissing) {
throw new Error(
`options.${property} is required to create a Klarna Order.\n` +
`medusa-config.js file has to contain ${property} { ${required.join(
", "
)}}`
)
}
}
replaceStringWithPropertyValue(string, obj) {
const keys = Object.keys(obj)
for (const key of keys) {
if (string.includes(`{${key}}`)) {
string = string.replace(`{${key}}`, obj[key])
}
}
return string
}
async paymentInputToKlarnaOrder(paymentInput) {
if (paymentInput.cart) {
this.validateKlarnaOrderUrls("merchant_urls")
return this.cartToKlarnaOrder(paymentInput.cart)
}
this.validateKlarnaOrderUrls("payment_collection_urls")
let order = {
// Custom id is stored, such that we can use it for hooks
merchant_data: paymentInput.resource_id,
locale: "en-US",
}
const { currency_code, amount } = paymentInput
order.order_lines = [
{
name: "Payment Collection",
quantity: 1,
unit_price: amount,
tax_rate: 0,
total_amount: amount,
total_tax_amount: 0,
},
]
// Defaults to Sweden
order.purchase_country = "SE"
order.order_amount = amount
order.order_tax_amount = 0
order.purchase_currency = currency_code.toUpperCase()
order.merchant_urls = {
terms: this.replaceStringWithPropertyValue(
this.options_.payment_collection_urls.terms,
paymentInput
),
checkout: this.replaceStringWithPropertyValue(
this.options_.payment_collection_urls.checkout,
paymentInput
),
confirmation: this.replaceStringWithPropertyValue(
this.options_.payment_collection_urls.confirmation,
paymentInput
),
push: `${this.backendUrl_}/klarna/push?klarna_order_id={checkout.order.id}`,
}
return order
}
/**
* Status for Klarna order.
* @param {Object} paymentData - payment method data from cart
@@ -251,7 +329,7 @@ class KlarnaProviderService extends PaymentService {
}
/**
* Creates Stripe PaymentIntent.
* Creates Klarna PaymentIntent.
* @param {string} cart - the cart to create a payment for
* @param {number} amount - the amount to create a payment for
* @returns {string} id of payment intent
@@ -271,6 +349,21 @@ class KlarnaProviderService extends PaymentService {
}
}
async createPaymentNew(paymentInput) {
try {
const order = await this.paymentInputToKlarnaOrder(paymentInput)
const klarnaPayment = await this.klarna_
.post(this.klarnaOrderUrl_, order)
.then(({ data }) => data)
return klarnaPayment
} catch (error) {
this.logger_.error(error)
throw error
}
}
/**
* Retrieves Klarna Order.
* @param {string} cart - the cart to retrieve order for
@@ -338,18 +431,20 @@ class KlarnaProviderService extends PaymentService {
* @param {string} klarnaOrderId - id of the order to acknowledge
* @returns {string} id of acknowledged order
*/
async acknowledgeOrder(klarnaOrderId, orderId) {
async acknowledgeOrder(klarnaOrderId, orderId = null) {
try {
await this.klarna_.post(
`${this.klarnaOrderManagementUrl_}/${klarnaOrderId}/acknowledge`
)
await this.klarna_.patch(
`${this.klarnaOrderManagementUrl_}/${klarnaOrderId}/merchant-references`,
{
merchant_reference1: orderId,
}
)
if (orderId !== null) {
await this.klarna_.patch(
`${this.klarnaOrderManagementUrl_}/${klarnaOrderId}/merchant-references`,
{
merchant_reference1: orderId,
}
)
}
return klarnaOrderId
} catch (error) {
@@ -408,6 +503,22 @@ class KlarnaProviderService extends PaymentService {
return paymentData
}
async updatePaymentNew(paymentData, paymentInput) {
if (paymentInput.amount !== paymentData.order_amount) {
const order = await this.paymentInputToKlarnaOrder(paymentInput)
return this.klarna_
.post(`${this.klarnaOrderUrl_}/${paymentData.order_id}`, order)
.then(({ data }) => data)
.catch(async (_) => {
return this.klarna_
.post(this.klarnaOrderUrl_, order)
.then(({ data }) => data)
})
}
return paymentData
}
/**
* Captures Klarna order.
* @param {Object} paymentData - payment method data from cart