/* eslint-disable eqeqeq */
'use strict';
const shopController = require('./shop.js');
const Decimal = require('decimal.js');
// 用户控制器
module.exports = class UserController extends shopController {
  // 使用模型
  get useModel() {
    const that = this;
    return that.app.model.Users;
  }

  /**
   * [registerValidate 用户注册验证器]
   * @return {[type]} [description]
   */
  get registerValidate() {
    const that = this;
    return {
      account_name: that.ctx.rules.name('账号')
        .required()
        .trim()
        .notEmpty(),
      password: that.ctx.rules.name('密码')
        .required()
        .trim()
        .notEmpty()
        .extend((field, value, row) => {
          row[field] = that.app.szjcomo.MD5(value);
        }),
      create_time: that.ctx.rules.default(that.app.szjcomo.date('Y-m-d H:i:s'))
        .required(),
    };
  }

  /**
   * [wxRegisterAdnLoginValidate 微信登录和注册验证器]
   * @return {[type]} [description]
   */
  get wxRegisterAdnLoginValidate() {
    const that = this;
    return {
      code: that.ctx.rules.name('微信授权code')
        .required()
        .notEmpty()
        .trim(),
    };
  }

  /**
   * [loginValidate 用户登录]
   * @return {[type]} [description]
   */
  get loginValidate() {
    const that = this;
    return {
      account_name: that.ctx.rules.name('用户账号')
        .required()
        .notEmpty()
        .trim(),
      password: that.ctx.rules.name('登录密码')
        .required()
        .notEmpty()
        .trim()
        .extend((field, value, row) => {
          row[field] = that.app.szjcomo.MD5(value);
        }),
    };
  }

  /**
   * 更新用户信息
   * @date:2023/10/20
   */
  get updateValidate() {
    const that = this;
    return {
      user_id: that.ctx.rules.default(that.service.shop.getWebUserId())
        .number(),
    };
  }

  /**
   * [wxuserValidate 微信用户写入]
   * @return {[type]} [description]
   */
  get wxuserValidate() {
    const that = this;
    return {
      nickname: that.ctx.rules.name('用户昵称')
        .required()
        .notEmpty()
        .trim(),
      openid: that.ctx.rules.name('openid')
        .required()
        .notEmpty()
        .trim(),
      password: that.ctx.rules.default(that.app.szjcomo.MD5('123456'))
        .required(),
      account_name: that.ctx.rules.default(`${that.app.szjcomo.str_rand(6)}${that.app.szjcomo.date('His')}`)
        .required(),
      money: that.ctx.rules.default(0)
        .number(),
      intergral: that.ctx.rules.default(0)
        .number(),
      headimgurl: that.ctx.rules.default('')
        .required(),
      login_time: that.ctx.rules.default(that.app.szjcomo.date('Y-m-d H:i:s'))
        .required(),
      city: that.ctx.rules.default('')
        .required(),
      province: that.ctx.rules.default('')
        .required(),
      country: that.ctx.rules.default('')
        .required(),
      sex: that.ctx.rules.default(0)
        .number(),
      subscribe: that.ctx.rules.default(0)
        .number(),
      unionid: that.ctx.rules.default('')
        .required(),
      create_time: that.ctx.rules.default(that.app.szjcomo.date('Y-m-d H:i:s'))
        .required(),
    };
  }

  /**
   * [wxloginURLValidate 获取微信登录地址]
   * @return {[type]} [description]
   */
  get wxloginURLValidate() {
    const that = this;
    return {
      page_uri: that.ctx.rules.name('当前地址')
        .required()
        .notEmpty()
        .trim(),
    };
  }

  /**
   * [userMoneyValidate 获取用户余额]
   * @return {[type]} [description]
   */
  get userMoneyValidate() {
    const that = this;
    return {
      user_id: that.ctx.rules.default(that.service.shop.getWebUserId())
        .number(),
      page: that.ctx.rules.default(1)
        .number(),
      limit: that.ctx.rules.default(50)
        .number(),
    };
  }

  get userTransferValidate() {
    const that = this;
    return {
      user_id: that.ctx.rules.default(that.service.shop.getWebUserId())
        .number(),
      diningCoinCode: that.ctx.rules.default('')
        .required(),
      page: that.ctx.rules.default(1)
        .number(),
      limit: that.ctx.rules.default(50)
        .number(),
    };
  }

  get businessCashCoinValidate() {
    const that = this;
    return {
      user_id: that.ctx.rules.default(that.service.shop.getWebUserId())
        .number(),
    };
  }

  // 2023/1/13 提现验证器
  get cashOutValidate() {
    const that = this;
    return {
      user_id: that.ctx.rules.default(that.service.shop.getWebUserId())
        .number(),
      cash_amount: that.ctx.rules.name('提现金额')
        .required()
        .notEmpty()
        .number(),
      remark: that.ctx.rules.name('备注说明')
        .default('')
        .trim(),
    };
  }

  // 2023/2/28 餐币核销验证
  get coinTransferValidate() {
    const that = this;
    return {
      user_id: that.ctx.rules.default(that.service.shop.getWebUserId())
        .number(),
      coinAmount: that.ctx.rules.name('核销收取餐币')
        .required()
        .notEmpty()
        .number(),
      time: that.ctx.rules.name('餐币二维码刷新时间')
        .required()
        .notEmpty()
        .number(),
      diningCoinCode: that.ctx.rules.name('餐币二维码特征')
        .required()
        .notEmpty(),
    };
  }


  /**
   * [login 用户登录 - 账号密码]
   * @return {[type]} [description]
   */
  async login() {
    const that = this;
    try {
      const data = await that.ctx.validate(that.loginValidate, await that.ctx.postParse());
      const user = await that.useModel.findOne({
        where: { account_name: data.account_name, password: data.password },
        // include: [
        //   { model: that.app.model.ProxyApplyLogs, as: 'proxyApplyLogs', attributes: [ 'verify_status' ] },
        // ],
        attributes: [ 'user_id', 'account_name', 'nickname', 'headimgurl', 'openid', 'intergral', 'is_proxy', 'partner_id', 'is_office', 'is_family' ],
        raw: true,
      });
      if (!user) throw new Error('登录失败,请检查账号密码是否正确');
      user.isNew = false;
      const result = await that.loginHandle(user);
      return that.ctx.appJson(that.app.szjcomo.appResult('SUCCESS', result, false));
    } catch (err) {
      console.log(err);
      return that.ctx.appJson(that.app.szjcomo.appResult(err.message));
    }
  }

  /**
   * [loginHandle 登录处理]
   * @param  {Object} user [description]
   * @return {[type]}      [description]
   */
  async loginHandle(user = {}) {
    const that = this;
    const token = that.app.jwt.sign(user, that.app.config.jwt.secret, { expiresIn: '24h' });
    const result = { token, user };
    return result;
  }

  /**
   * [register 用户注册]
   * @return {[type]} [description]
   */
  async register() {
    const that = this;
    try {
      const data = await that.ctx.validate(that.registerValidate, await that.ctx.postParse());
      const createBean = that.app.comoBean.instance(data, {});
      const result = await that.service.manager.create(createBean, that.useModel, '注册失败,请稍候重试');
      return that.ctx.appJson(that.app.szjcomo.appResult('SUCCESS', result, false));
    } catch (err) {
      return that.ctx.appJson(that.app.szjcomo.appResult(err.message));
    }
  }

  /**
   * [wxRegisterAdnLogin 用户登录 - 微信注册登录]
   * @return {[type]} [description]
   */
  async wxRegisterAdnLogin() {
    const that = this;
    try {
      const appid = await that.service.configs.getConfigValue('wechat_account_appid');
      const secret = await that.service.configs.getConfigValue('wechat_account_secret');
      const data = await that.ctx.validate(that.wxRegisterAdnLoginValidate, await that.ctx.getParse());
      const result = await that.service.wechat.authLogin(appid, secret, data.code);
      if (result.errcode) throw new Error(`微信通讯失败,错误信息:${result.errmsg}`);
      const userInfo = await that.service.wechat.authUserInfo(result);
      const user = await that.wxRegisterAdnLoginHandle(userInfo, data.inviteCode);
      const loginRes = await that.loginHandle(user);
      return that.ctx.appJson(that.app.szjcomo.appResult('SUCCESS', loginRes, false));
    } catch (err) {
      await that.logs('user.js', err);
      return that.ctx.appJson(that.app.szjcomo.appResult(err.message));
    }
  }

  /**
   * [wxloginURL 微信登录地址]
   * @return {[type]} [description]
   */
  async wxloginURL() {
    const that = this;
    try {
      const data = await that.ctx.validate(that.wxloginURLValidate, await that.ctx.postParse());
      const appid = await that.service.configs.getConfigValue('wechat_account_appid');
      const curarr = data.page_uri.split('#');
      const result = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appid}&redirect_uri=${encodeURIComponent(curarr[0] + '#/shop/wxauth')}&response_type=code&scope=snsapi_userinfo&state=${that.app.szjcomo.base64_encode(data.page_uri)}#wechat_redirect`;
      return that.ctx.appJson(that.app.szjcomo.appResult('SUCCESS', result, false));
    } catch (err) {
      return that.ctx.appJson(that.app.szjcomo.appResult(err.message));
    }
  }

  /**
   * [wxRegisterAdnLoginHandle 注册并登录]
   * @param  {Object} userInfo [description]
   * @param  {Number} inviteCode
   * @return {[type]}          [description]
   */
  async wxRegisterAdnLoginHandle(userInfo = {}, inviteCode = -1) {
    const that = this;
    const inviter_id = inviteCode;
    // console.log('==========inviteCode========== : ' + inviter_id);
    const options = {
      where: { openid: userInfo.openid },
      attributes: [ 'user_id', 'account_name', 'nickname', 'headimgurl', 'openid', 'partner_id', 'is_office', 'is_family' ],
      raw: true,
    };
    let user = await that.useModel.findOne(options);
    if (!user) {
      // 2022/9/27 新用户注册 写入信息
      user = await that.writeWxUser(userInfo);
      user.isNew = true;
      // 2022/9/27: 新用户红包奖励8.8元
      await that.service.shop.userMoneyAdd(user.user_id, 8.8, null, '新用户注册奖励', 0, 1, -1);
      // 2022/9/29 受邀注册奖励 和 邀请新用户奖励
      if (inviter_id > 0) {
        try {
          const inviterInfo = await that.useModel.findOne({
            where: { user_id: inviter_id },
            attributes: [ 'user_id', 'nickname', 'headimgurl' ],
            raw: true,
          });
          await that.service.shop.userMoneyAdd(user.user_id, 1.68, null, '受邀注册奖励', 0, 2, inviter_id, inviterInfo.nickname, inviterInfo.headimgurl);
          await that.service.shop.userMoneyAdd(inviter_id, 1.68, null, '邀请新用户奖励', 0, 3, user.user_id, user.nickname, user.headimgurl);
          // 2022/11/17 邀请关系绑定
          await that.service.inviter.addRelUserInviter(user.user_id, inviter_id);
        } catch (e) {
          // 邀请人id不存在
        }
      }
    } else {
      user.isNew = false;
      // 2023/8/25 更新登录时间
      const updateBean = await that.app.comoBean.instance({
        login_time: that.app.szjcomo.date('Y-m-d H:i:s'),
        update_ttime: that.app.szjcomo.date('Y-m-d H:i:s'),
      }, { where: { user_id: user.user_id } });
      await that.service.base.update(updateBean, that.useModel, '微信用户登录时间更新失败,请重试');
    }
    return user;
  }

  /**
   * [writeWxUser 写入微信用户]
   * @param  {Object} userInfo [description]
   * @return {[type]}          [description]
   */
  async writeWxUser(userInfo = {}) {
    const that = this;
    const data = await that.ctx.validate(that.wxuserValidate, userInfo);
    const createBean = await that.app.comoBean.instance(data);
    const result = await that.service.base.create(createBean, that.useModel, '添加微信用户失败,请重试');
    return {
      user_id: result.dataValues.user_id,
      account_name: result.dataValues.account_name,
      nickname: result.dataValues.nickname,
      headimgurl: result.dataValues.headimgurl,
      openid: result.dataValues.openid,
      unionid: result.dataValues.unionid,
      is_office: result.dataValues.is_office,
      is_family: result.dataValues.is_family,
    };
  }

  /**
   * [userMoney 获取用户余额]
   * @return {[type]} [description]
   */
  async userMoney() {
    const that = this;
    try {
      const data = await that.ctx.validate(that.userMoneyValidate, await that.ctx.getParse());
      const result = await that.service.shop.getUserMoney(data.user_id);
      return that.ctx.appJson(that.app.szjcomo.appResult('SUCCESS', result, false));
    } catch (err) {
      return that.ctx.appJson(that.app.szjcomo.appResult(err.message));
    }
  }

  /**
   * [userMoney 获取用户账户余额]
   * @return {[type]} [description]
   */
  async userAccount() {
    const that = this;
    try {
      const data = await that.ctx.validate(that.userMoneyValidate, await that.ctx.getParse());
      const result = await that.service.shop.getUserAccount(data.user_id);
      return that.ctx.appJson(that.app.szjcomo.appResult('SUCCESS', result, false));
    } catch (err) {
      return that.ctx.appJson(that.app.szjcomo.appResult(err.message));
    }
  }

  /**
   * [userMoneyLog 用户资金明细]
   * @return {[type]} [description]
   */
  async userMoneyLog() {
    const that = this;
    try {
      const data = await that.ctx.validate(that.userMoneyValidate, await that.ctx.getParse());
      const selectBean = await that.app.comoBean.instance(data, {
        offset: (data.page - 1) * data.limit,
        limit: data.limit,
        where: { user_id: data.user_id },
        order: [[ 'log_id', 'desc' ]],
        attributes: [ 'log_id', 'log_desc', 'change_time', 'money', 'type', 'inviter_id', 'inviter_name', 'inviter_img' ],
      });
      const result = await that.service.base.select(selectBean, that.app.model.UsersMoneyLogs, '查询资金明细失败,请稍候重试', true, true);
      return that.ctx.appJson(that.app.szjcomo.appResult('SUCCESS', result, false));
    } catch (err) {
      return that.ctx.appJson(that.app.szjcomo.appResult(err.message));
    }
  }

  /**
   * [userMoneyLog 用户分佣明细]
   * @return {[type]} [description]
   */
  async userCommissionLog() {
    const that = this;
    try {
      const data = await that.ctx.validate(that.userMoneyValidate, await that.ctx.getParse());
      const selectBean = await that.app.comoBean.instance(data, {
        // offset: (data.page - 1) * data.limit, limit: data.limit,
        where: { user_id: data.user_id },
        order: [[ 'log_id', 'desc' ]],
        attributes: [ 'log_desc', 'create_time', 'commission', 'type', 'inviter_id', 'inviter_name', 'inviter_img' ],
      });
      // 2022/11/28 直接查询所有数据 不分页
      const result = await that.service.base.select(selectBean, that.app.model.UsersCommissionLogs, '查询分佣明细失败,请稍候重试', false, true);
      return that.ctx.appJson(that.app.szjcomo.appResult('SUCCESS', result, false));
    } catch (err) {
      return that.ctx.appJson(that.app.szjcomo.appResult(err.message));
    }
  }

  /**
   * [userMoneyLog 用户餐币明细]
   * @return {[type]} [description]
   */
  async coinDetail() {
    const that = this;
    try {
      const data = await that.ctx.validate(that.userMoneyValidate, await that.ctx.getParse());
      const selectBean = await that.app.comoBean.instance(data, {
        where: { user_id: data.user_id },
        order: [[ 'log_id', 'desc' ]],
      });
      // 2022/11/28 直接查询所有数据 不分页
      const result = await that.service.base.select(selectBean, that.app.model.DinnerCoinLogs, '查询分佣明细失败,请稍候重试', false, true);
      return that.ctx.appJson(that.app.szjcomo.appResult('SUCCESS', result, false));
    } catch (err) {
      return that.ctx.appJson(that.app.szjcomo.appResult(err.message));
    }
  }

  // 2023/2/28 用户餐饮币账户列表
  async userDiningCoin() {
    const that = this;
    try {
      const data = await that.ctx.validate(that.userMoneyValidate, await that.ctx.getParse());
      const selectBean = await that.app.comoBean.instance(data, {
        where: { user_id: data.user_id, expired: false },
      });
      // 2023/2/28 直接查询所有数据 不分页
      const result = await that.service.base.select(selectBean, that.app.model.DinnerCoins, '查询餐饮币账户失败,请稍候重试', false, true);
      return that.ctx.appJson(that.app.szjcomo.appResult('SUCCESS', result, false));
    } catch (err) {
      return that.ctx.appJson(that.app.szjcomo.appResult(err.message));
    }
  }

  /**
   * 用户指定商家餐币账户余额
   * @return {Promise<*>}
   */
  async userCouldTransferCoin() {
    const that = this;
    try {
      const data = await that.ctx.validate(that.userTransferValidate, await that.ctx.getParse());
      const res = await that.getCouldTransferCoin(data);
      return that.ctx.appJson(that.app.szjcomo.appResult('SUCCESS', { couldTransferCoins: res.account }, false));
    } catch (err) {
      return that.ctx.appJson(that.app.szjcomo.appResult(err.message));
    }
  }

  /**
   * 用户可在指定商家消费的餐币账户余额
   * @param data
   */
  async getCouldTransferCoin(data) {
    const that = this;
    if (!data.diningCoinCode) {
      throw new Error('参数错误');
    }
    const userInfo = await that.app.model.Users.findOne({
      where: { openid: data.diningCoinCode },
      attributes: [ 'user_id' ],
    });
    if (!userInfo || userInfo.user_id < 0) {
      throw new Error('参数错误');
    }
    const businessInfo = await that.app.model.Users.findOne({
      where: { user_id: data.user_id },
      attributes: [ 'partner_id' ],
    });
    if (!businessInfo || businessInfo.partner_id < 1) {
      throw new Error('抱歉,您不是源森家具的合作商户,无权收款。');
    }
    const seq = that.app.Sequelize;
    const selectBean = await that.app.comoBean.instance({}, {
      where: {
        user_id: userInfo.user_id,
        // partner_id: businessInfo.partner_id,
        // 2023/4/11 补充通用餐币
        partner_id: { [seq.Op.in]: [ businessInfo.partner_id, 1 ] },
        expired: false,
      },
      attributes: [[ seq.fn('sum', seq.col('account')), 'account' ]],
    });
    const result = await that.service.base.select(selectBean, that.app.model.DinnerCoins, '查询餐饮币账户余额失败,请稍候重试', false, false);
    const res = JSON.parse(JSON.stringify(result));
    res.customer_id = userInfo.user_id;
    res.partner_id = businessInfo.partner_id;
    res.business_id = data.user_id;
    return res;
  }

  /**
   * 商家可提现餐币金额
   * @return {Promise<*>}
   */
  async businessDiningCoinCouldCash() {
    const that = this;
    try {
      const data = await that.ctx.validate(that.businessCashCoinValidate, await that.ctx.getParse());
      const res = await that.getDiningCoinCouldCash(data);
      return that.ctx.appJson(that.app.szjcomo.appResult('SUCCESS', res, false));
    } catch (err) {
      return that.ctx.appJson(that.app.szjcomo.appResult(err.message));
    }
  }

  /**
   * 商家可提现餐币金额
   * @param data
   */
  async getDiningCoinCouldCash(data) {
    const that = this;
    const businessInfo = await that.app.model.Users.findOne({
      where: { user_id: data.user_id },
    });
    if (!businessInfo || businessInfo.partner_id < 0) {
      throw new Error('您的账号还没有绑定的合作商铺哦');
    }
    const partnerInfo = await that.app.model.PartnerInfo.findOne({
      where: { id: businessInfo.partner_id },
    });
    if (!partnerInfo || partnerInfo.user_id !== data.user_id) {
      throw new Error('您的账号没有权限提现餐费哦');
    }
    const seq = that.app.Sequelize;
    const currentDateTime = that.app.szjcomo.date('Y-m-d H:i:s');
    const sevenDayTime = 24 * 60 * 60 * 1000; // 2023/3/1 24小时后可提现
    const endTimeStamp = Date.parse(currentDateTime) - sevenDayTime;
    const endDateTime = that.app.szjcomo.date('Y-m-d H:i:s', endTimeStamp / 1000);
    // 2023/3/1 查询24小时前的所得餐币总和 以及所有时间提现的总和 再求和 即为 可提现餐币金额
    // todo : 特殊情况 商家管理员有自家绑定的商铺 餐币消费支出
    const selectBean = await that.app.comoBean.instance({}, {
      where: {
        user_id: businessInfo.user_id,
        partner_id: businessInfo.partner_id,
        create_time: { [seq.Op.lte]: endDateTime },
        account: { [seq.Op.gte]: 0 },
      },
      attributes: [[ seq.fn('sum', seq.col('account')), 'account' ]],
    });
    const coinResult = await that.service.base.select(selectBean, that.app.model.DinnerCoinLogs, '查询商家可提现餐币金额失败,请稍候重试', false, false);
    const selectBean2 = await that.app.comoBean.instance({}, {
      where: {
        user_id: businessInfo.user_id,
        partner_id: businessInfo.partner_id,
        account: { [seq.Op.lte]: 0 },
        type: { [seq.Op.ne]: -1 },
      },
      attributes: [[ seq.fn('sum', seq.col('account')), 'account' ]],
    });
    const cashResult = await that.service.base.select(selectBean2, that.app.model.DinnerCoinLogs, '查询商家可提现餐币金额失败,请稍候重试', false, false);
    const coinRes = JSON.parse(JSON.stringify(coinResult));
    const cashRes = JSON.parse(JSON.stringify(cashResult));
    const couldCash = new Decimal(coinRes.account ? coinRes.account : 0)
      .add(new Decimal(cashRes.account ? cashRes.account : 0))
      .toNumber();
    coinRes.all_coin_could_cash = couldCash > 0 ? couldCash : 0;
    coinRes.all_cash = cashRes.account;
    coinRes.partner_id = businessInfo.partner_id;
    coinRes.partner_fees = partnerInfo.partner_fees;
    return coinRes;
  }

  /**
   * 商家申请核销餐币
   * @return {Promise<void>}
   */
  async coinTransfer() {
    const that = this;
    const seq = that.app.Sequelize;
    const transaction = await that.app.model.transaction();
    try {
      const data = await that.ctx.validate(that.coinTransferValidate, await that.ctx.postParse());
      // 2023/2/28 获取可核销餐币
      const intervalTime = Date.parse(that.app.szjcomo.date('Y-m-d H:i:s')) - data.time;
      if (intervalTime > 10 * 60 * 1000) {
        throw new Error('顾客付款码已超时失效,请重新扫码!');
      }
      const transferParams = await that.getCouldTransferCoin(data);
      if (data.coinAmount > 0 && data.coinAmount <= transferParams.account) {
        // 2023/2/28 发起核销收取餐币
        const partnerInfo = await that.app.model.PartnerInfo.findOne({
          where: { id: transferParams.partner_id },
        });
        // 2023/4/12 核销餐币 包含通用电子餐币
        const selectBean = await that.app.comoBean.instance({}, {
          where: {
            user_id: transferParams.customer_id,
            // partner_id: transferParams.partner_id,
            partner_id: { [seq.Op.in]: [ transferParams.partner_id, 1 ] },
            expired: false,
          },
          order: [[ 'partner_id', 'desc' ], [ 'ori_partner', 'desc' ]],
        });
        // 2023/2/28 查询所有指定商家餐币
        const result = await that.service.base.select(selectBean, that.app.model.DinnerCoins, '查询餐饮币账户失败,请稍候重试', false, true);
        const customerAccounts = [];
        let needAccount = 0;
        for (const resultElement of result) {
          needAccount += resultElement.account;
          customerAccounts.push(JSON.parse(JSON.stringify(resultElement)));
          if (needAccount >= data.coinAmount) {
            break;
          }
        }
        let firstCoinAmount;
        let secondCoinAmount;
        let thirdCoinAmount;
        let fourthCoinAmount;
        let incomeCoinAmount = 0;
        switch (customerAccounts.length) {
          case 1:
            firstCoinAmount = data.coinAmount;
            secondCoinAmount = 0;
            thirdCoinAmount = 0;
            fourthCoinAmount = 0;
            break;
          case 2:
            firstCoinAmount = customerAccounts[0].account;
            secondCoinAmount = data.coinAmount - firstCoinAmount;
            thirdCoinAmount = 0;
            fourthCoinAmount = 0;
            break;
          case 3:
            firstCoinAmount = customerAccounts[0].account;
            secondCoinAmount = customerAccounts[1].account;
            thirdCoinAmount = data.coinAmount - firstCoinAmount - secondCoinAmount;
            fourthCoinAmount = 0;
            break;
          case 4:
            firstCoinAmount = customerAccounts[0].account;
            secondCoinAmount = customerAccounts[1].account;
            thirdCoinAmount = customerAccounts[2].account;
            fourthCoinAmount = data.coinAmount - firstCoinAmount - secondCoinAmount - thirdCoinAmount;
            break;
          default:
            break;
        }
        // =========================================== 2023/3/1 第一个账户划账======================================
        await that.doTransferCoins(that, transferParams, firstCoinAmount, partnerInfo, transaction, customerAccounts, 0);
        incomeCoinAmount += firstCoinAmount * (customerAccounts[0].ori_partner ? partnerInfo.rate_from_partner : partnerInfo.rate_default);
        // =============================== 2023/3/1 需要第二个账户来继续划账 ==========================================
        if (customerAccounts.length > 1 && secondCoinAmount > 0) {
          await that.doTransferCoins(that, transferParams, secondCoinAmount, partnerInfo, transaction, customerAccounts, 1);
          incomeCoinAmount += secondCoinAmount * (customerAccounts[1].ori_partner ? partnerInfo.rate_from_partner : partnerInfo.rate_default);
        }
        // =============================== 2023/3/18 需要第三个账户来继续划账 ==========================================
        if (customerAccounts.length > 2 && thirdCoinAmount > 0) {
          await that.doTransferCoins(that, transferParams, thirdCoinAmount, partnerInfo, transaction, customerAccounts, 2);
          incomeCoinAmount += thirdCoinAmount * (customerAccounts[2].ori_partner ? partnerInfo.rate_from_partner : partnerInfo.rate_default);
        }
        // =============================== 2023/3/18 需要第四个账户来继续划账 ==========================================
        if (customerAccounts.length > 3 && fourthCoinAmount > 0) {
          await that.doTransferCoins(that, transferParams, fourthCoinAmount, partnerInfo, transaction, customerAccounts, 3);
          incomeCoinAmount += fourthCoinAmount * (customerAccounts[3].ori_partner ? partnerInfo.rate_from_partner : partnerInfo.rate_default);
        }
        await transaction.commit();
        incomeCoinAmount = incomeCoinAmount.toFixed(2);
        return that.ctx.appJson(that.app.szjcomo.appResult('SUCCESS', {
          incomeCoinAmount,
          transferCoinAmount: data.coinAmount,
        }, false));
      }
      throw new Error('输入的核销金额有误,请稍后重试');
    } catch (e) {
      if (transaction) transaction.rollback();
      return that.ctx.appJson(that.app.szjcomo.appResult(e.message));
    }
  }

  // 2023/3/1 餐币划账 具体逻辑和操作
  async doTransferCoins(that, transferParams, coinAmount, partnerInfo, transaction, customerAccounts, index) {
    // 2023/3/6 获取顾客信息
    const customerInfo = await that.app.model.Users.findOne({
      where: { user_id: transferParams.customer_id },
      transaction,
      raw: true,
    });
    // 2023/3/1 扣去顾客餐币
    await that.service.diningCoin.addDiningCoinChangeLog({
      user_id: transferParams.customer_id,
      order_id: -1,
      partner_id: customerAccounts[index].partner_id,
      type: 3,
      account: -coinAmount,
      log_desc: partnerInfo.name + ' 消费',
    }, transaction);
    // 2023/3/1 更新顾客账户
    const customerAccountBean = await that.app.comoBean.instance({
      account: customerAccounts[index].account - coinAmount,
      update_time: that.app.szjcomo.date('Y-m-d H:i:s'),
    }, {
      where: {
        user_id: transferParams.customer_id,
        ori_partner: customerAccounts[index].ori_partner,
        partner_id: customerAccounts[index].partner_id,
        expired: false,
      }, transaction,
    });
    if (customerAccounts[index].account === coinAmount) {
      // 2023/3/1 删除0元账户
      await that.service.base.delete(customerAccountBean, that.app.model.DinnerCoins, '顾客餐饮币清零更新失败,请重试');
    } else {
      await that.service.base.update(customerAccountBean, that.app.model.DinnerCoins, '顾客餐饮币余额更新失败,请重试');
    }
    // 2023/3/1 划入商家账户记录
    const businessCoinAmount = coinAmount * (customerAccounts[index].ori_partner ? partnerInfo.rate_from_partner : partnerInfo.rate_default);
    await that.service.diningCoin.addDiningCoinChangeLog({
      user_id: transferParams.business_id,
      order_id: -1,
      partner_id: transferParams.partner_id,
      type: 4,
      account: businessCoinAmount,
      log_desc: '核销收取餐币',
      ori_partner: customerAccounts[index].ori_partner,
      customer_id: customerInfo.user_id,
      customer_name: customerInfo.nickname,
      customer_img: customerInfo.headimgurl,
    }, transaction);
    // 2023/2/28 查询商家餐饮币账户列表 添加 或 更新账户余额
    const info = await that.app.model.DinnerCoins.findOne({
      where: {
        user_id: transferParams.business_id,
        // ori_partner: customerAccounts[index].ori_partner,
        partner_id: transferParams.partner_id,
        expired: false,
      },
      transaction,
      raw: true,
    });
    if (!info) {
      // 2023/2/27 没有对应类型的餐饮币 则插入该类型的餐饮币账户
      const createData = {
        user_id: transferParams.business_id,
        account: businessCoinAmount,
        // ori_partner: customerAccounts[index].ori_partner,
        ori_partner: true,
        partner_id: transferParams.partner_id,
        create_time: that.app.szjcomo.date('Y-m-d H:i:s'),
        expired: false,
        expired_time: that.app.szjcomo.date('Y-m-d H:i:s', parseInt(+new Date() + '') / 1000 + 90 * 24 * 60 * 60),
      };
      createData.partner_name = partnerInfo.name;
      createData.partner_address = partnerInfo.address;
      createData.partner_tel = partnerInfo.tel_num;
      createData.partner_opening_time = partnerInfo.opening_time;
      const createBean = await that.app.comoBean.instance(createData, { transaction });
      await that.service.base.create(createBean, that.app.model.DinnerCoins, '餐饮币发放失败,请重试');
    } else {
      const updateBean = await that.app.comoBean.instance({
        account: info.account + businessCoinAmount,
        update_time: that.app.szjcomo.date('Y-m-d H:i:s'),
        expired: false,
        expired_time: that.app.szjcomo.date('Y-m-d H:i:s', parseInt(+new Date() + '') / 1000 + 90 * 24 * 60 * 60),
      }, {
        where: {
          user_id: transferParams.business_id,
          // ori_partner: customerAccounts[index].ori_partner,
          partner_id: transferParams.partner_id,
        }, transaction,
      });
      await that.service.base.update(updateBean, that.app.model.DinnerCoins, '餐饮币余额更新失败,请重试');
    }
  }

  /**
   * 用户可提现金额(求和)
   * @return {Promise<*>}
   */
  async userCommissionCouldCash() {
    const that = this;
    try {
      const data = await that.ctx.validate(that.userMoneyValidate, await that.ctx.getParse());
      const result = await that.getCouldCashCommission(data.user_id);
      return that.ctx.appJson(that.app.szjcomo.appResult('SUCCESS', result, false));
    } catch (err) {
      return that.ctx.appJson(that.app.szjcomo.appResult(err.message));
    }
  }

  /**
   * 获取用户可提现金额(求和)
   * @return {Promise<void>}
   */
  async getCouldCashCommission(user_id = -1) {
    if (user_id <= 0) {
      throw new Error('参数错误');
    }
    const that = this;
    const seq = that.app.Sequelize;
    const currentDateTime = that.app.szjcomo.date('Y-m-d H:i:s');
    const sevenDayTime = 7 * 24 * 60 * 60 * 1000;
    const endTimeStamp = Date.parse(currentDateTime) - sevenDayTime;
    const endDateTime = that.app.szjcomo.date('Y-m-d H:i:s', endTimeStamp / 1000);
    // 2022/11/28 查询7天前的所得分佣总和 以及所有时间得提现总和 再求和 即为 可提现金额
    const selectBean = await that.app.comoBean.instance({ user_id }, {
      where: { user_id, create_time: { [seq.Op.lte]: endDateTime }, commission: { [seq.Op.gte]: 0 } },
      attributes: [ 'user_id', [ seq.fn('sum', seq.col('commission')), 'all_commission' ]],
    });
    const commissionResult = await that.service.base.select(selectBean, that.app.model.UsersCommissionLogs, '查询佣金失败,请稍候重试', false, false);
    const selectBean2 = await that.app.comoBean.instance({ user_id }, {
      where: { user_id, commission: { [seq.Op.lte]: 0 }, type: { [seq.Op.ne]: -1 } }, // type-1提现失败类型
      attributes: [ 'user_id', [ seq.fn('sum', seq.col('commission')), 'all_cash' ]],
    });
    const cashResult = await that.service.base.select(selectBean2, that.app.model.UsersCommissionLogs, '查询佣金失败,请稍候重试', false, false);
    const commRes = JSON.parse(JSON.stringify(commissionResult));
    const cashRes = JSON.parse(JSON.stringify(cashResult));
    commRes.all_commission_could_cash = new Decimal(commRes.all_commission ? commRes.all_commission : 0)
      .add(new Decimal(cashRes.all_cash ? cashRes.all_cash : 0))
      .toNumber();
    commRes.all_cash = cashRes.all_cash;
    return commRes;
  }

  /**
   * 用户佣金提现
   * @return {Promise<void>}
   */
  async userCashOut() {
    const that = this;
    try {
      const data = await that.ctx.validate(that.cashOutValidate, await that.ctx.postParse());
      // 2023/1/17 获取可提现佣金额度
      const res = await that.getCouldCashCommission(data.user_id);
      if (data.cash_amount >= 0.1 && data.cash_amount <= res.all_commission_could_cash) {
        // 2023/1/31 发起提现
        // todo : 用户分佣提现 1.扣取税费;2.用户分佣转通用电子餐费;
        const result = await that.service.wxPay.transfer(data);
        // 2023/1/31 提现状态
        if (result.status != 200) {
          throw new Error('提现转账出现异常,请联系客服后再重试');
        }
        return that.ctx.appJson(that.app.szjcomo.appResult('SUCCESS', result, false));
      }
      throw new Error('输入提现金额有误,请稍后重试');
    } catch (e) {
      return that.ctx.appJson(that.app.szjcomo.appResult(e.message));
    }
  }

  /**
   * 用户佣金转电子餐费
   * @return {Promise<void>}
   */
  async commission2DiningCoin() {

  }

  /**
   * 商家餐币提现
   * @return {Promise<*>}
   */
  async userCoinCashOut() {
    const that = this;
    try {
      const data = await that.ctx.validate(that.cashOutValidate, await that.ctx.postParse());
      // 2023/1/17 获取可提现佣金额度
      const res = await that.getDiningCoinCouldCash(data);
      data.partner_id = res.partner_id;
      if (data.cash_amount >= 0.1 && data.cash_amount <= (res.all_coin_could_cash - res.partner_fees)) {
        // 2023/1/31 发起提现
        const result = await that.service.businessPayService.transfer(data);
        // 2023/1/31 提现状态
        if (result.status != 200) {
          throw new Error('提现转账出现异常,请联系客服后再重试');
        }
        return that.ctx.appJson(that.app.szjcomo.appResult('SUCCESS', result, false));
      }
      throw new Error('输入提现金额有误,请稍后重试');
    } catch (e) {
      return that.ctx.appJson(that.app.szjcomo.appResult(e.message));
    }
  }

  /**
   * [newUserBenefits 查询新用户福利]
   * @return {[type]} [description]
   */
  async newUserBenefits() {
    const that = this;
    try {
      const data = await that.ctx.validate(that.userMoneyValidate, await that.ctx.getParse());
      const seq = that.app.Sequelize;
      const selectBean = await that.app.comoBean.instance(data, {
        offset: (data.page - 1) * data.limit, limit: data.limit, where: {
          user_id: data.user_id,
          type: { [seq.Op.in]: [ 1, 2 ] },
        },
        order: [[ 'type', 'asc' ]],
      });
      const result = await that.service.base.select(selectBean, that.app.model.UsersMoneyLogs, '新用户福利查询失败,请稍候重试', true, true);
      return that.ctx.appJson(that.app.szjcomo.appResult('SUCCESS', result, false));
    } catch (err) {
      return that.ctx.appJson(that.app.szjcomo.appResult(err.message));
    }
  }

  /**
   * 更新用户信息
   * @date:2023/10/20
   */
  async updateUserInfo() {
    const that = this;
    try {
      const data = await that.ctx.validate(that.updateValidate, await that.ctx.anyParse());
      // 2023/10/20  更新用户信息
      const dataParam = {};
      if (data.is_office) {
        dataParam.is_office = true;
      }
      if (data.is_family) {
        dataParam.is_family = true;
      }
      dataParam.update_ttime = that.app.szjcomo.date('Y-m-d H:i:s');
      const updateBean = await that.app.comoBean.instance(dataParam, { where: { user_id: data.user_id } });
      const result = await that.service.base.update(updateBean, that.useModel, '微信用户信息更新失败,请重试');
      return that.ctx.appJson(that.app.szjcomo.appResult('SUCCESS', result, false));
    } catch (e) {
      return that.ctx.appJson(that.app.szjcomo.appResult(e.message));
    }
  }

};