/* 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} */ 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} */ 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;