admin/controllers/product/index.js

/* eslint-disable consistent-return */
/* eslint-disable no-cond-assign */
/* eslint-disable no-return-await */
/* ============================================================================ *\
|| ########################################################################## ||
|| # Auction Software Marketplace          Release: 0.6   Build 0.7         # ||
|| # ---------------------------------------------------------------------- # ||
|| # License # 35YAHCNR9344X6O666C123AB                                     # ||
|| # ---------------------------------------------------------------------- # ||
|| # Copyright ©2014–2021 Develop Scripts LLC. All Rights Reserved          # ||
|| # This file may not be redistributed in whole or significant part.       # ||
|| # ------------- AUCTION SOFTWARE IS NOT FREE SOFTWARE ------------------ # ||
|| # http://www.auctionsoftwaremarketplace.com|support@auctionsoftware.com  # ||
|| # ---------------------------------------------------------------------- # ||
|| ########################################################################## ||
\* ============================================================================ */

/* eslint-disable prefer-destructuring */
/* eslint-disable no-param-reassign */
const jwt = require('jsonwebtoken')
const _ = require('underscore')
const parse = require('csv-parse')
const axios = require('axios')
const fs = require('fs')

const adminProductModule = require('../../modules/product').default
const adminAuctionModule = require('../../modules/auction').default
const schemaModule = require('./schema').default
const commonFunction = require('../../../common/function').default
const returnCtrl = require('../../../front/controllers/return')
const auctionCtrl = require('../auction')

const { jsonResponse } = require('../logger')

const shortDescribeSCH = async (items) => {
    function changingdata(item) {
        item.avatarorg =
            item.file_name === '' || item.file_name === null
                ? `${global.s3_static_image_url}images/pics-coming.jpg`
                : `${global.s3_static_image_url}uploads/product/${item.file_name}`
        return item
    }
    const promises = items.map(changingdata)
    items = await Promise.all(promises)
    return items
}

const processBidDeposits = async (items) => {
    const changingdata = async (item) => {
        const reqBody = {
            body: {
                filters: {
                    project_id: {
                        value: item.id,
                        field: 'bdt.type_id',
                        type: 'in',
                    },
                },
            },
        }
        const [results] = await Promise.all([adminProductModule.fetchDepositsData(reqBody, 0)])
        item = { ...item, ...results[0] }
        return item
    }
    const promises = items.map(changingdata)
    items = await Promise.all(promises)
    return items
}

const processAllItems = async (items) => {}
const getAttachmentList = async (req, items) => {
    async function changingdata(item) {
        const [results0] = await Promise.all([adminProductModule.fetchAllAttachments(item.id)])
        console.log('results0', results0[0].uploadimages)
        item.uploadimages = results0[0].uploadimages
        return item
    }
    const promises = items.map(changingdata)
    items = await Promise.all(promises)
    return items
}

const auctionDetail = async (req, items) => {
    async function changingdata(item) {
        const [results0, bidCount] = await Promise.all([
            adminAuctionModule.fetchAuctionbyID(item.auctionid),
            adminAuctionModule.fetchBidByID(item.id),
        ])
        item.auctionDetails = results0[0]
        item.bidcount = bidCount[0]
        return item
    }
    const promises = items.map(changingdata)
    items = await Promise.all(promises)
    return items
}

/**
 * Download files from array of urls into the server & store it in attachments table
 * @param {object} req request object
 * @param {string[]} urlArr array of urls to download the documents from
 * @param {string} filePath file path to downalod the files to
 * @param {string} fileType type of file, doc or image
 * @param {number} projectId project id
 * @returns
 */
