Files
medusa-store/packages/medusa-plugin-restock-notification/src/services/restock-notification.js
Sebastian Rindom 329767e279 fix: ensures that delayed restock notifications are being sent (#881)
* fix: ensures that delayed restock notifications are being sent

* fix: default options to empty object

* fix: tests
2021-12-08 09:55:00 +01:00

153 lines
4.3 KiB
JavaScript

import { MedusaError } from "medusa-core-utils"
import { BaseService } from "medusa-interfaces"
/**
* Restock notifications can be used to keep track of customers who wish to be
* notified when a certain item is restocked. Restock notifications can only
* apply to sold out items and will be deleted once items are restocked.
*/
class RestockNotificationService extends BaseService {
constructor(
{
manager,
eventBusService,
productVariantService,
restockNotificationModel,
},
options
) {
super()
this.manager_ = manager
this.options_ = options
this.productVariantService_ = productVariantService
this.restockNotificationModel_ = restockNotificationModel
this.eventBus_ = eventBusService
}
withTransaction(transactionManager) {
if (!transactionManager) {
return this
}
const cloned = new RestockNotificationService(
{
manager: transactionManager,
options: this.options_,
eventBusService: this.eventBus_,
productVariantService: this.productVariantService_,
restockNotificationModel: this.restockNotificationModel_,
},
this.options_
)
cloned.transactionManager_ = transactionManager
return cloned
}
/**
* Retrieves a restock notification by a given variant id.
* @param {string} variantId - the variant id to retrieve restock notification
* for
* @return {Promise<RestockNotification>} The restock notification
*/
async retrieve(variantId) {
const restockRepo = this.manager_.getRepository(
this.restockNotificationModel_
)
return await restockRepo.findOne({ where: { variant_id: variantId } })
}
/**
* Adds an email to be notified when a certain variant is restocked. Throws if
* the variant is not sold out.
* @param {string} variantId - the variant id to sign up for notifications for
* @param {string} email - the email to signup
* @return {Promise<RestockNotification>} The resulting restock notification
*/
async addEmail(variantId, email) {
return this.atomicPhase_(async (manager) => {
const restockRepo = manager.getRepository(this.restockNotificationModel_)
const existing = await this.retrieve(variantId)
if (existing) {
// Converting to a set handles duplicates for us
const emailSet = new Set(existing.emails)
emailSet.add(email)
existing.emails = Array.from(emailSet)
return await restockRepo.save(existing)
} else {
const variant = await this.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)
}
})
}
/**
* Checks if anyone has signed up for restock notifications on a given variant
* and emits a restocked event to the event bus. After successful emission the
* restock notification is deleted.
* @param {string} variantId - the variant id to trigger restock for
* @return The resulting restock notification
*/
async triggerRestock(variantId) {
const delay = this.options_?.trigger_delay ?? 0
if (delay) {
return await this.eventBus_.emit(
"restock-notification.execute",
{ variant_id: variantId },
{ delay }
)
}
return await this.restockExecute(variantId)
}
async restockExecute(variantId) {
return await this.atomicPhase_(async (manager) => {
const restockRepo = manager.getRepository(this.restockNotificationModel_)
const existing = await this.retrieve(variantId)
if (!existing) {
return
}
const variant = await this.productVariantService_.retrieve(variantId)
if (
variant.inventory_quantity > (this.options_?.inventory_required ?? 0)
) {
await this.eventBus_
.withTransaction(manager)
.emit("restock-notification.restocked", {
variant_id: variantId,
emails: existing.emails,
})
await restockRepo.delete(variantId)
}
})
}
}
export default RestockNotificationService