feat: restock service

This commit is contained in:
Sebastian Rindom
2021-03-26 12:44:55 +01:00
parent c3bc8c98b4
commit 8bd5fa8212
8 changed files with 306 additions and 469 deletions
@@ -0,0 +1,32 @@
import {
Entity,
Index,
BeforeInsert,
Column,
DeleteDateColumn,
CreateDateColumn,
UpdateDateColumn,
PrimaryColumn,
ManyToOne,
JoinColumn,
} from "typeorm"
import { ProductVariant } from "@medusajs/medusa"
@Entity()
export class RestockNotification {
@PrimaryColumn()
variant_id: string
@ManyToOne(() => ProductVariant)
@JoinColumn({ name: "variant_id" })
variant: ProductVariant
@Column({ type: "jsonb" })
emails: string[]
@CreateDateColumn({ type: "timestamptz" })
created_at: Date
@UpdateDateColumn({ type: "timestamptz" })
updated_at: Date
}
@@ -0,0 +1,81 @@
import { MedusaError } from "medusa-core-utils"
import { BaseService } from "medusa-interfaces"
class RestockNotificationService extends BaseService {
constructor(
{
manager,
eventBusService,
productVariantService,
restockNotificationRepository,
},
options
) {
super()
this.manager_ = manager
this.options_ = options
this.productVariantService_ = productVariantService
this.restockNotificationRepo_ = restockNotificationRepository
this.eventBus_ = eventBusService
}
async retrieve(variantId) {
const restockRepo = this.manager_.getCustomRepository(
this.restockNotificationRepo_
)
return await restockRepo.findOne({ where: { variant_id: variantId } })
}
async addEmail(variantId, email) {
return this.atomicPhase_(async (manager) => {
const restockRepo = manager.getCustomRepository(
this.restockNotificationRepo_
)
const existing = await this.retrieve(variantId)
if (existing) {
// Converting to a set handles duplicates for us
const emailSet = new Set(existing.emails)
emailSet.push(email)
existing.emails = Array.from(emailSet)
return await restockRepo.save(existing)
} else {
const variant = await productVariantService.retrieve(variantId)
if (variant.inventory_quantity > 0) {
throw new MedusaError(
MedusaError.Types.NOT_ALLOWED,
"You cannot sign up for restock notifications on a product that is not sold out"
)
}
const created = restockRepo.create({
variant_id: variant.id,
emails: [email],
})
return await restockRepo.save(created)
}
})
}
async triggerRestock(variantId) {
return this.atomicPhase_(async (manager) => {
const existing = await this.retrieve(variantId)
if (!existing) {
return
}
})
}
}
export default RestockNotificationService
@@ -1,34 +0,0 @@
import { BaseService } from "medusa-interfaces"
import twilio from "twilio"
class TwilioSmsService extends BaseService {
/**
* @param {Object} options - options defined in `medusa-config.js`
* e.g.
* {
* account_sid: "1234",
* auth_token: "XXX",
* from_number: "+4512345678"
* }
*/
constructor({}, options) {
super()
this.options_ = options
this.twilioClient = twilio(options.account_sid, options.auth_token)
}
/**
* @param {Object} data - Twilio message options
* see: https://www.twilio.com/docs/sms/api/message-resource#create-a-message-resource
*/
async sendSms(data) {
return this.twilioClient.messages.create({
from: this.options_.from_number,
...data,
})
}
}
export default TwilioSmsService
@@ -0,0 +1,81 @@
class VariantSubscriber {
constructor({
eventBusService,
restockNotificationService,
productVariantService,
}) {
this.restockNotificationService_ = restockNotificationService
eventBusService.subscribe("product_variant.updated", this.handleVariantUpdate)
}
registerClaim = async (data) => {
const { id } = data
const fromClaim = await this.claimService_.retrieve(id, {
relations: [
"order",
"order.payments",
"order.region",
"order.claims",
"order.discounts",
"claim_items",
"return_order",
"return_order.items",
"return_order.shipping_method",
"additional_items",
"shipping_address",
"shipping_methods",
],
})
const fromOrder = fromClaim.order
if (fromClaim.type === "replace") {
await this.brightpearlService_.createClaim(fromOrder, fromClaim)
} else if (fromClaim.type === "refund") {
await this.brightpearlService_.createClaimCredit(fromOrder, fromClaim)
}
}
registerShipment = async (data) => {
const { fulfillment_id } = data
const shipment = await this.fulfillmentService_.retrieve(fulfillment_id)
const noteId = shipment.metadata.goods_out_note
if (noteId) {
await this.brightpearlService_.registerGoodsOutTrackingNumber(
noteId,
shipment
)
await this.brightpearlService_.registerGoodsOutShipped(noteId, shipment)
}
}
registerReturn = async (data) => {
const { id, return_id } = data
const order = await this.orderService_.retrieve(id, {
relations: ["region", "payments"],
})
const fromReturn = await this.returnService_.retrieve(return_id, {
relations: ["items"],
})
return this.brightpearlService_
.createSalesCredit(order, fromReturn)
.catch((err) => console.log(err))
}
registerRefund = async (data) => {
const { id, refund_id } = data
const order = await this.orderService_.retrieve(id, {
relations: ["region", "payments"],
})
const refund = await this.paymentProviderService_.retrieveRefund(refund_id)
return this.brightpearlService_
.createRefundCredit(order, refund)
.catch((err) => console.log(err))
}
}
export default OrderSubscriber