const downloadFileFromUrls = async (req, urlArr, filePath, fileType, projectId) => {
    let allowedContents = []
    let allowedTypes = {}
    if (fileType === 'doc') {
        allowedTypes = {
            pdf: 'pdf',
            msword: 'doc',
            'vnd.openxmlformats-officedocument.wordprocessingml.document': 'docx',
            'vnd.ms-excel': 'xls',
            'vnd.openxmlformats-officedocument.spreadsheetml.sheet': 'xlsx',
            plain: 'txt',
            'html; charset=UTF-8': 'html',
        }
    } else if (fileType === 'image') {
        allowedContents = [
            'jpg',
            'jpeg',
            'png',
            'gif',
            'html; charset=UTF-8',
            'jpeg; charset=UTF-8',
            'html; charset=utf-8',
        ]
    } else {
        return 'Invalid file type'
    }
    /**
     * upload file or image to server & store it in attachments table\
     * @param {string} url path to downalod the files to
     * @returns {Promise} uloaded file info
     */
    const uploaderFunction = async (url) => {
        return new Promise(async (resolve, reject) => {
            const res = await axios.get(url)
            const headertype = res.headers['content-type'].split('/')[1]

            let origfilename = new URL(url).searchParams.get('filename')
            if (!origfilename) {
                origfilename = url.substring(url.lastIndexOf('/') + 1)
            }

            let name = ''
            if (fileType === 'image') {
                name = `${'lot-'}${Date.now()}${Math.floor(
                    100000 + Math.random() * 900000,
                )}.${origfilename.split('.').pop()}`
            } else if (fileType === 'doc') {
                allowedContents = _.keys(allowedTypes)
                name = `${'doc-'}${Date.now()}${Math.floor(
                    100000 + Math.random() * 900000,
                )}.${origfilename.split('.').pop()}`
            }

            const cond = _.contains(allowedContents, headertype)
            if (cond) {
                const [secondname] = name.split('?')
                name = secondname
                const fileName = filePath + name
                axios({
                    method: 'get',
                    url,
                    responseType: 'stream',
                })
                    .then((resp) => {
                        const fileStream = fs.createWriteStream(fileName, {
                            autoClose: true,
                        })
                        resp.data.pipe(fileStream)
                        fileStream.on('finish', function () {
                            resolve(name)
                        })
                        fileStream.on('error', function (err) {
                            reject(err)
                        })
                    })
                    .catch((err) => {
                        console.error(err)
                        reject(err)
                    })
            } else {
                reject('Not an allowed content type')
            }
        })
    }

    let fileNameArr = []
    for (let url of urlArr) {
        try {
            const fileName = await uploaderFunction(url)
            fileNameArr.push(fileName)
        } catch (e) {
            console.error(`[File Download From URL Error] ${e}`)
        }
    }

    // store file names into DB
    req.body.uploadimages = fileNameArr
    imageUploader(req, projectId)
    return
}
/**
 * upload image and bind that image to project
 * @param {string} req req.body.uploadimages[]
 * @param {string} projectID project id
 * @param {adminProductModule.addattachementtoproduct} modules
 * @param {adminProductModule.deleteAttachmentProject} modules
 * @returns {Boolean} uploaded or not
 */
const imageUploader = async (req, projectID) => {
    if (req.body.uploadimages !== '') {
        let upimgfinal = []
        if (req.body.uploadimages instanceof Array) {
            upimgfinal = req.body.uploadimages
        } else {
            upimgfinal = req.body.uploadimages.toString().split(',')
        }

        if (upimgfinal.length) {
            console.log('upimgfinal', upimgfinal)
            await Promise.all([
                adminProductModule.addattachementtoproduct(upimgfinal[0], projectID),
                adminProductModule.deleteAttachmentProject(projectID),
            ])
            upimgfinal.forEach(async (value, index) => {
                const imagobj = {
                    file_name: value,
                    user_id: req.body.user_id,
                    orderby: index,
                }
                console.log('imagobj', imagobj)
                await Promise.all([adminProductModule.addattachement(imagobj, projectID)])
                // if (index === upimgfinal.length - 1) {
                // }
            })
        }
    }
    return true
}

/**
 * Save audio files for a project into attachments table
 * @param {number} userId the user ID
 * @param {string[]} audioFilesArr array of audio files name
 * @param {adminProductModule.addAudioAttachment} modules
 * @param {string} projectId the project ID
 */
const saveAudioFilesToAttachments = async (userId, audioFilesArr, projectId) => {
    if (audioFilesArr.length) {
        audioFilesArr.forEach(async (value, index) => {
            const audioFile = {
                file_name: value,
                user_id: userId,
                orderby: index,
            }
            await Promise.all([adminProductModule.addAudioAttachment(audioFile, projectId)])
        })
    }
}
/**
 * Save audio files for a project into attachments table
 * @param {number} userId the user ID
 * @param {string[]} audioFilesArr array of audio files name
 * @param {adminProductModule.addAudioAttachment} modules
 * @param {string} projectId the project ID
 */
