feat: restock service
This commit is contained in:
@@ -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
|
||||
Reference in New Issue
Block a user