@tomei/product
Version:
NestJS package for product module
592 lines (538 loc) • 18.6 kB
text/typescript
import { ProductWithInventoryBase } from '../../base/product-with-inventory/product-with-inventory.base';
import { ClassError, RecordNotFoundError } from '@tomei/general';
import { ProductJewelleryRepository } from './jewellery-product.repository';
import { IJewelleryProductAttr } from '../../interfaces/product-jewellery-attr.interface';
import { ProductWithInventoryModel } from '../../entities/product-with-inventory.entity';
import { ProductJewelleryModel } from '../../entities/product-jewellery.entity';
import { ProductModel } from '../../entities/product.entity';
import cuid from '../../helpers/cuid';
import { LoginUser } from '@tomei/sso';
import { StockProfileModel, StockProfile } from '@tomei/stock';
import { Op } from 'sequelize';
import { ActionEnum, Activity } from '@tomei/activity-history';
import { SettingsCategoryModel } from '../../entities/settings-category.entity';
import { SettingsCollectionModel } from '../../entities/settings-collection.entity';
import { SettingsGroupModel } from '../../entities/settings-group.entity';
import { ProductCertificateModel } from '../../entities/product-certificate.entity';
import { ProductTagModel } from '../../entities/product-tag.entity';
import { ProductBrandModel } from '../../entities/product-brand.entity';
import { ProductCustomizeOptionModel } from '../../entities/product-customize-option.entity';
import { ProductMaterialModel } from '../../entities/product-material.entity';
import { IProductVariantCreate } from '../../interfaces/product-variant-create.interface';
import { ProductVariantWithInventory } from '../variant-product-with-inventory/variant-product-with-inventory';
import { ProductVariantType } from '../../enum/product-variant.enum';
interface IProductJewelleryInitParam {
productId?: string;
productInfo?: IJewelleryProductAttr;
}
export class ProductJewellery extends ProductWithInventoryBase {
ObjectType = 'ProductJewellery';
private _ProfileId: string;
private _Surface: string;
private _Uniqueness: string;
private _HasCertificateYN = 'N';
private static _ProductJewelleryRepository = new ProductJewelleryRepository();
get ProductId() {
return super.ProductId;
}
set ProductId(productId: string) {
super.ProductId = productId;
}
get ProfileId() {
return this._ProfileId;
}
private set ProfileId(id: string) {
this._ProfileId = id;
}
get Surface() {
return this._Surface;
}
set Surface(surface: string) {
this._Surface = surface;
}
get Uniqueness() {
return this._Uniqueness;
}
set Uniqueness(uniqueness: string) {
this._Uniqueness = uniqueness;
}
get HasCertificateYN() {
return this._HasCertificateYN;
}
set HasCertificateYN(hasCertificateYN: string) {
this._HasCertificateYN = hasCertificateYN;
}
get UOM() {
return super.UOM;
}
get TotalUnits() {
return super.TotalUnits;
}
get TotalUnitsAvailable() {
return super.TotalUnitsAvailable;
}
get TotalUnitsInCurrentOrder() {
return super.TotalUnitsInCurrentOrder;
}
get TotalUnitsSold() {
return super.TotalUnitsSold;
}
get TotalUnitsReserved() {
return super.TotalUnitsReserved;
}
get TotalUnitsOnConsignment() {
return super.TotalUnitsOnConsignment;
}
get TotalUnitsUnderMaintenance() {
return super.TotalUnitsUnderMaintenance;
}
get TotalUnitsVoid() {
return super.TotalUnitsVoid;
}
get TotalUnitsInTransit() {
return super.TotalUnitsInTransit;
}
get TotalUnitsBackOrdered() {
return super.TotalUnitsBackOrdered;
}
get TotalUnitsPreOrdered() {
return super.TotalUnitsPreOrdered;
}
get StockLowAlertLevel() {
return super.StockLowAlertLevel;
}
get StockReorderLevel() {
return super.StockReorderLevel;
}
get BufferStockLevel() {
return super.BufferStockLevel;
}
protected constructor(productJewelleryAttr) {
super(productJewelleryAttr);
this._ProfileId = productJewelleryAttr.ProfileId;
this._Surface = productJewelleryAttr.Surface;
this._Uniqueness = productJewelleryAttr.Uniqueness;
this._HasCertificateYN = productJewelleryAttr.HasCertificateYN;
}
static async init(
options: IProductJewelleryInitParam,
): Promise<ProductJewellery> {
try {
const { productId, productInfo } = options;
if (productId) {
const product =
await ProductJewellery._ProductJewelleryRepository.findOne({
where: {
ProductId: productId,
},
include: [
{
model: ProductWithInventoryModel,
include: [
{
model: ProductModel,
},
],
},
],
});
const productAttr: IJewelleryProductAttr = {
ProductId: product.ProductId,
Name: product.ProductWithInventory.Product.Name,
Description: product.ProductWithInventory.Product.Description,
SKU: product.ProductWithInventory.Product.SKU,
Type: product.ProductWithInventory.Product.Type,
Remark: product.ProductWithInventory.Product.Remark,
IsTaxableYN: product.ProductWithInventory.Product.IsTaxableYN,
TaxCode: product.ProductWithInventory.Product.TaxCode,
IsPriceInclusiveTaxYN:
product.ProductWithInventory.Product.IsPriceInclusiveTaxYN,
Status: product.ProductWithInventory.Product.Status,
VerifiedYN: product.ProductWithInventory.Product.VerifiedYN,
VerifiedById: product.ProductWithInventory.Product.VerifiedById,
VerifiedAt: product.ProductWithInventory.Product.VerifiedAt,
VariantLevels: product.ProductWithInventory.Product.VariantLevels,
VariantTypeLevel1:
product.ProductWithInventory.Product.VariantTypeLevel1,
VariantTypeLevel2:
product.ProductWithInventory.Product.VariantTypeLevel2,
VariantTypeLevel3:
product.ProductWithInventory.Product.VariantTypeLevel3,
CreatedById: product.ProductWithInventory.Product.CreatedById,
CreatedAt: product.ProductWithInventory.Product.CreatedAt,
UpdatedById: product.ProductWithInventory.Product.UpdatedById,
UpdatedAt: product.ProductWithInventory.Product.UpdatedAt,
UpdatedSSYN: product.ProductWithInventory.Product.UpdatedSSYN,
UOM: product.ProductWithInventory.UOM,
TotalUnits: product.ProductWithInventory.TotalUnits,
TotalUnitsAvailable: product.ProductWithInventory.TotalUnitsAvailable,
TotalUnitsInCurrentOrder:
product.ProductWithInventory.TotalUnitsInCurrentOrder,
TotalUnitsSold: product.ProductWithInventory.TotalUnitsSold,
TotalUnitsReserved: product.ProductWithInventory.TotalUnitsReserved,
TotalUnitsOnConsignment:
product.ProductWithInventory.TotalUnitsOnConsignment,
TotalUnitsUnderMaintenance:
product.ProductWithInventory.TotalUnitsUnderMaintenance,
TotalUnitsVoid: product.ProductWithInventory.TotalUnitsVoid,
TotalUnitsInTransit: product.ProductWithInventory.TotalUnitsInTransit,
TotalUnitsBackOrdered:
product.ProductWithInventory.TotalUnitsBackOrdered,
TotalUnitsPreOrdered:
product.ProductWithInventory.TotalUnitsPreOrdered,
StockLowAlertLevel: product.ProductWithInventory.StockLowAlertLevel,
StockReorderLevel: product.ProductWithInventory.StockReorderLevel,
BufferStockLevel: product.ProductWithInventory.BufferStockLevel,
ProfileId: product.ProfileId,
Surface: product.Surface,
Uniqueness: product.Uniqueness,
HasCertificateYN: product.HasCertificateYN,
PreviousSKU: product.ProductWithInventory.Product.PreviousSKU,
};
if (productAttr) {
const productJewellery = new ProductJewellery(productAttr);
return productJewellery;
} else {
throw Error('ProductId not found.');
}
} else {
if (!productInfo) {
throw Error('Product info is required.');
}
return new ProductJewellery(productInfo);
}
} catch (err) {
throw Error('Failed to instantiate ProductJewellery.');
}
}
async create(
loginUser: LoginUser,
dbTransaction: any,
profileId?: string,
): Promise<any> {
try {
if (!profileId) {
throw new Error('ProfileId is required.');
}
let stockProfile: StockProfile;
try {
stockProfile = await StockProfile.init(profileId);
} catch (error) {
if (error.message && error.message === 'ProfileId not found') {
throw new RecordNotFoundError(
'ProductJewelleryErrMsg01',
'Stock Profile not found. Please create Stock Profile first.',
);
} else {
throw error;
}
}
this.ProfileId = stockProfile.ProfileId;
const parentData = await super.create(loginUser, dbTransaction);
const data = await ProductJewellery._ProductJewelleryRepository.create(
{
ProfileId: this._ProfileId,
ProductId: parentData.ProductId,
Surface: this._Surface,
Uniqueness: this._Uniqueness,
HasCertificateYN: this._HasCertificateYN,
},
{
transaction: dbTransaction,
},
);
const entityValueAfter = data.get({ plain: true });
const activity = new Activity();
activity.ActivityId = cuid();
activity.Action = ActionEnum.CREATE;
activity.Description = 'Add new product with inventory';
activity.EntityType = 'ProductWithInventory';
activity.EntityId = data.ProductId;
activity.EntityValueBefore = JSON.stringify({});
activity.EntityValueAfter = JSON.stringify(entityValueAfter);
await activity.create(loginUser.ObjectId, dbTransaction);
} catch (error) {
throw error;
}
}
static async findAll(
loginUser: LoginUser,
dbTransaction?: any,
searchOptions?: { page: any; rows: any; search: any },
): Promise<
ProductJewelleryModel[] | { rows: ProductJewelleryModel[]; count: number }
> {
try {
await super.findAll(loginUser);
if (searchOptions.page && searchOptions.rows) {
const offset = searchOptions.rows * (searchOptions.page - 1);
let searchObj: any;
try {
searchObj = searchOptions.search
? JSON.parse(searchOptions.search)
: {};
} catch (err) {
throw new Error('Bad value for search.');
}
const {
StoreId,
CategoryCode,
CollectionCode,
CertificateId,
GroupCode,
Brand,
TagId,
CustomizeOptionId,
MaterialId,
...prodFilter
} = searchObj;
const productQueryObj = {};
Object.entries(prodFilter).forEach(([key, value]) => {
productQueryObj[key] = {
[Op.substring]: value,
};
});
return await ProductJewellery._ProductJewelleryRepository.findAllWithPagination(
{
productQuery: {
whereProduct: productQueryObj,
StoreId,
CategoryCode,
CollectionCode,
CertificateId,
GroupCode,
Brand,
TagId,
CustomizeOptionId,
MaterialId,
},
rows: searchOptions.rows,
offset,
transaction: dbTransaction,
},
);
} else {
return await ProductJewellery._ProductJewelleryRepository.findAll(
dbTransaction,
);
}
} catch (error) {
throw error;
}
}
public async update(
loginUser: LoginUser,
productInfo?: IJewelleryProductAttr,
dbTransaction?: any,
): Promise<any> {
try {
const updatedInfo = await super.update(
loginUser,
productInfo,
dbTransaction,
);
return updatedInfo;
} catch (error) {
throw error;
}
}
public async deactivate(
loginUser: LoginUser,
dbTransaction?: any,
): Promise<void> {
super.deactivate(loginUser, dbTransaction);
}
public async verify(
loginUser: LoginUser,
dbTransaction?: any,
): Promise<void> {
try {
await super.verify(loginUser, dbTransaction);
} catch (error) {
throw error;
}
}
public async delete(
loginUser: LoginUser,
dbTransaction?: any,
): Promise<void> {
try {
await super.delete(loginUser, dbTransaction);
} catch (error) {
throw error;
}
}
public async activate(
loginUser: LoginUser,
dbTransaction?: any,
): Promise<void> {
try {
await super.activate(loginUser, dbTransaction);
} catch (error) {
throw error;
}
}
static async findOne(
options: any,
dbTransaction?: any,
): Promise<ProductJewelleryModel> {
try {
//check if option string
const dbOptions =
typeof options !== 'string'
? options
: {
where: {
ProductId: options,
},
include: [
{
model: ProductWithInventoryModel,
include: [
{
model: ProductModel,
include: [
{
model: SettingsCategoryModel,
attributes: ['Code', 'Name', 'Description', 'Status'],
},
{
model: SettingsCollectionModel,
attributes: ['Code', 'Name', 'Description', 'Status'],
},
{
model: SettingsGroupModel,
attributes: ['Code', 'Name', 'Description', 'Status'],
},
{ model: ProductCertificateModel },
{ model: ProductTagModel },
{ model: ProductBrandModel },
{ model: ProductCustomizeOptionModel },
{ model: ProductMaterialModel },
{
model: SettingsGroupModel,
},
],
},
],
},
{
model: StockProfileModel,
},
],
};
return await ProductJewellery._ProductJewelleryRepository.findOne({
...dbOptions,
transaction: dbTransaction,
});
} catch (error) {
throw error;
}
}
public async addVariant(
addVariantInfo: IProductVariantCreate,
loginUser: LoginUser,
dbTransaction?: any,
) {
try {
const product = await ProductJewellery._Repository.findOne({
where: {
SKU: addVariantInfo.SKU,
},
transaction: dbTransaction,
});
if (product) {
throw new ClassError(
'ProductVariant',
'ProductVariantErrMsg03',
'SKU must be unique.',
);
}
const variant = await ProductVariantWithInventory.init();
variant.ProductId = this.ProductId;
variant.Name = addVariantInfo.Name;
variant.Description = addVariantInfo.Description;
variant.Type = addVariantInfo.Type;
variant.Level = addVariantInfo.Level;
variant.StockLowAlertLevel = addVariantInfo.StockLowAlertLevel;
variant.StockReorderLevel = addVariantInfo.StockReorderLevel;
variant.BufferStockLevel = addVariantInfo.BufferStockLevel;
await variant.setSKU(addVariantInfo.SKU);
await variant.setParentId(addVariantInfo.ParentId);
await variant.setColour(addVariantInfo.Colour);
await variant.setSize(addVariantInfo.Size);
switch (variant.Type) {
case ProductVariantType.HEIGHT:
await variant.setMinMax(
variant.Type,
addVariantInfo.MinHeight,
addVariantInfo.MaxHeight,
);
break;
case ProductVariantType.LENGTH:
await variant.setMinMax(
variant.Type,
addVariantInfo.MinLength,
addVariantInfo.MaxLength,
);
break;
case ProductVariantType.WIDTH:
await variant.setMinMax(
variant.Type,
addVariantInfo.MinWidth,
addVariantInfo.MaxWidth,
);
break;
case ProductVariantType.WEIGHT:
await variant.setMinMax(
variant.Type,
addVariantInfo.MinWeight,
addVariantInfo.MaxWeight,
);
break;
default:
break;
}
await variant.create(loginUser, dbTransaction);
return {
VariantId: variant.VariantId,
ProductId: variant.ProductId,
Name: variant.Name,
Description: variant.Description,
SKU: variant.SKU,
Size: variant.Size,
Colour: variant.Colour,
Type: variant.Type,
Level: variant.Level,
ParentId: variant.ParentId,
MinWeight: variant.MinWeight,
MaxWeight: variant.MaxWeight,
MinWidth: variant.MinWidth,
MaxWidth: variant.MaxWidth,
MinHeight: variant.MinHeight,
MaxHeight: variant.MaxHeight,
MinLength: variant.MinLength,
MaxLength: variant.MaxLength,
Status: variant.Status,
CreatedById: variant.CreatedById,
CreatedAt: variant.CreatedAt,
UpdatedById: variant.UpdatedById,
UpdatedAt: variant.UpdatedAt,
UpdatedSSYN: variant.UpdatedSSYN,
TotalUnitsAvailable: variant.TotalUnitsAvailable,
TotalUnitsInCurrentOrder: variant.TotalUnitsInCurrentOrder,
TotalUnitsSold: variant.TotalUnitsSold,
TotalUnitsReserved: variant.TotalUnitsReserved,
TotalUnitsInTransit: variant.TotalUnitsInTransit,
TotalUnitsOnConsignment: variant.TotalUnitsOnConsignment,
TotalUnitsBackOrdered: variant.TotalUnitsBackOrdered,
TotalUnitsPreOrdered: variant.TotalUnitsPreOrdered,
StockLowAlertLevel: variant.StockLowAlertLevel,
StockReorderLevel: variant.StockReorderLevel,
BufferStockLevel: variant.BufferStockLevel,
};
} catch (error) {
throw error;
}
}
}