const itemPropsArray = async (req, projectID) => {
    try {
        if (req.body.itemPropsArray !== '') {
            const baseTableUsed = global.configColumns.itemPropsArray
            const customTableUsed = { enabled: 0 }
            // if (req.body.itemPropsArray.length)
            await Promise.all([adminProductModule.deleteItemPropsProject(projectID)])

            req.body.itemPropsArray.forEach(async (value) => {
                value.project_id = projectID
                value.id = 0
                value.is_deleted = 0
                if (
                    value.release_date &&
                    value.release_date !== '' &&
                    !isNaN(new Date(value.release_date))
                ) {
                    value.release_date = commonFunction.dateTimeFormatConvert(
                        new Date(value.release_date),
                    )
                } else {
                    value.release_date = null
                }
                await Promise.all([
                    commonFunction.tableFunction(
                        { ...req, ...{ body: value } },
                        baseTableUsed,
                        customTableUsed,
                    ),
                ])
            })
        }
        return true
    } catch (e) {
        console.log('Error', e)
        return true
    }
}
/**
 * get items properties
 * @param {Object} req req.body
 * @param {string[]} audioFilesArr array of audio files name
 * @param {commonFunction.asyncForEach} modules
 * @param {commonFunction.fetchFilteredDataFunction} modules
 * @param {commonFunction.dateTimeFormatConvert} modules
 * @param {string} records the all items required
 */
const getItemPropsArray = async (req, records) => {
    if (records.length) {
        const baseTableUsed = global.configColumns.itemPropsArray
        const customTableUsed = { enabled: 0 }
        await commonFunction.asyncForEach(records, async (value) => {
            let responseData = []
            ;[responseData] = await Promise.all([
                commonFunction.fetchFilteredDataFunction(
                    {
                        ...req,
                        ...{
                            body: {
                                ...value,
                                filters: {
                                    project_id: {
                                        value: value.id,
                                        field: 'ipa.project_id',
                                        type: 'in',
                                    },
                                    is_deleted: {
                                        value: 1,
                                        field: 'ipa.is_deleted',
                                        type: 'notin',
                                    },
                                },
                            },
                        },
                    },
                    baseTableUsed,
                    customTableUsed,
                ),
            ])

            value.itemPropsArray = responseData[0]

            return value
        })

        return records
    }
    return records
}
/**
 * bulkUploadValidation
 * @param {string[]} audioFilesArr array of audio files name
 * @param {String} record
 * @param {String} iterate
 * @param {String} errors
 * @param {commonFunction.fetchFilteredDataFunction} modules
 * @param {commonFunction.getValidID} modules
 */
const bulkUploadValidation = (record, iterate, errors) => {
    // validation
    ;['auction', 'buynow', 'rprice', 'sprice', 'bprice'].forEach((data) => {
        record[data] = parseFloat(record[data])
    })

    if (!record.title || record.title === '') {
        errors.push({ line: iterate, message: 'Title missing' })
    }
    if (!record.auction && !record.buynow) {
        errors.push({ line: iterate, message: 'Must be auction or buynow' })
    }

    if (record.auction && record.qty > 1) {
        errors.push({ line: iterate, message: 'Qty error!' })
    }

    if (record.auction && !record.rprice && !record.sprice) {
        errors.push({ line: iterate, message: 'sprice, rprice is missing!' })
    }

    if (record.buynow && !record.bprice) {
        errors.push({ line: iterate, message: 'bprice is missing!' })
    }

    if (record.auction && record.rprice <= record.sprice) {
        errors.push({ line: iterate, message: 'sprice must be less than rprice!' })
    }

    if (record.auction && record.buynow && record.rprice > record.bprice) {
        errors.push({ line: iterate, message: 'rprice must be less than bprice!' })
    }

    return errors
}
/**
 * bulkUploadValidation
 * @param {Object} req object with project info
 * @param {commonFunction.dateTimeFormatConvert} modules
 * @param {commonFunction.getValidID} modules
 * @param {commonFunction.dateTimeFormatConvert} modules
 * @param {commonFunction.tableFunction} modules
 */
