Adds createFromCart and order.completed subscribers

This commit is contained in:
olivermrbl
2020-07-09 18:16:45 +02:00
parent 1e48ab3d74
commit 08cf7c7f2b
8 changed files with 119 additions and 10 deletions

View File

@@ -12,19 +12,31 @@ export default async (req, res) => {
const paymentIntent = event.data.object const paymentIntent = event.data.object
const orderService = req.scope.resolve("orderService")
// handle payment intent events // handle payment intent events
switch (event.type) { switch (event.type) {
case "payment_intent.succeeded": case "payment_intent.succeeded":
const cartId = paymentIntent.metadata.cart_id
const order = await orderService.retrieveByCartId(cartId)
await orderService.update(order._id, {
payment_status: "captured",
})
break break
case "payment_intent.canceled": case "payment_intent.cancelled":
break const cartId = paymentIntent.metadata.cart_id
case "payment_intent.created": const order = await orderService.retrieveByCartId(cartId)
await orderService.update(order._id, {
status: "cancelled",
})
break break
case "payment_intent.payment_failed": case "payment_intent.payment_failed":
// TODO: Not implemented yet
break break
case "payment_intent.amount_capturable_updated": case "payment_intent.amount_capturable_updated":
break // TODO: Not implemented yet
case "payment_intent.processing":
break break
default: default:
res.status(400) res.status(400)

View File

@@ -104,6 +104,8 @@ class StripeProviderService extends PaymentService {
customer: stripeCustomerId, customer: stripeCustomerId,
amount: amount * 100, // Stripe amount is in cents amount: amount * 100, // Stripe amount is in cents
currency: currency_code, currency: currency_code,
capture_method: "manual",
metadata: { cart_id: cart._id },
}) })
return paymentIntent return paymentIntent

View File

@@ -10,13 +10,14 @@ class CartSubscriber {
this.stripeProviderService_ = stripeProviderService this.stripeProviderService_ = stripeProviderService
this.eventBus_ = eventBusService this.eventBus_ = eventBusService
this.eventBus_.subscribe("cart.created", (data) => {
console.log(data)
})
this.eventBus_.subscribe("cart.customer_updated", async (cart) => { this.eventBus_.subscribe("cart.customer_updated", async (cart) => {
await this.onCustomerUpdated(cart) await this.onCustomerUpdated(cart)
}) })
this.eventBus_.subscribe("order.completed", async (order) => {
const paymentData = order.payment_method.data
await this.stripeProviderService_.capturePayment(paymentData)
})
} }
async onCustomerUpdated(cart) { async onCustomerUpdated(cart) {

View File

@@ -7,6 +7,10 @@ class OrderSubscriber {
this.eventBus_.subscribe("order.placed", async (order) => { this.eventBus_.subscribe("order.placed", async (order) => {
await this.economicService_.draftEconomicInvoice(order) await this.economicService_.draftEconomicInvoice(order)
}) })
this.eventBus_.subscribe("order.completed", async (order) => {
await this.economicService_.bookEconomicInvoice(order._id)
})
} }
} }

View File

@@ -15,7 +15,7 @@ export default async (req, res) => {
const orderService = req.scope.resolve("orderService") const orderService = req.scope.resolve("orderService")
const cart = await cartService.retrieve(value.cartId) const cart = await cartService.retrieve(value.cartId)
let order = await orderService.create(cart) let order = await orderService.createFromCart(cart)
order = await orderService.decorate(order, [ order = await orderService.decorate(order, [
"status", "status",
"fulfillment_status", "fulfillment_status",

View File

@@ -63,6 +63,9 @@ export const orders = {
fulfillment_status: "not_fulfilled", fulfillment_status: "not_fulfilled",
payment_status: "awaiting", payment_status: "awaiting",
status: "pending", status: "pending",
metadata: {
cart_id: IdMap.getId("test-cart"),
},
}, },
processedOrder: { processedOrder: {
_id: IdMap.getId("processed-order"), _id: IdMap.getId("processed-order"),
@@ -237,6 +240,9 @@ export const OrderModelMock = {
orders.orderToRefund.payment_status = "captured" orders.orderToRefund.payment_status = "captured"
return Promise.resolve(orders.orderToRefund) return Promise.resolve(orders.orderToRefund)
} }
if (query.metadata.cart_id === IdMap.getId("test-cart")) {
return Promise.resolve(orders.testOrder)
}
return Promise.resolve(undefined) return Promise.resolve(undefined)
}), }),
} }

