Merge branch 'integration/dummy-project' of github.com:medusajs/medusa into integration/dummy-project

This commit is contained in:
Sebastian Rindom
2020-07-09 18:19:21 +02:00
15 changed files with 195 additions and 11 deletions

View File

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

View File

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

View File

@@ -10,13 +10,14 @@ class CartSubscriber {
this.stripeProviderService_ = stripeProviderService
this.eventBus_ = eventBusService
this.eventBus_.subscribe("cart.created", (data) => {
console.log(data)
})
this.eventBus_.subscribe("cart.customer_updated", async (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) {

View File

@@ -0,0 +1,10 @@
import { Router } from "express"
import routes from "./routes"
export default (container) => {
const app = Router()
routes(app)
return app
}

View File

@@ -0,0 +1 @@
export default (fn) => (...args) => fn(...args).catch(args[2])

View File

@@ -0,0 +1,5 @@
import { default as wrap } from "./await-middleware"
export default {
wrap,
}

View File

@@ -0,0 +1,18 @@
export default async (req, res) => {
const schema = Validator.object().keys({
orderId: Validator.string().required(),
})
const { value, error } = schema.validate(req.body)
if (error) {
throw new MedusaError(MedusaError.Types.INVALID_DATA, error.details)
}
try {
const economicService = req.scope.resolve("economicService")
await economicService.bookEconomicInvoice(value.orderId)
res.sendStatus(200)
} catch (error) {
throw error
}
}

View File

@@ -0,0 +1,18 @@
export default async (req, res) => {
const schema = Validator.object().keys({
orderId: Validator.string().required(),
})
const { value, error } = schema.validate(req.body)
if (error) {
throw new MedusaError(MedusaError.Types.INVALID_DATA, error.details)
}
try {
const economicService = req.scope.resolve("economicService")
await economicService.draftEconomicInvoice(value.orderId)
res.sendStatus(200)
} catch (error) {
throw error
}
}

View File

@@ -0,0 +1,20 @@
import { Router } from "express"
import middlewares from "../../middlewares"
const route = Router()
export default (app) => {
app.use("/economic", route)
route.post(
"/draft-invoice",
middlewares.wrap(require("./create-draft-invoice").default)
)
route.post(
"/book-invoice",
middlewares.wrap(require("./book-invoice").default)
)
return app
}

View File

@@ -188,6 +188,9 @@ class EconomicService extends BaseService {
"economicDraftId",
draftInvoice.draftInvoiceNumber
)
const invoiceOrder = await this.orderService_.retrieve(order._id)
return invoiceOrder
} catch (error) {
throw error
}
@@ -211,7 +214,7 @@ class EconomicService extends BaseService {
},
}
await this.economic_.post(
return this.economic_.post(
`${ECONOMIC_BASE_URL}/invoices/booked`,
bookInvoiceRequest
)

View File

@@ -7,6 +7,10 @@ class OrderSubscriber {
this.eventBus_.subscribe("order.placed", async (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 cart = await cartService.retrieve(value.cartId)
let order = await orderService.create(cart)
let order = await orderService.createFromCart(cart)
order = await orderService.decorate(order, [
"status",
"fulfillment_status",

View File

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

View File

@@ -1,5 +1,6 @@
import { IdMap } from "medusa-test-utils"
import { OrderModelMock, orders } from "../../models/__mocks__/order"
import { carts } from "../../models/__mocks__/cart"
import OrderService from "../order"
import { PaymentProviderServiceMock } from "../__mocks__/payment-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", () => {
let result
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", () => {
const orderService = new OrderService({
orderModel: OrderModelMock,

View File

@@ -153,6 +153,27 @@ class OrderService extends BaseService {
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
* @return {Promise} the result of the find operation
@@ -161,6 +182,24 @@ class OrderService extends BaseService {
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
* @param {object} order - the order to create