You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
409 lines
12 KiB
409 lines
12 KiB
/* eslint-disable camelcase */
|
|
import httpStatus from 'http-status';
|
|
import { Model, DataTypes, Op } from 'sequelize';
|
|
import { isEqual, isNil, isUndefined, omitBy, pick } from 'lodash';
|
|
import moment from 'moment-timezone';
|
|
|
|
import { serviceName } from '../../config/vars';
|
|
import postgres from '../../config/postgres';
|
|
import APIError from '../utils/APIException';
|
|
|
|
/**
|
|
* Create connection
|
|
*/
|
|
const { sequelize } = postgres;
|
|
class FileConfig extends Model { }
|
|
|
|
const PUBLIC_FIELDS = [
|
|
'name',
|
|
'type',
|
|
'group',
|
|
'config'
|
|
];
|
|
|
|
FileConfig.Groups = {
|
|
PRODUCT: 'product',
|
|
PRODUCT_OPTION: 'product-option',
|
|
PRODUCT_PRICE: 'product-price',
|
|
ORDER: 'order',
|
|
ORDER_NESTED: 'order-nested',
|
|
INVOICE: 'invoice',
|
|
INVOICE_NESTED: 'invoice-nested',
|
|
RETURN: 'return',
|
|
RETURN_NESTED: 'return-nested',
|
|
DELIVERY: 'delivery',
|
|
IMPORT: 'import',
|
|
IMPORT_NESTED: 'import-nested',
|
|
STOCK_TAKE: 'stock-take',
|
|
STOCK_TAKE_NESTED: 'stock-take-nested',
|
|
TRANSFER: 'transfer',
|
|
TRANSFER_NESTED: 'transfer-nested',
|
|
EXPORT: 'export',
|
|
EXPORT_NESTED: 'export-nested',
|
|
PAYMENT: 'payment',
|
|
CUSTOMER: 'customer',
|
|
SUPPLIER: 'supplier',
|
|
DELIVERY_PAYMENT: 'delivery-payment',
|
|
DELIVERY_PAYMENT_NESTED: 'delivery-payment-nested',
|
|
/** Sale Report */
|
|
SALE_REPORT_TIME: 'sale-report-time',
|
|
SALE_REPORT_TIME_NESTED: 'sale-report-time-nested',
|
|
SALE_REPORT_TIME_INVOICE: 'sale-report-time-invoice',
|
|
SALE_REPORT_PROFIT: 'sale-report-profit',
|
|
SALE_REPORT_PROFIT_NESTED: 'sale-report-profit-nested',
|
|
SALE_REPORT_PROFIT_INVOICE: 'sale-report-profit-invoice',
|
|
SALE_REPORT_PROFIT_PRODUCT: 'sale-report-profit-product',
|
|
SALE_REPORT_DISCOUNT: 'sale-report-discount',
|
|
SALE_REPORT_DISCOUNT_NESTED: 'sale-report-discount-nested',
|
|
SALE_REPORT_DISCOUNT_INVOICE: 'sale-report-discount-invoice',
|
|
SALE_REPORT_RETURN: 'sale-report-return',
|
|
SALE_REPORT_RETURN_NESTED: 'sale-report-return-nested',
|
|
SALE_REPORT_RETURN_INVOICE: 'sale-report-return-invoice',
|
|
SALE_REPORT_STAFF: 'sale-report-staff',
|
|
SALE_REPORT_STAFF_NESTED: 'sale-report-staff-nested',
|
|
SALE_REPORT_STAFF_TIME: 'sale-report-staff-time',
|
|
SALE_REPORT_STAFF_TIME_NESTED: 'sale-report-staff-time-nested',
|
|
SALE_REPORT_STAFF_INVOICE: 'sale-report-staff-invoice',
|
|
SALE_REPORT_STORE: 'sale-report-store',
|
|
SALE_REPORT_STORE_NESTED: 'sale-report-store-nested',
|
|
SALE_REPORT_STORE_TIME: 'sale-report-store-time',
|
|
SALE_REPORT_STORE_TIME_NESTED: 'sale-report-store-time-nested',
|
|
SALE_REPORT_STORE_INVOICE: 'sale-report-store-invoice',
|
|
|
|
/** product report */
|
|
PRODUCT_REPORT_SALE: 'product-report-sale',
|
|
PRODUCT_REPORT_SALE_SPECIFIC: 'product-report-sale-specific',
|
|
PRODUCT_REPORT_SALE_GROUP_CATEGORIES: 'product-report-sale-group-categories',
|
|
PRODUCT_REPORT_SALE_DETAIL: 'product-report-sale-detail',
|
|
|
|
PRODUCT_REPORT_PROFIT: 'product-report-profit',
|
|
PRODUCT_REPORT_PROFIT_GROUP_CATEGORIES: 'product-report-profit-group-categories',
|
|
|
|
PRODUCT_REPORT_STOCK_VALUE: 'product-report-stock-value',
|
|
PRODUCT_REPORT_STOCK_VALUE_GROUP_CATEGORIES: 'product-report-stock-value-group-categories',
|
|
PRODUCT_REPORT_STOCK_VALUE_DETAIL: 'product-report-stock-value-detail',
|
|
PRODUCT_REPORT_STOCK_VALUE_STORE: 'product-report-stock-value-store',
|
|
PRODUCT_REPORT_STOCK_VALUE_GENERAL: 'product-report-stock-value-general',
|
|
|
|
PRODUCT_REPORT_STOCK: 'product-report-stock',
|
|
PRODUCT_REPORT_STOCK_STORE: 'product-report-stock-store',
|
|
PRODUCT_REPORT_STOCK_ONE_STORE: 'product-report-stock-one-store',
|
|
PRODUCT_REPORT_STOCK_GROUP_CATEGORIES: 'product-report-stock-group-categories',
|
|
PRODUCT_REPORT_STOCK_MORE_STORE: 'product-report-stock-more-store',
|
|
|
|
PRODUCT_REPORT_STOCK_DETAIL: 'product-report-stock-detail',
|
|
PRODUCT_REPORT_STOCK_DETAIL_STORE: 'product-report-stock-detail-store',
|
|
PRODUCT_REPORT_STOCK_DETAIL_DETAIL: 'product-report-stock-detail-detail',
|
|
PRODUCT_REPORT_STOCK_DETAIL_GROUP_CATEGORIES: 'product-report-stock-detail-group-categories',
|
|
PRODUCT_REPORT_STOCK_DETAIL_GENERAL: 'product-report-stock-detail-general',
|
|
|
|
PRODUCT_REPORT_STAFF: 'product-report-staff',
|
|
PRODUCT_REPORT_STAFF_SPECIFIC: 'product-report-staff-specific',
|
|
PRODUCT_REPORT_STAFF_DETAIL: 'product-report-staff-detail',
|
|
PRODUCT_REPORT_STAFF_GROUP_CATEGORIES: 'product-report-staff-group-categories',
|
|
|
|
PRODUCT_REPORT_EXPORT: 'product-report-export',
|
|
PRODUCT_REPORT_EXPORT_SPECIFIC: 'product-report-export-specific',
|
|
PRODUCT_REPORT_EXPORT_DETAIL: 'product-report-export-detail',
|
|
PRODUCT_REPORT_EXPORT_GROUP_CATEGORIES: 'product-report-export-group-categories',
|
|
|
|
PRODUCT_REPORT_CUSTOMER: 'product-report-customer',
|
|
PRODUCT_REPORT_CUSTOMER_SPECIFIC: 'product-report-customer-specific',
|
|
PRODUCT_REPORT_CUSTOMER_DETAIL: 'product-report-customer-detail',
|
|
PRODUCT_REPORT_CUSTOMER_GROUP_CATEGORIES: 'product-report-customer-group-categories',
|
|
|
|
PRODUCT_REPORT_SUPPLIER: 'product-report-supplier',
|
|
PRODUCT_REPORT_SUPPLIER_DETAIL: 'product-report-supplier-detail',
|
|
PRODUCT_REPORT_SUPPLIER_SPECIFIC: 'product-report-supplier-specific',
|
|
PRODUCT_REPORT_SUPPLIER_GROUP_CATEGORIES: 'product-report-supplier-group-categories',
|
|
|
|
PRODUCT_REPORT_STOCK_SPECIFIC: 'product-report-stock-specific',
|
|
PRODUCT_REPORT_STOCK_DETAIL_SPECIFIC: 'product-report-stock-detail-specific',
|
|
PRODUCT_REPORT_CUSTOMER_INVOICE: 'product-report-customer-invoice',
|
|
PRODUCT_REPORT_STAFF_INVOICE: 'product-report-staff-invoice',
|
|
|
|
/** start end of day report */
|
|
END_OF_DAY_REPORT_SALE: 'end-of-day-report-sale',
|
|
END_OF_DAY_REPORT_SALE_DETAIL: 'end-of-day-report-sale-detail',
|
|
END_OF_DAY_REPORT_SALE_DETAIL_TIME: 'end-of-day-report-sale-detail-time',
|
|
END_OF_DAY_REPORT_PAYMENT: 'end-of-day-report-payment',
|
|
END_OF_DAY_REPORT_PRODUCT: 'end-of-day-report-product',
|
|
END_OF_DAY_REPORT_PRODUCT_DETAIL: 'end-of-day-report-product-detail',
|
|
};
|
|
|
|
FileConfig.Types = {
|
|
IMPORT: 'import',
|
|
EXPORT: 'export'
|
|
};
|
|
|
|
FileConfig.Configs = [
|
|
'name', // file name,
|
|
'path', // file path,
|
|
'content', // file data
|
|
];
|
|
|
|
/**
|
|
* FileConfig Schema
|
|
* @public
|
|
*/
|
|
FileConfig.init(
|
|
{
|
|
id: {
|
|
type: DataTypes.INTEGER,
|
|
autoIncrement: true,
|
|
primaryKey: true
|
|
},
|
|
name: {
|
|
type: DataTypes.STRING(255),
|
|
defaultValue: null
|
|
},
|
|
type: {
|
|
type: DataTypes.STRING(50),
|
|
allowNull: false
|
|
},
|
|
group: {
|
|
type: DataTypes.STRING(100),
|
|
defaultValue: null
|
|
},
|
|
path: {
|
|
type: DataTypes.STRING(155),
|
|
defaultValue: null
|
|
},
|
|
config: {
|
|
type: DataTypes.JSONB,
|
|
defaultValue: null
|
|
},
|
|
|
|
// manager
|
|
is_active: {
|
|
type: DataTypes.BOOLEAN,
|
|
defaultValue: true
|
|
},
|
|
created_at: {
|
|
type: DataTypes.DATE,
|
|
defaultValue: DataTypes.NOW
|
|
},
|
|
updated_at: {
|
|
type: DataTypes.DATE,
|
|
defaultValue: DataTypes.NOW
|
|
},
|
|
created_by: {
|
|
type: DataTypes.JSONB,
|
|
defaultValue: null // id | name
|
|
},
|
|
|
|
},
|
|
{
|
|
timestamps: false,
|
|
schema: serviceName,
|
|
sequelize: sequelize,
|
|
modelName: 'file_config',
|
|
tableName: 'tbl_file_configs'
|
|
}
|
|
);
|
|
|
|
/**
|
|
* Register event emiter
|
|
*/
|
|
FileConfig.Events = {
|
|
FILE_CONFIG_CREATED: `${serviceName}.file-config.created`,
|
|
FILE_CONFIG_UPDATED: `${serviceName}.file-config.updated`,
|
|
FILE_CONFIG_DELETED: `${serviceName}.file-config.deleted`,
|
|
};
|
|
FileConfig.EVENT_SOURCE = `${serviceName}.file-config`;
|
|
|
|
/**
|
|
* Add your
|
|
* - pre-save hooks
|
|
* - validations
|
|
* - virtuals
|
|
*/
|
|
FileConfig.addHook('afterCreate', () => { });
|
|
|
|
FileConfig.addHook('afterUpdate', () => { });
|
|
|
|
FileConfig.addHook('afterDestroy', () => { });
|
|
|
|
/**
|
|
* Load query
|
|
* @param {*} params
|
|
*/
|
|
function filterConditions(params) {
|
|
const options = omitBy(params, isNil);
|
|
options.is_active = true;
|
|
|
|
// TODO: load condition
|
|
if (options.name) {
|
|
options.name = {
|
|
[Op.iLike]: `%${options.name}%`
|
|
};
|
|
}
|
|
|
|
return options;
|
|
}
|
|
|
|
/**
|
|
* Load sort query
|
|
* @param {*} sort_by
|
|
* @param {*} order_by
|
|
*/
|
|
function sortConditions({ sort_by, order_by }) {
|
|
let sort = null;
|
|
switch (sort_by) {
|
|
case 'created_at':
|
|
sort = ['created_at', order_by];
|
|
break;
|
|
case 'updated_at':
|
|
sort = ['updated_at', order_by];
|
|
break;
|
|
default: sort = ['created_at', 'DESC'];
|
|
break;
|
|
}
|
|
return sort;
|
|
}
|
|
|
|
/**
|
|
* Transform postgres model to expose object
|
|
*/
|
|
FileConfig.transform = (params) => {
|
|
const transformed = {};
|
|
const fields = [
|
|
'id',
|
|
'name',
|
|
'type',
|
|
'group',
|
|
'config',
|
|
'created_by'
|
|
];
|
|
fields.forEach((field) => {
|
|
transformed[field] = params[field];
|
|
});
|
|
|
|
// pipe date
|
|
const dateFields = [
|
|
'created_at',
|
|
'updated_at'
|
|
];
|
|
dateFields.forEach((field) => {
|
|
if (params[field]) {
|
|
transformed[field] = moment(params[field]).unix();
|
|
} else {
|
|
transformed[field] = null;
|
|
}
|
|
});
|
|
|
|
return transformed;
|
|
};
|
|
|
|
/**
|
|
* Get all changed properties
|
|
*/
|
|
FileConfig.getChangedProperties = ({ newModel, oldModel }) => {
|
|
const changedProperties = [];
|
|
const allChangableProperties = [
|
|
'name',
|
|
'type',
|
|
'group',
|
|
'config',
|
|
'status',
|
|
'status_name'
|
|
];
|
|
if (!oldModel) {
|
|
return allChangableProperties;
|
|
}
|
|
|
|
allChangableProperties.forEach((field) => {
|
|
if (
|
|
!isUndefined(newModel[field]) &&
|
|
!isEqual(newModel[field], oldModel[field])
|
|
) {
|
|
changedProperties.push(field);
|
|
}
|
|
});
|
|
|
|
return changedProperties;
|
|
};
|
|
|
|
/**
|
|
* Detail
|
|
*
|
|
* @public
|
|
* @param {string} group
|
|
*/
|
|
FileConfig.get = async (operation) => {
|
|
try {
|
|
const data = await FileConfig.findOne({
|
|
where: {
|
|
type: operation.type,
|
|
group: operation.group,
|
|
is_active: true
|
|
}
|
|
});
|
|
if (!data) {
|
|
throw new APIError({
|
|
status: httpStatus.NOT_FOUND,
|
|
message: 'Không tìm thấy file!'
|
|
});
|
|
}
|
|
return data;
|
|
} catch (ex) {
|
|
throw ex;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* List users in descending order of 'createdAt' timestamp.
|
|
*
|
|
* @param {number} skip - Number of users to be skipped.
|
|
* @param {number} limit - Limit number of users to be returned.
|
|
* @returns {Promise<Supplider[]>}
|
|
*/
|
|
FileConfig.list = async ({
|
|
name,
|
|
|
|
// sort
|
|
sort_by,
|
|
order_by,
|
|
skip = 0,
|
|
limit = 20,
|
|
}) => {
|
|
const options = filterConditions({
|
|
name
|
|
});
|
|
const sort = sortConditions({ sort_by, order_by });
|
|
return FileConfig.findAll({
|
|
where: options,
|
|
order: [sort],
|
|
offset: skip,
|
|
limit: limit
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Total records.
|
|
*
|
|
* @param {number} skip - Number of users to be skipped.
|
|
* @param {number} limit - Limit number of users to be returned.
|
|
* @returns {Promise<Number>}
|
|
*/
|
|
FileConfig.totalRecords = ({
|
|
name
|
|
}) => {
|
|
const options = filterConditions({
|
|
name
|
|
});
|
|
|
|
return FileConfig.count({ where: options });
|
|
};
|
|
|
|
/**
|
|
* Filter only allowed fields from Province
|
|
*
|
|
* @param {Object} params
|
|
*/
|
|
FileConfig.filterParams = (params) => pick(params, PUBLIC_FIELDS);
|
|
|
|
/**
|
|
* @typedef Province
|
|
*/
|
|
export default FileConfig;
|
|
|