View File

@@ -1,5 +1,6 @@
import { IdMap } from "medusa-test-utils" import { IdMap } from "medusa-test-utils"
import { OrderModelMock, orders } from "../../models/__mocks__/order" import { OrderModelMock, orders } from "../../models/__mocks__/order"
import { carts } from "../../models/__mocks__/cart"
import OrderService from "../order" import OrderService from "../order"
import { PaymentProviderServiceMock } from "../__mocks__/payment-provider" import { PaymentProviderServiceMock } from "../__mocks__/payment-provider"
import { FulfillmentProviderServiceMock } from "../__mocks__/fulfillment-provider" import { FulfillmentProviderServiceMock } from "../__mocks__/fulfillment-provider"
@@ -30,6 +31,27 @@ describe("OrderService", () => {
}) })
}) })
describe("createFromCart", () => {
const orderService = new OrderService({
orderModel: OrderModelMock,
eventBusService: EventBusServiceMock,
})
beforeEach(async () => {
jest.clearAllMocks()
})
it("calls order model functions", async () => {
await orderService.createFromCart(carts.completeCart)
expect(OrderModelMock.create).toHaveBeenCalledTimes(1)
expect(OrderModelMock.create).toHaveBeenCalledWith({
...carts.completeCart,
metadata: { cart_id: carts.completeCart._id },
})
})
})
describe("retrieve", () => { describe("retrieve", () => {
let result let result
const orderService = new OrderService({ const orderService = new OrderService({
@@ -53,6 +75,29 @@ describe("OrderService", () => {
}) })
}) })
describe("retrieveByCartId", () => {
let result
const orderService = new OrderService({
orderModel: OrderModelMock,
})
beforeAll(async () => {
jest.clearAllMocks()
result = await orderService.retrieveByCartId(IdMap.getId("test-cart"))
})
it("calls order model functions", async () => {
expect(OrderModelMock.findOne).toHaveBeenCalledTimes(1)
expect(OrderModelMock.findOne).toHaveBeenCalledWith({
metadata: { cart_id: IdMap.getId("test-cart") },
})
})
it("returns correct order", async () => {
expect(result._id).toEqual(IdMap.getId("test-order"))
})
})
describe("update", () => { describe("update", () => {
const orderService = new OrderService({ const orderService = new OrderService({
orderModel: OrderModelMock, orderModel: OrderModelMock,

View File

@@ -153,6 +153,27 @@ class OrderService extends BaseService {
return order return order
} }
/**
* Gets an order by cart id.
* @param {string} cartId - cart id to find order
* @return {Promise<Order>} the order document
*/
async retrieveByCartId(cartId) {
const order = await this.orderModel_
.findOne({ metadata: { cart_id: cartId } })
.catch(err => {
throw new MedusaError(MedusaError.Types.DB_ERROR, err.message)
})
if (!order) {
throw new MedusaError(
MedusaError.Types.NOT_FOUND,
`Order with cart id ${cartId} was not found`
)
}
return order
}
/** /**
* @param {Object} selector - the query object for find * @param {Object} selector - the query object for find
* @return {Promise} the result of the find operation * @return {Promise} the result of the find operation
@@ -161,6 +182,24 @@ class OrderService extends BaseService {
return this.orderModel_.find(selector) return this.orderModel_.find(selector)
} }
/**
* Creates an order from a cart
* @param {object} order - the order to create
* @return {Promise} resolves to the creation result.
*/
async createFromCart(cart) {
return this.orderModel_
.create({ ...cart, metadata: { cart_id: cart._id } })
.then(result => {
// Notify subscribers
this.eventBus_.emit(OrderService.Events.PLACED, result)
return result
})
.catch(err => {
throw new MedusaError(MedusaError.Types.DB_ERROR, err.message)
})
}
/** /**
* Creates an order * Creates an order
* @param {object} order - the order to create * @param {object} order - the order to create