const projectTableAction = async (req) => {
    req.body.id = commonFunction.getValidID(req.body.id)

    const baseTableUsed = global.configColumns.projects
    const customTableUsed = global.configColumns.custom_projects

    if (req.body.date_added) {
        req.body.date_added = commonFunction.dateTimeFormatConvert(req.body.date_added)
    }
    if (req.body.date_closed) {
        req.body.date_closed = commonFunction.dateTimeFormatConvert(req.body.date_closed)
    }

    if (req.body.public_start_date) {
        req.body.public_start_date = commonFunction.dateTimeFormatConvert(
            req.body.public_start_date,
        )
    }

    const [results] = await Promise.all([
        commonFunction.tableFunction(
            req,
            baseTableUsed,
            customTableUsed,
            null,
            ['id'],
            ['project_id'],
        ),
    ])
    return results
}
module.exports = {
    processBidDeposits,
    /**
     * Get all project listing
     *
     * @memberOf adminside.product
     * @param {adminProductModule.fetchProductsAll} modules
     * @param {adminProductModule.fetchActiveAuctions} modules
     */
    listings: async (req, res) => {
        if (req.body.filters.action) {
            req.body.action =
                typeof req.body.filters.action.value === 'undefined'
                    ? 'open'
                    : req.body.filters.action.value

            delete req.body.filters.action
        }

        req.body.auctionlot = req.body.auctionlot ? req.body.auctionlot : 0
        let records = []
        let totalRecords = []
        let activelots = []
        let selectedBuyer = []
        try {
            ;[records, totalRecords, activelots] = await Promise.all([
                adminProductModule.fetchProductsAll(req, 0),
                adminProductModule.fetchProductsAll(req, 1),
                adminProductModule.fetchActiveAuctions(req),
            ])
            records = await shortDescribeSCH(records)
            if (global.configColumns.bid_deposit && global.configColumns.bid_deposit.enabled) {
                records = await processBidDeposits(records)
            }

            if (activelots.length > 0 && req.body.auctionlot > 0) {
                if (activelots[0] && activelots[0].selltype && activelots[0].selltype === 1) {
                    if (activelots[0].selectedbuyer && activelots[0].selectedbuyer !== '') {
                        ;[selectedBuyer] = await Promise.all([
                            adminProductModule.fetchActiveAuctionsUsers(
                                activelots[0].selectedbuyer,
                            ),
                        ])
                    }
                }
            }
        } catch (e) {
            console.error(e)
            jsonResponse(res, 'error', {
                responseType: 3,
                message: 'Internal Server error!',
            })
        } finally {
            let responseData = { records, totalRecords, activelots, selectedBuyer }
            responseData = await commonFunction.getdynamicinnercontents(req, responseData)
            jsonResponse(res, 'success', {
                responseType: 1,
                message: 'Details successfully retrieved!',
                responseData,
            })
        }
    },
    /**
     * Change Product Status
     *
     * @memberOf adminside.product
     * @param {frontend.return.relistProduct} modules
     * @param {adminProductModule.marketStatusUpdate} modules
     */
    changeStatus: async (req, res) => {
        try {
            if (req.body.action === 'relist') {
                const processAllItemsStatus = async (items) => {
                    await Promise.all([returnCtrl.relistProduct(items, 'relisted')])
                    return true
                }
                const resultloop = []
                req.body.project_id.forEach(async (element) => {
                    const looptoformat = await processAllItemsStatus(element)
                    resultloop.push(looptoformat)
                })
                await Promise.all(resultloop)
                jsonResponse(res, 'success', {
                    responseType: 1,
                    message: 'Relisted successfully',
                })
            } else if (req.body.mainUpdate) {
                req.body.id = req.body.project_id
                await Promise.all([projectTableAction(req)])
            } else if (req.body.action && req.body.project_id.length > 0) {
                await adminProductModule.marketStatusUpdate(req.body.action, req.body.project_id)
            }
        } catch (e) {
            console.error(e)
            jsonResponse(res, 'error', {
                responseType: 3,
                message: 'Internal Server error!',
            })
        } finally {
            const responseData = {}
            jsonResponse(res, 'success', {
                responseType: 1,
                message: 'Status successfully changed',
                responseData,
            })
        }
    },
    /**
     * Get Single Project Details
     *
     * @memberOf adminside.project
     * @param {adminProductModule.fetchProjectbyID} modules
     */
    getSingleProject: async (req, res) => {
        let record = {}
        try {
            const id = commonFunction.getValidID(req.body.id)
            req.body.filters = req.body.filters ? req.body.filters : {}
            req.body.filters.id = { value: id, field: 'p.id', type: 'in' }

            let [records] = await Promise.all([adminProductModule.fetchProductsAll(req, 0)])
            records = await shortDescribeSCH(records)
            records = await getAttachmentList(req, records)
            records = await auctionDetail(req, records)
            if (typeof global.configFeatures.itemPropsArray !== 'undefined') {
                if (parseInt(global.configFeatures.itemPropsArray.enabled, 10) === 1) {
                    records = await getItemPropsArray(req, records)
                }
            }
            record = records[0]
        } catch (e) {
            console.error(e)
            jsonResponse(res, 'error', {
                responseType: 3,
                message: 'Internal Server error!',
            })
        } finally {
            const responseData = { record }
            jsonResponse(res, 'success', {
                responseType: 1,
                message: 'Details successfully retrieved!',
                responseData,
            })
        }
    },
    /**
     * project Action
     *
     * @memberOf adminside.project
     * @param {commonFunction.getValidID} modules
     * @param {commonFunction.dateTimeFormatConvert} modules
     * @param {commonFunction.tableFunction} modules
     * @param {auctionCtrl.reConfigureEndTime} modules
     * @param {commonFunction.notifyinsert} modules
     *
     */
    projectAction: async (req, res) => {
        try {
            req.body.id = commonFunction.getValidID(req.body.id)

            const baseTableUsed = global.configColumns.projects
            const customTableUsed = global.configColumns.custom_projects

            if (req.body.date_added) {
                req.body.date_added = commonFunction.dateTimeFormatConvert(req.body.date_added)
            }
            if (req.body.date_closed) {
                req.body.date_closed = commonFunction.dateTimeFormatConvert(req.body.date_closed)
            }

            if (req.body.public_start_date) {
                req.body.public_start_date = commonFunction.dateTimeFormatConvert(
                    req.body.public_start_date,
                )
            }

            if (req.body.id) {
                req.body.updated_at = commonFunction.dateTimeFormatConvert(new Date())
            } else {
                req.body.user_id = req.user.admin_id
                req.body.created_at = commonFunction.dateTimeFormatConvert(new Date())
            }

            req.body.wprice =
                req.body.wprice && req.body.wprice > req.body.sprice
                    ? req.body.wprice
                    : req.body.sprice
            const [results] = await Promise.all([
                commonFunction.tableFunction(req, baseTableUsed, customTableUsed),
            ])

            if (req.body.auctionid) {
                auctionCtrl.reConfigureEndTime(req, req.body.auctionid, false)
            }

            if (req.body.id) {
                req.body.project_id = req.body.id
            } else {
                req.body.project_id = results[0].insertId
                if (typeof global.configFeatures.private_project_email !== 'undefined') {
                    if (
                        parseInt(global.configFeatures.private_project_email.enabled, 10) === 1 &&
                        parseInt(req.body.selltype, 10) === 1
                    ) {
                        req.body.refer_id = req.body.project_id
                        req.body.refer_field = global.configFeatures.private_project_email.cat_name
                        req.body.type = 'private_project_email'
                        await Promise.all([commonFunction.notifyinsert(req)])
                    }
                }

                if (typeof global.configFeatures.saved_search_email !== 'undefined') {
                    if (parseInt(global.configFeatures.saved_search_email.enabled, 10) === 1) {
                        req.body.refer_id = req.body.project_id
                        req.body.refer_field = global.configFeatures.saved_search_email.cat_name
                        req.body.type = 'saved_search_email'
                        await Promise.all([commonFunction.notifyinsert(req)])
                    }
                }

                if (typeof global.configFeatures.watchlist_close_notification !== 'undefined') {
                    if (
                        parseInt(global.configFeatures.watchlist_close_notification.enabled, 10) ===
                        1
                    ) {
                        req.body.refer_id = req.body.project_id
                        req.body.refer_field =
                            global.configFeatures.watchlist_close_notification.cat_name
                        const watchlistCloseNotificationHours = global.configurations.variables
                            .watchlist_close_notification_hour
                            ? global.configurations.variables.watchlist_close_notification_hour.split(
                                  ',',
                              )
                            : []
                        for (let i = 0; i < watchlistCloseNotificationHours.length; i += 1) {
                            if (i === 0) req.body.type = 'watchlist_close_notification'
                            else req.body.type = `watchlist_close_notification_${i}`
                            await Promise.all([commonFunction.notifyinsert(req)])
                        }
                    }
                }
            }

            // upload product images from urls
            if (req.body.image_url && req.body.image_url_list) {
                // download files asynchronously
                downloadFileFromUrls(
                    req,
                    req.body.image_url_list,
                    `${global.path}public/uploads/product/`,
                    'image',
                    req.body.project_id,
                )
            } else {
                await imageUploader(req, req.body.project_id)
            }

            // uploaded audio files
            if (req.body.uploadedAudioFiles) {
                saveAudioFilesToAttachments(
                    req.body.user_id,
                    req.body.uploadedAudioFiles,
                    req.body.project_id,
                )
            }

            if (typeof global.configFeatures.itemPropsArray !== 'undefined') {
                if (parseInt(global.configFeatures.itemPropsArray.enabled, 10) === 1) {
                    await itemPropsArray(req, req.body.project_id)
                }
            }
        } catch (e) {
            console.error(e)
            jsonResponse(res, 'error', {
                responseType: 3,
                message: 'Internal Server error!',
            })
        } finally {
            const responseData = {
                project_id: req.body.project_id,
            }
            jsonResponse(res, 'success', {
                responseType: 1,
                message: req.body.id ? 'Successfully updated!' : 'Successfully added!',
                responseData,
            })
        }
    },
    /**
     * bulkProjectAction
     *
     * @memberOf adminside.project
     * @param {Object} req request object
     * @param {Object} res response object
     * @param {commonFunction.dateTimeFormatConvert} modules
     * @param {commonFunction.tableFunction} modules
     *
     */
    bulkProjectAction: async (req, res) => {
        const fs = require('fs')
        let validCols = []
        const rs = fs.createReadStream(`./public/uploads/temp/${req.body.uploadFiles[0]}`)
        if (req.body.project && req.body.project === 'NPS') {
            validCols = ['title', 'qty', 'desc_proc', 'auction', 'sprice', 'rprice', 'auctiontype']
        } else {
            validCols = [
                'title',
                'qty',
                'desc_proc',
                'auction',
                'sprice',
                'rprice',
                'buynow',
                'bprice',
                'auctiontype',
            ]
        }
        const records = []
        const baseTableUsed = global.configColumns.projects
        const customTableUsed = global.configColumns.custom_projects

        let iterate = 1
        let errors = []
        let allColumns = baseTableUsed.array_columns

        if (customTableUsed.enabled) {
            allColumns = [...allColumns, ...customTableUsed.array_columns]
        }

        const parser = parse({
            columns: true,
        })
            .on('readable', async () => {
                let record
                while ((record = parser.read())) {
                    if (
                        _.difference(_.intersection(Object.keys(record), validCols), validCols)
                            .length > 0
                    ) {
                        errors.push({
                            line: 0,
                            message: `Missing columns, 
                        They are ${validCols.toString()}.`,
                        })
                        parser.end()
                    }
                    if (
                        _.difference(
                            Object.keys(record),
                            _.intersection(Object.keys(record), allColumns),
                        ).length > 0
                    ) {
                        errors.push({
                            line: 0,
                            message: `Some column not matching our record`,
                        })
                        parser.end()
                    }
                    if (!record.date_added) {
                        record.date_added = commonFunction.dateTimeFormatConvert(new Date())
                    }

                    if (!record.date_closed) {
                        record.date_closed = commonFunction.dateTimeFormatConvert(new Date())
                    }
                    if (!record.market_status) {
                        record.market_status = 'draft'
                    }
                    record.buynow = record.buynow ? record.buynow : 0
                    record.user_id = req.user.admin_id
                    record.created_at = commonFunction.dateTimeFormatConvert(new Date())
                    record.wprice = record.sprice
                    record.bprice = record.bprice ? record.bprice : 0
                    records.push(record)
                    iterate += 1
                    errors = bulkUploadValidation(record, iterate, errors)
                }
            })
            .on('error', () => {
                jsonResponse(res, 'error', {
                    responseType: 3,
                    message: 'Internal Server error!',
                })
                return false
            })
            .on('end', async () => {
                if (errors.length === 0) {
                    console.log('record', records)
                    records
                        .reduce((p, item) => {
                            return p.then(async () => {
                                return await Promise.all([
                                    commonFunction.tableFunction(
                                        { body: item },
                                        baseTableUsed,
                                        customTableUsed,
                                    ),
                                ])
                            })
                        }, Promise.resolve())
                        .then(() => {
                            const responseData = {}
                            jsonResponse(res, 'success', {
                                responseType: 1,
                                message: 'Successfully added!',
                                responseData,
                            })
                            return false
                        })
                } else {
                    jsonResponse(res, 'error', {
                        responseType: 3,
                        message: `Row: ${errors[0].line} ${errors[0].message} `,
                        responseData: { record: errors },
                    })
                    return false
                }
            })
        await rs.pipe(parser)
    },
    /**
     * bulkProjectAction
     *
     * @memberOf adminside.project
     * @param {Object} req request object
     * @param {Object} res response object
     * @param {adminProductModule.bidHistoryViewPage} modules
     * @param {commonFunction.asyncForEach} modules
     * @param {commonFunction.getdynamicinnercontents} modules
     *
     */
    bidhistory: async (req, res) => {
        let records = []
        let totalRecords = []
        try {
            ;[records, totalRecords] = await Promise.all([
                adminProductModule.bidHistoryViewPage(req, 0),
                adminProductModule.bidHistoryViewPage(req, 1),
            ])
            const itemsChanged = []
            const getBidText = async (item) => {
                let bidText = ''
                if (item.proposal === 'hard_bid') {
                    bidText = 'Hard'
                } else if (item.proposal === 'bid_as_proxy') {
                    bidText = 'Proxy'
                } else if (item.proposal === 'tie_bid') {
                    bidText = 'Tie'
                } else if (item.proposal === 'proxy_leads') {
                    bidText = 'Leads'
                }
                item.bidtext = bidText
                itemsChanged.push(item)
                return true
            }

            await commonFunction.asyncForEach(records, async (element) => {
                await getBidText(element)
            })
            records = await shortDescribeSCH(itemsChanged)
        } catch (e) {
            console.error(e)
            jsonResponse(res, 'error', {
                responseType: 3,
                message: 'Internal Server error!',
            })
        } finally {
            let responseData = { records, totalRecords }
            responseData = await commonFunction.getdynamicinnercontents(req, responseData)
            jsonResponse(res, 'success', {
                responseType: 1,
                message: 'Details successfully retrieved!',
                responseData,
            })
        }
    },
    /**
     * Get All ttw Bid History
     *
     * @memberOf frontend.product
     * @param {adminProductModule.bidHistoryViewPage} modules
     * @param {adminProductModule.ttwBidHistory} modules
     */
    ttwBidhistory: async (req, res) => {
        let records = []
        let totalRecords = []
        try {
            ;[records, totalRecords] = await Promise.all([
                adminProductModule.ttwBidHistory(req, 0),
                adminProductModule.ttwBidHistory(req, 1),
            ])
            if (records.length) {
                records.map((bid) => {
                    bid.name_secret = `${
                        bid.first_name && bid.first_name.length ? bid.first_name[0] : ''
                    }***${
                        bid.last_name && bid.last_name.length
                            ? bid.last_name[bid.last_name.length - 1]
                            : ''
                    }`
                    return bid
                })
            }

            totalRecords = totalRecords.length
        } catch (e) {
            console.error(e)
            jsonResponse(res, 'error', {
                responseType: 3,
                message: 'Internal Server error!',
            })
        } finally {
            const responseData = { records, totalRecords }
            jsonResponse(res, 'success', {
                responseType: 1,
                message: 'Details successfully retrieved!',
                responseData,
            })
        }
    },
    /**
     * ttwBidhistoryUpdate
     *
     * @memberOf adminside.project
     * @param {Object} req request object
     * @param {Object} res response object
     * @param {commonFunction.ttwBidHistoryUpdate} modules
     *
     */
    ttwBidhistoryUpdate: async (req, res) => {
        try {
            if (req.body && req.body.id && req.body.proposed_amount) {
                await Promise.all([adminProductModule.ttwBidHistoryUpdate(req.body)])
            } else {
                jsonResponse(res, 'error', {
                    responseType: 3,
                    message: 'Required params missing!',
                })
            }
        } catch (e) {
            console.error(e)
            jsonResponse(res, 'error', {
                responseType: 3,
                message: 'Internal Server error!',
            })
        } finally {
            jsonResponse(res, 'success', {
                responseType: 1,
                message: 'Details successfully updated!',
                responseData: [],
            })
        }
    },
}