UNPKG

shadowsocks-manager

Version:

A shadowsocks manager tool for multi user and traffic control.

365 lines (343 loc) 12 kB
const log4js = require('log4js'); const logger = log4js.getLogger('alipay'); const cron = appRequire('init/cron'); const config = appRequire('services/config').all(); const alipayf2f = require('alipay-ftof'); const fs = require('fs'); const ref = appRequire('plugins/webgui_ref/time'); const orderPlugin = appRequire('plugins/webgui_order'); const groupPlugin = appRequire('plugins/group'); let alipay_f2f; if(config.plugins.alipay && config.plugins.alipay.use) { try { const privateKey = fs.readFileSync(config.plugins.alipay.merchantPrivateKey, 'utf8').toString(); config.plugins.alipay.merchantPrivateKey = privateKey .replace(/-----BEGIN RSA PRIVATE KEY-----/, '') .replace(/-----END RSA PRIVATE KEY-----/, '') .replace(/\n/g, ''); } catch (err) {} try { const publicKey = fs.readFileSync(config.plugins.alipay.alipayPublicKey, 'utf8').toString(); config.plugins.alipay.alipayPublicKey = publicKey .replace(/-----BEGIN PUBLIC KEY-----/, '') .replace(/-----END PUBLIC KEY-----/, '') .replace(/\n/g, ''); } catch (err) {} alipay_f2f = new alipayf2f({ appid: config.plugins.alipay.appid, notifyUrl: config.plugins.alipay.notifyUrl, merchantPrivateKey: '-----BEGIN RSA PRIVATE KEY-----\n' + config.plugins.alipay.merchantPrivateKey + '\n-----END RSA PRIVATE KEY-----', alipayPublicKey: '-----BEGIN PUBLIC KEY-----\n' + config.plugins.alipay.alipayPublicKey + '\n-----END PUBLIC KEY-----', gatewayUrl: config.plugins.alipay.gatewayUrl, }); } const isTelegram = config.plugins.webgui_telegram && config.plugins.webgui_telegram.use; let telegram; if(isTelegram) { telegram = appRequire('plugins/webgui_telegram/admin'); } const knex = appRequire('init/knex').knex; const account = appRequire('plugins/account/index'); const moment = require('moment'); const push = appRequire('plugins/webgui/server/push'); const createOrder = async (user, account, orderId) => { const oldOrder = await knex('alipay').where({ user, account: account ? account : null, orderType: orderId }).where('expireTime', '>', Date.now() + 15 * 60 * 1000).where({ status: 'CREATE', }).then(success => { return success[0]; }); if(oldOrder) { return { orderId: oldOrder.orderId, qrCode: oldOrder.qrcode, }; } const orderInfo = await orderPlugin.getOneOrder(orderId); if(+orderInfo.alipay <= 0) { return Promise.reject('amount error'); } const userInfo = await knex('user').where({ id: user }).then(s => s[0]); const groupInfo = await groupPlugin.getOneGroup(userInfo.group); if(groupInfo.order) { if(JSON.parse(groupInfo.order).indexOf(orderInfo.id) < 0) { return Promise.reject('invalid order'); } } const myOrderId = moment().format('YYYYMMDDHHmmss') + Math.random().toString().substr(2, 6); const time = 60; const qrCode = await alipay_f2f.createQRPay({ tradeNo: myOrderId, subject: orderInfo.name || 'ss续费', totalAmount: +orderInfo.alipay, body: orderInfo.name || 'ss续费', timeExpress: 10, }); await knex('alipay').insert({ orderId: myOrderId, orderType: orderId, qrcode: qrCode.qr_code, amount: orderInfo.alipay + '', user, account: account ? account : null, status: 'CREATE', createTime: Date.now(), expireTime: Date.now() + time * 60 * 1000, }); logger.info(`创建订单: [${ myOrderId }][${ orderInfo.alipay }][account: ${ account }]`); return { orderId: myOrderId, qrCode: qrCode.qr_code, }; }; const sendSuccessMail = async userId => { const emailPlugin = appRequire('plugins/email/index'); const user = await knex('user').select().where({ type: 'normal', id: userId, }).then(success => { if(success.length) { return success[0]; } return Promise.reject('user not found'); }); const orderMail = await knex('webguiSetting').select().where({ key: 'mail', }).then(success => { if(!success.length) { return Promise.reject('settings not found'); } success[0].value = JSON.parse(success[0].value); return success[0].value.order; }); await emailPlugin.sendMail(user.email, orderMail.title, orderMail.content); }; cron.minute(async () => { logger.info('check alipay order'); if(!alipay_f2f) { return; } const orders = await knex('alipay').select().whereNotBetween('expireTime', [0, Date.now()]); const scanOrder = order => { logger.info(`order: [${ order.orderId }]`); if(order.status !== 'TRADE_SUCCESS' && order.status !== 'FINISH') { return alipay_f2f.checkInvoiceStatus(order.orderId).then(success => { if(success.code === '10000') { return knex('alipay').update({ status: success.trade_status }).where({ orderId: order.orderId, }); } }); } else if(order.status === 'TRADE_SUCCESS') { const accountId = order.account; const userId = order.user; push.pushMessage('支付成功', { body: `订单[ ${ order.orderId } ][ ${ order.amount } ]支付成功`, }); isTelegram && telegram.push(`订单[ ${ order.orderId } ][ ${ order.amount } ]支付成功`); return account.setAccountLimit(userId, accountId, order.orderType) .then(() => { return knex('alipay').update({ status: 'FINISH', }).where({ orderId: order.orderId, }); }).then(() => { logger.info(`订单支付成功: [${ order.orderId }][${ order.amount }][account: ${ accountId }]`); ref.payWithRef(userId, order.orderType); sendSuccessMail(userId); }).catch(err => { logger.error(`订单支付失败: [${ order.orderId }]`, err); }); }; }; for(const order of orders) { await scanOrder(order); } }, 'CheckAlipayOrder', 1); const checkOrder = async (orderId) => { const order = await knex('alipay').select().where({ orderId, }).then(success => { if(success.length) { return success[0]; } return Promise.reject('order not found'); }); return order.status; }; const verifyCallback = (data) => { const signStatus = alipay_f2f.verifyCallback(data); if(signStatus) { knex('alipay').update({ status: data.trade_status, alipayData: JSON.stringify(data), }).where({ orderId: data.out_trade_no, }).andWhereNot({ status: 'FINISH', }).then(); } return signStatus; }; const orderList = async (options = {}) => { const where = {}; if(options.userId) { where['user.id'] = options.userId; } const orders = await knex('alipay').select([ 'alipay.orderId', 'alipay.orderType', 'user.id as userId', 'user.username', 'account_plugin.port', 'alipay.amount', 'alipay.status', 'alipay.alipayData', 'alipay.createTime', 'alipay.expireTime', ]) .leftJoin('user', 'user.id', 'alipay.user') .leftJoin('account_plugin', 'account_plugin.id', 'alipay.account') .where(where) .orderBy('alipay.createTime', 'DESC'); orders.forEach(f => { f.alipayData = JSON.parse(f.alipayData); }); return orders; }; const orderListAndPaging = async (options = {}) => { const search = options.search || ''; const group = options.group; const filter = options.filter || []; const sort = options.sort || 'alipay.createTime_desc'; const page = options.page || 1; const pageSize = options.pageSize || 20; const start = options.start ? moment(options.start).hour(0).minute(0).second(0).millisecond(0).toDate().getTime() : moment(0).toDate().getTime(); const end = options.end ? moment(options.end).hour(23).minute(59).second(59).millisecond(999).toDate().getTime() : moment().toDate().getTime(); let count = knex('alipay').select().whereBetween('alipay.createTime', [start, end]); let orders = knex('alipay').select([ 'alipay.orderId', 'alipay.orderType', 'webgui_order.name as orderName', 'user.id as userId', 'user.group as group', 'user.username', 'account_plugin.port', 'alipay.amount', 'alipay.status', 'alipay.alipayData', 'alipay.createTime', 'alipay.expireTime', ]) .leftJoin('user', 'user.id', 'alipay.user') .leftJoin('account_plugin', 'account_plugin.id', 'alipay.account') .leftJoin('webgui_order', 'webgui_order.id', 'alipay.orderType') .whereBetween('alipay.createTime', [start, end]); if(filter.length) { count = count.whereIn('alipay.status', filter); orders = orders.whereIn('alipay.status', filter); } if(group >= 0) { count = count.leftJoin('user', 'user.id', 'alipay.user').where({ 'user.group': group }); orders = orders.where({ 'user.group': group }); } if(search) { count = count.where('alipay.orderId', 'like', `%${ search }%`); orders = orders.where('alipay.orderId', 'like', `%${ search }%`); } count = await count.count('orderId as count').then(success => success[0].count); orders = await orders.orderBy(sort.split('_')[0], sort.split('_')[1]).limit(pageSize).offset((page - 1) * pageSize); orders.forEach(f => { f.alipayData = JSON.parse(f.alipayData); }); const maxPage = Math.ceil(count / pageSize); return { total: count, page, maxPage, pageSize, orders, }; }; const getCsvOrder = async (options = {}) => { const search = options.search || ''; const group = options.group; const filter = options.filter || []; const sort = options.sort || 'alipay.createTime_desc'; const start = options.start ? moment(options.start).hour(0).minute(0).second(0).millisecond(0).toDate().getTime() : moment(0).toDate().getTime(); const end = options.end ? moment(options.end).hour(23).minute(59).second(59).millisecond(999).toDate().getTime() : moment().toDate().getTime(); let orders = knex('alipay').select([ 'alipay.orderId', 'alipay.orderType', 'user.id as userId', 'user.group as group', 'user.username', 'account_plugin.port', 'alipay.amount', 'alipay.status', 'alipay.alipayData', 'alipay.createTime', 'alipay.expireTime', ]) .leftJoin('user', 'user.id', 'alipay.user') .leftJoin('account_plugin', 'account_plugin.id', 'alipay.account') .whereBetween('alipay.createTime', [start, end]); if(filter.length) { orders = orders.whereIn('alipay.status', filter); } if(group >= 0) { orders = orders.where({ 'user.group': group }); } if(search) { orders = orders.where('alipay.orderId', 'like', `%${ search }%`); } orders = await orders.orderBy(sort.split('_')[0], sort.split('_')[1]); orders.forEach(f => { f.alipayData = JSON.parse(f.alipayData); }); return orders; }; const getUserFinishOrder = async userId => { let orders = await knex('alipay').select([ 'orderId', 'amount', 'createTime', ]).where({ user: userId, status: 'FINISH', }).orderBy('createTime', 'DESC'); orders = orders.map(order => { return { orderId: order.orderId, type: '支付宝', amount: order.amount, createTime: order.createTime, }; }); return orders; }; const refund = async (orderId, amount) => { const order = await knex('alipay').where({ orderId }).then(s => s[0]); if(!order) { return Promise.reject('order not found'); } let refundAmount = order.amount; if(amount) { refundAmount = amount; } const result = await alipay_f2f.refund(order.orderId, { refundNo: moment().format('YYYYMMDDHHmmss') + Math.random().toString().substr(2, 6), refundAmount, }); return result; }; cron.minute(async () => { if(!alipay_f2f) { return; } await knex('alipay').delete().where({ status: 'CREATE' }).whereBetween('createTime', [0, Date.now() - 1 * 24 * 3600 * 1000]); }, 'DeleteAlipayOrder', 53); exports.orderListAndPaging = orderListAndPaging; exports.orderList = orderList; exports.createOrder = createOrder; exports.checkOrder = checkOrder; exports.verifyCallback = verifyCallback; exports.getCsvOrder = getCsvOrder; exports.getUserFinishOrder = getUserFinishOrder; exports.refund = refund;