import { OrderModel } from '../../models/order.entity'; import { IServiceOrderAttr } from '../../interfaces/service-order-attr.interface'; import { Order } from '../order/order'; import { ServiceOrderRepository } from './service-order.repository'; import { LoginUser } from '@tomei/sso'; import { ServiceItem } from '../service-item/service-item'; import { ServiceItemRepository } from '../service-item/service-item.repository'; import { ApplicationConfig } from '@tomei/config'; import { ActionEnum, Activity } from '@tomei/activity-history'; import { OrderItemModel } from '../../models/order-item.entity'; import { ClassError } from '@tomei/general'; import { OrderStatusEnum } from '../../enums/order-status.enum'; export class ServiceOrder extends Order { TotalItems: number = 0; TotalItemsPending: number = 0; TotalItemsInProgress: number = 0; TotalItemsDone: number = 0; ServiceItems: ServiceItem[] = []; private static _ServiceOrderRepo = new ServiceOrderRepository(); private static _ServiceItemRepo = new ServiceItemRepository(); constructor(serviceOrderAttr?: IServiceOrderAttr) { super(serviceOrderAttr); if (serviceOrderAttr) { this.TotalItems = serviceOrderAttr.TotalItems; this.TotalItemsPending = serviceOrderAttr.TotalItemsPending; this.TotalItemsInProgress = serviceOrderAttr.TotalItemsInProgress; this.TotalItemsDone = serviceOrderAttr.TotalItemsDone; } } static async init(OrderNo?: string, dbTransaction?: any) { if (OrderNo) { const storeData = await ServiceOrder._ServiceOrderRepo.findByPk(OrderNo, { transaction: dbTransaction, include: [ { model: OrderModel, }, ], }); if (storeData) { return new ServiceOrder({ ...storeData?.get({ plain: true }), ...storeData.Order?.get({ plain: true }), }); } else { throw Error('ServiceOrder not found.'); } } return new ServiceOrder(); } public async addServiceItem( loginUser: LoginUser, dbTransaction: any, serviceItem: ServiceItem, ) { try { //This method will add service item to the service order. // Set ServiceItem.OrderNo = this._OrderNo serviceItem.OrderNo = this.OrderNo; // Set this._TotalItems = this._TotalItems + 1 this.TotalItems += 1; // Set this._TotalItemsPending = this._TotalItems (*here TotalItems already updated) this.TotalItemsPending += 1; //Append Params.serviceItem to this._ServiceItems. this.ServiceItems.push(serviceItem); // Return ServiceItem. return serviceItem; } catch (error) { throw new Error(error.message); } } public async confirmOrder( loginUser: LoginUser, dbTransaction: any, items: ServiceItem[], ) { //This method will create service order and service items. try { // Part 1: Check Privileges const systemCode = ApplicationConfig.getComponentConfigValue('system-code'); const isPrivileged = await loginUser.checkPrivileges( systemCode, 'Order - Create', ); if (!isPrivileged) { throw new Error('You do not have permission to create ServiceOrder.'); } //Part 3: Create Service Order //Set class properties this.Status = OrderStatusEnum.CONFIRMED; this.CreatedById = loginUser.ObjectId; this.CreatedAt = new Date(); this.UpdatedById = loginUser.ObjectId; this.UpdatedAt = new Date(); //Using OrderRepo and ServiceOrderRepo, insert both record by populating the table attributes. await ServiceOrder._OrderRepo.create( { OrderNo: this.OrderNo, CustomerId: this.CustomerId, OrderType: this.OrderType, Platform: this.Platform, PlatformRefNo: this.PlatformRefNo, Date: this.Date, Amount: this.Amount, Currency: this.Currency, DeliveryMethod: this.DeliveryMethod, Status: this.Status, AllowDepositYN: this.AllowDepositYN, DepositAmount: this.DepositAmount, CancellationType: this.CancellationType, CancellationReasonCode: this.CancellationReasonCode, CancellationById: this.CancellationById, CancellationByName: this.CancellationByName, CancellationDate: this.CancellationDate, DiscountPercentage: this.DiscountPercentage, CreatedById: this.CreatedById, CreatedAt: this.CreatedAt, UpdatedById: this.UpdatedById, UpdatedAt: this.UpdatedAt, }, { transaction: dbTransaction, }, ); await ServiceOrder._ServiceOrderRepo.create( { OrderNo: this.OrderNo, TotalItems: this.TotalItems, TotalItemsPending: this.TotalItemsPending, TotalItemsInProgress: this.TotalItemsInProgress, TotalItemsDone: this.TotalItemsDone, ServiceItems: this.ServiceItems, }, { transaction: dbTransaction, }, ); //Part 4: Record Create Service Order Activity //Set EntityValueAfter with the new service order properties const entityValueAfter = { OrderNo: this.OrderNo, CustomerId: this.CustomerId, OrderType: this.OrderType, Platform: this.Platform, PlatformRefNo: this.PlatformRefNo, Date: this.Date, Amount: this.Amount, Currency: this.Currency, DeliveryMethod: this.DeliveryMethod, Status: this.Status, AllowDepositYN: this.AllowDepositYN, DepositAmount: this.DepositAmount, CancellationType: this.CancellationType, CancellationReasonCode: this.CancellationReasonCode, CancellationById: this.CancellationById, CancellationByName: this.CancellationByName, CancellationDate: this.CancellationDate, DiscountPercentage: this.DiscountPercentage, CreatedById: this.CreatedById, CreatedAt: this.CreatedAt, UpdatedById: this.UpdatedById, UpdatedAt: this.UpdatedAt, Items: this.ServiceItems, Customer: this.Customer, }; //Initialize Activity class and fill in the required properties const activity = new Activity(); activity.ActivityId = activity.createId(); activity.Action = ActionEnum.CREATE; activity.Description = `Create Service Order`; activity.EntityType = 'ServiceOrder'; activity.EntityId = this.OrderNo; activity.EntityValueBefore = JSON.stringify({}); activity.EntityValueAfter = JSON.stringify(entityValueAfter); //Call the create method to record the activity history await activity.create(loginUser.ObjectId, dbTransaction); //Part 5: Create Service Order Items //For each item in Params.Items, insert both record by populating the table attributes for (const item of items) { await item.create(loginUser, dbTransaction); } return this; } catch (error) { throw error; } } public async getServiceitems(loginUser: LoginUser, dbTransaction: any) { //This method will fill service item property in service order try { //Part 1: Check Privilege const systemCode = ApplicationConfig.getComponentConfigValue('system-code'); const isPrivileged = await loginUser.checkPrivileges( systemCode, 'Order - View', ); if (!isPrivileged) { throw new Error('You do not have permission to create OrderItem.'); } //Part 2: Retrieve Service Items //Using service item repo, retrieve service item and order item data by orderNo using ServiceItemRepo.findAll const data = await ServiceOrder._ServiceItemRepo.findAll({ include: [ { model: OrderItemModel, where: { OrderNo: this.OrderNo, }, }, ], transaction: dbTransaction, }); //Map retrieved data to service item object const serviceItems = data.map((item) => { return new ServiceItem({ ...item?.get({ plain: true }), ...item.OrderItem?.get({ plain: true }), }); }); //Set ServiceItems property with result from previous step this.ServiceItems = serviceItems; } catch (error) { throw error; } } public async update(loginUser: LoginUser, dbTransaction: any) { try { await super.update(loginUser, dbTransaction); const oldServiceOrder = await ServiceOrder._ServiceOrderRepo.findByPk( this.OrderNo, { transaction: dbTransaction, }, ); const EntityValueBefore = { ...oldServiceOrder?.get({ plain: true }), }; const payload = { TotalItems: this.TotalItems, TotalItemsPending: this.TotalItemsPending, TotalItemsInProgress: this.TotalItemsInProgress, TotalItemsDone: this.TotalItemsDone, }; await ServiceOrder._ServiceOrderRepo.update(payload, { where: { OrderNo: this.OrderNo, }, transaction: dbTransaction, }); const EntityValueAfter = { ...oldServiceOrder?.get({ plain: true }), ...payload, }; const activity = new Activity(); activity.ActivityId = activity.createId(); activity.Action = ActionEnum.UPDATE; activity.Description = `Update Service Order ${this.OrderNo}`; activity.EntityType = 'ServiceOrder'; activity.EntityId = this.OrderNo; activity.EntityValueBefore = JSON.stringify(EntityValueBefore); activity.EntityValueAfter = JSON.stringify(EntityValueAfter); await activity.create(loginUser.ObjectId, dbTransaction); } catch (error) { throw error; } } async markItemInProgress( loginUser: LoginUser, dbTransaction: any, ): Promise { try { if (this.Status == OrderStatusEnum.CONFIRMED) { await super.setProcessing(loginUser, dbTransaction); } this.TotalItemsPending -= 1; this.TotalItemsInProgress += 1; const entityValueBefore = { OrderNo: this.OrderNo, TotalItems: this.TotalItems, TotalItemsPending: this.TotalItemsPending, TotalItemsInProgress: this.TotalItemsInProgress, TotalItemsDone: this.TotalItemsDone, }; const payload = { TotalItemsPending: this.TotalItemsPending, TotalItemsInProgress: this.TotalItemsInProgress, }; await ServiceOrder._ServiceOrderRepo.update(payload, { where: { OrderNo: this.OrderNo, }, transaction: dbTransaction, }); const entityValueAfter = { OrderNo: this.OrderNo, TotalItems: this.TotalItems, TotalItemsPending: this.TotalItemsPending, TotalItemsInProgress: this.TotalItemsInProgress, TotalItemsDone: this.TotalItemsDone, }; const activity = new Activity(); activity.ActivityId = activity.createId(); activity.Action = ActionEnum.UPDATE; activity.Description = `Mark Service Order ${this.OrderNo} Item to In Progress`; activity.EntityType = 'ServiceOrder'; activity.EntityId = this.OrderNo; activity.EntityValueBefore = JSON.stringify(entityValueBefore); activity.EntityValueAfter = JSON.stringify(entityValueAfter); await activity.create(loginUser.ObjectId, dbTransaction); } catch (error) { throw error; } } async markItemDone(loginUser: LoginUser, dbTransaction: any): Promise { try { if (this.TotalItemsInProgress > 0) { this.TotalItemsInProgress -= 1; } else { this.TotalItemsPending -= 1; } this.TotalItemsDone += 1; const entityValueBefore = { OrderNo: this.OrderNo, TotalItems: this.TotalItems, TotalItemsPending: this.TotalItemsPending, TotalItemsInProgress: this.TotalItemsInProgress, TotalItemsDone: this.TotalItemsDone, }; const payload = { TotalItemsInProgress: this.TotalItemsInProgress, TotalItemsDone: this.TotalItemsDone, }; await ServiceOrder._ServiceOrderRepo.update(payload, { where: { OrderNo: this.OrderNo, }, transaction: dbTransaction, }); const entityValueAfter = { ...entityValueBefore, ...payload, }; const activity = new Activity(); activity.ActivityId = activity.createId(); activity.Action = ActionEnum.UPDATE; activity.Description = `Mark Service Order ${this.OrderNo} Item to Done`; activity.EntityType = 'ServiceOrder'; activity.EntityId = this.OrderNo; activity.EntityValueBefore = JSON.stringify(entityValueBefore); activity.EntityValueAfter = JSON.stringify(entityValueAfter); await activity.create(loginUser.ObjectId, dbTransaction); } catch (error) { throw error; } } async setPendingCollection( loginUser: LoginUser, dbTransaction: any, ): Promise { try { if (this.TotalItemsDone !== this.TotalItems) { throw new ClassError( 'ServiceOrder', 'ServiceOrderErrMsg0X', 'All job must be done before order ready to be collected.', 'setPendingCollection', 400, ); } await super.setPendingCollection(loginUser, dbTransaction); } catch (error) { throw error; } } async unMarkItemDone( loginUser: LoginUser, dbTransaction: any, ): Promise { try { this.TotalItemsDone -= 1; this.TotalItemsInProgress += 1; const entityValueBefore = { OrderNo: this.OrderNo, TotalItems: this.TotalItems, TotalItemsPending: this.TotalItemsPending, TotalItemsInProgress: this.TotalItemsInProgress, TotalItemsDone: this.TotalItemsDone, }; const payload = { TotalItemsInProgress: this.TotalItemsInProgress, TotalItemsDone: this.TotalItemsDone, }; await ServiceOrder._ServiceOrderRepo.update(payload, { where: { OrderNo: this.OrderNo, }, transaction: dbTransaction, }); const entityValueAfter = { ...entityValueBefore, ...payload, }; const activity = new Activity(); activity.ActivityId = activity.createId(); activity.Action = ActionEnum.UPDATE; activity.Description = `Unmark Service Order ${this.OrderNo} Item from Done to In Progress`; activity.EntityType = 'ServiceOrder'; activity.EntityId = this.OrderNo; activity.EntityValueBefore = JSON.stringify(entityValueBefore); activity.EntityValueAfter = JSON.stringify(entityValueAfter); await activity.create(loginUser.ObjectId, dbTransaction); } catch (error) { throw error; } } }