Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

prasanna malla
prasanna malla

Posted on

     

Shipping new features to our NPM package

Earlier, we published aVendure plugin to NPM and fixed ourfirst bug. Now, it is time to add new features and publish an update.

On the Todo afterextending the AdminUI in Vendure, was the ability for sending back in stock email notifications from the admin. We have the button; let's get to the functionality! All interactions with the server need to be done via GraphQL API calls in the admin ui.

Add the function call to the button and create thenotify method

// back-in-stock-list.component.html<tdclass="right align-middle"><button*ngIf="subscription.status === 'Created' && subscription.productVariant.stockOnHand > 0"class="icon-button"title="Send notification email"(click)="notify(subscription.id)"><clr-iconshape="envelope"></clr-icon></button></td>
Enter fullscreen modeExit fullscreen mode
// back-in-stock-list.component.tsasyncnotify(id:ID):Promise<void>{try{awaitthis.dataService.mutate(gql`                    mutation {                        updateBackInStockSubscription(input: {id: "${id}", status: Notified}) {                            id                            status                        }                    }                `,).toPromise();this.notificationService.success('Notification email sent');this.refresh();}catch(e){this.notificationService.error('Error');}}
Enter fullscreen modeExit fullscreen mode

The hard rule is that in an admin UI extension, youcannot import anything from@vendure/core or anything else outside the ui folder. The setup for sending off emails is event driven and came across this hard rule when importingEventBus with this misleading error screen, having nothing to do with other packages as shown. RemovingEventBus made this go away

VSCode error screenshot

Instead, we publish theBackInStockEvent from theupdate method inBackInStockService. Email sending from admin works! Next Todo item was limiting emails sent to amount of saleable stock with configurable options.

Vendure is built-on solid foundations using TypeORM with Nest.js which allows us to define databasesubscribers. With a subscriber, we can listen to specific entity events and take actions based on inserts, updates, deletions and more.

An important factor when working with TypeORM subscribers is that they are very low-level and require some understanding of the Vendure schema. By defining the subscriber as an injectable provider, and passing it to a Vendure plugin, you can take advantage of Nest's dependency injection inside the subscriber methods.

Under the hood, TypeORM uses the Observer design pattern to implement database subscribers. This pattern defines a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically. When you register a subscriber, TypeORM sets up database triggers or hooks on the entities that the subscriber is interested in.

When the trigger or hook is fired, the database notifies TypeORM of the event. TypeORM then invokes the corresponding method on the subscriber class, passing in the event data. The subscriber can then perform any custom logic it needs to in response to the event.

This approach is much more efficient than polling the database because it eliminates the need to constantly query the database for changes. Instead, the database itself is responsible for detecting events and notifying the subscribers. This leads to better performance and reduced database load.

Create a subscriber forProductVariant

/** * @description * Subscribes to {@link ProductVariant} entity changes * and FIFO updates {@link BackInStock} to be notified * to the amount of saleable stock with plugin init option * limitEmailToStock = true or false to notify all subscribers * */@Injectable()@EventSubscriber()exportclassProductVariantSubscriberimplementsEntitySubscriberInterface<ProductVariant>{constructor(privateconnection:TransactionalConnection,privatebackInStockService:BackInStockService,privateproductVariantService:ProductVariantService,privaterequestContextService:RequestContextService,){this.connection.rawConnection.subscribers.push(this);}listenTo(){returnProductVariant;}// set subscriptions to be notified only on replenishment eventasyncafterUpdate(event:UpdateEvent<ProductVariant>){if(event.entity?.stockOnHand>event.databaseEntity?.stockOnHand){constctx=awaitthis.requestContextService.create({apiType:getApiType()});constproductVariant=awaitthis.productVariantService.findOne(ctx,event.entity?.id);//! calculate saleable manually as this context is not aware of the current db transactionconstsaleableStock=event.entity?.stockOnHand-productVariant!.stockAllocated-productVariant!.outOfStockThreshold;constbackInStockSubscriptions=awaitthis.backInStockService.findActiveForProductVariant(ctx,productVariant!.id,{take:BackInStockPlugin.options.limitEmailToStock?saleableStock:undefined,sort:{createdAt:SortOrder.ASC,},},);if(saleableStock>=1&&backInStockSubscriptions.totalItems>=1){for(constsubscriptionofbackInStockSubscriptions.items){this.backInStockService.update(ctx,{id:subscription.id,status:BackInStockSubscriptionStatus.Notified,});}}}}}@VendurePlugin({// .. configproviders:[{provide:PLUGIN_INIT_OPTIONS,useFactory:()=>BackInStockPlugin.options,},BackInStockService,ProductVariantSubscriber,],})exportclassBackInStockPlugin{staticoptions:BackInStockOptions={enableEmail:true,limitEmailToStock:true,};staticinit(options:BackInStockOptions):typeofBackInStockPlugin{this.options=options;returnBackInStockPlugin;}// .. ui extensions}
Enter fullscreen modeExit fullscreen mode

By comparing thestockOnHand on the ongoing DB transactionevent.entity and the existing value onevent.databaseEntity we can determine replenishment event. Since the newcontext in the subscriber is not aware of the ongoing DB transaction, we need to change setting saleableStock fromProductVariantService to manual calculation. With theProductVariantSubscriber added to theproviders array and we are ready to test it!

Instead of publishing your changes, you can runyarn build and copy over thedist folder to thenode_modules/@callit-today/vendure-plugin-back-in-stock in a test app. Since there is no un-publishing versions in NPM this ensures our new features work and protects against {sometimes 🙋 } forgetting to build before publishing.

Finally, runnpm publish and done! You can catch me onVendure slack for more)

Top comments(0)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

on a qwik vendure adventure
  • Location
    Queens, New York
  • Work
    open-source software developer
  • Joined

More fromprasanna malla

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp