Forráskód Böngészése

Merge branch 'dev'

lrf 2 éve
szülő
commit
17f20d8665

+ 2 - 2
app/controller/shop/config/.shop.js

@@ -1,6 +1,6 @@
 module.exports = {
   create: {
-    requestBody: ['qrcode', 'goods_score', 'send_score', 'service_score', 'logo', 'name', 'code', 'person', 'phone', 'address', 'file', 'status'],
+    requestBody: ['cut', 'qrcode', 'goods_score', 'send_score', 'service_score', 'logo', 'name', 'code', 'person', 'phone', 'address', 'file', 'status'],
   },
   destroy: {
     params: ['!id'],
@@ -8,7 +8,7 @@ module.exports = {
   },
   update: {
     params: ['!id'],
-    requestBody: ['qrcode', 'goods_score', 'send_score', 'service_score', 'logo', 'name', 'code', 'person', 'phone', 'address', 'file', 'status'],
+    requestBody: ['cut', 'qrcode', 'goods_score', 'send_score', 'service_score', 'logo', 'name', 'code', 'person', 'phone', 'address', 'file', 'status'],
   },
   show: {
     parameters: {

+ 39 - 0
app/controller/shop/config/.shopCashOut.js

@@ -0,0 +1,39 @@
+module.exports = {
+  create: {
+    requestBody: ['money', 'shop', 'apply_time', 'deal_person', 'exam_time', 'card', 'card_name', 'card_bank', 'status'],
+  },
+  destroy: {
+    params: ['!id'],
+    service: 'delete',
+  },
+  update: {
+    params: ['!id'],
+    requestBody: ['money', 'shop', 'apply_time', 'deal_person', 'exam_time', 'card', 'card_name', 'card_bank', 'status'],
+  },
+  show: {
+    parameters: {
+      params: ['!id'],
+    },
+    service: 'fetch',
+  },
+  index: {
+    parameters: {
+      query: {
+        'meta.createdAt@start': 'meta.createdAt@start',
+        'meta.createdAt@end': 'meta.createdAt@end',
+        shop: 'shop',
+        status: 'status',
+      },
+      // options: {
+      //   "meta.state": 0 // 默认条件
+      // },
+    },
+    service: 'query',
+    options: {
+      query: ['skip', 'limit'],
+      sort: ['meta.createdAt'],
+      desc: true,
+      count: true,
+    },
+  },
+};

+ 43 - 0
app/controller/shop/config/.shopInBill.js

@@ -0,0 +1,43 @@
+module.exports = {
+  create: {
+    requestBody: ['total', 'receipts', 'shop', 'cut', 'time', 'source', 'source_id'],
+  },
+  destroy: {
+    params: ['!id'],
+    service: 'delete',
+  },
+  update: {
+    params: ['!id'],
+    requestBody: ['total', 'receipts', 'shop', 'cut', 'time', 'source', 'source_id'],
+  },
+  show: {
+    parameters: {
+      params: ['!id'],
+    },
+    service: 'fetch',
+  },
+  index: {
+    parameters: {
+      query: {
+        'time@start': 'time@start',
+        'time@end': 'time@end',
+        shop: 'shop',
+        source: 'source',
+        source_id: 'source_id',
+      },
+      // options: {
+      //   "meta.state": 0 // 默认条件
+      // },
+    },
+    service: 'query',
+    options: {
+      query: ['skip', 'limit'],
+      sort: ['meta.createdAt'],
+      desc: true,
+      count: true,
+    },
+  },
+  computedTotal: {
+    params: ['!shop'],
+  },
+};

+ 13 - 0
app/controller/shop/shopCashOut.js

@@ -0,0 +1,13 @@
+'use strict';
+const meta = require('./config/.shopCashOut.js');
+const Controller = require('egg').Controller;
+const { CrudController } = require('naf-framework-mongoose-free/lib/controller');
+
+// 
+class ShopCashOutController extends Controller {
+  constructor(ctx) {
+    super(ctx);
+    this.service = this.ctx.service.shop.shopCashOut;
+  }
+}
+module.exports = CrudController(ShopCashOutController, meta);

+ 13 - 0
app/controller/shop/shopInBill.js

@@ -0,0 +1,13 @@
+'use strict';
+const meta = require('./config/.shopInBill.js');
+const Controller = require('egg').Controller;
+const { CrudController } = require('naf-framework-mongoose-free/lib/controller');
+
+// 
+class ShopInBillController extends Controller {
+  constructor(ctx) {
+    super(ctx);
+    this.service = this.ctx.service.shop.shopInBill;
+  }
+}
+module.exports = CrudController(ShopInBillController, meta);

+ 2 - 2
app/controller/util.js

@@ -14,8 +14,8 @@ class UtilController extends Controller {
     this.tradeService = this.ctx.service.util.trade;
   }
   async util() {
-    await this.ctx.service.view.order.allOrder();
-    this.ctx.ok();
+    const res = this.ctx.multiply(this.ctx.minus(1, this.ctx.divide(0, 100)), 200);
+    this.ctx.ok({ data: res });
   }
 
   async crk() {

+ 1 - 0
app/model/shop/shop.js

@@ -16,6 +16,7 @@ const shop = {
   send_score: { type: Number, required: false, default: 5, zh: '发货评分' }, //
   service_score: { type: Number, required: false, default: 5, zh: '服务评分' }, //
   qrcode: { type: Array, required: false, zh: '二维码' }, //
+  cut: { type: Number, required: false, zh: '抽成比例' }, //
 };
 const schema = new Schema(shop, { toJSON: { getters: true, virtuals: true } });
 schema.index({ id: 1 });

+ 30 - 0
app/model/shop/shopCashOut.js

@@ -0,0 +1,30 @@
+'use strict';
+const Schema = require('mongoose').Schema;
+const metaPlugin = require('naf-framework-mongoose-free/lib/model/meta-plugin');
+
+const MoneyPlugin = require('naf-framework-mongoose-free/lib/model/type-money-plugin');
+
+// 店铺提现申请
+const shopCashOut = {
+  shop: { type: String, required: false, zh: '店铺', ref: 'Shop.Shop' }, //
+  apply_time: { type: String, required: false, zh: '申请时间' }, //
+  deal_person: { type: String, required: false, zh: '审核处理人', ref: 'User.admin' }, //
+  exam_time: { type: String, required: false, zh: '审核时间' }, //
+  card: { type: String, required: false, zh: '银行卡号' }, //
+  card_name: { type: String, required: false, zh: '银行卡所属' }, //
+  card_bank: { type: String, required: false, zh: '所属银行' }, //
+  status: { type: String, required: false, default: '0', zh: '审核状态' }, // 字典表:withdrawal_exam_status
+};
+const schema = new Schema(shopCashOut, { toJSON: { getters: true, virtuals: true } });
+schema.index({ id: 1 });
+schema.index({ 'meta.createdAt': 1 });
+schema.index({ shop: 1 });
+schema.index({ status: 1 });
+
+schema.plugin(metaPlugin);
+schema.plugin(MoneyPlugin({ zh: '提现金额', required: false, key: 'money' }));
+
+module.exports = app => {
+  const { mongoose } = app;
+  return mongoose.model('ShopCashOut', schema, 'shopCashOut');
+};

+ 30 - 0
app/model/shop/shopInBill.js

@@ -0,0 +1,30 @@
+'use strict';
+const Schema = require('mongoose').Schema;
+const metaPlugin = require('naf-framework-mongoose-free/lib/model/meta-plugin');
+
+const MoneyPlugin = require('naf-framework-mongoose-free/lib/model/type-money-plugin');
+
+// 店铺流水
+// 如果是入账,则有抽成比例,总金额.出账则不需要抽成比例和总金额
+const shopInBill = {
+  shop: { type: String, required: false, zh: '店铺', ref: 'Shop.Shop' }, //
+  cut: { type: Number, required: false, zh: '抽成比例' }, //
+  time: { type: String, required: false, zh: '流水时间' }, //
+  source: { type: String, required: false, zh: '来源' }, // 字典:cashBack_source
+  source_id: { type: String, required: false, zh: '来源id' }, //
+};
+const schema = new Schema(shopInBill, { toJSON: { getters: true, virtuals: true } });
+schema.index({ id: 1 });
+schema.index({ 'meta.createdAt': 1 });
+schema.index({ shop: 1 });
+schema.index({ source: 1 });
+schema.index({ source_id: 1 });
+
+schema.plugin(metaPlugin);
+schema.plugin(MoneyPlugin({ zh: '总金额', required: false, key: 'total' }));
+schema.plugin(MoneyPlugin({ zh: '净金额', required: false, key: 'receipts' }));
+
+module.exports = app => {
+  const { mongoose } = app;
+  return mongoose.model('ShopInBill', schema, 'shopInBill');
+};

+ 43 - 0
app/service/shop/shopCashOut.js

@@ -0,0 +1,43 @@
+'use strict';
+const { CrudService } = require('naf-framework-mongoose-free/lib/service');
+const { BusinessError, ErrorCode } = require('naf-core').Error;
+const _ = require('lodash');
+const assert = require('assert');
+const moment = require('moment');
+
+//
+class ShopCashOutService extends CrudService {
+  constructor(ctx) {
+    super(ctx, 'shopcashout');
+    this.model = this.ctx.model.Shop.ShopCashOut;
+    this.shopInBillModel = this.ctx.model.Shop.ShopInBill;
+  }
+  async beforeCreate(data) {
+    const { shop } = data;
+    if (!shop) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '缺少提款人');
+    const num = await this.model.count({ shop, status: '0' });
+    if (num > 0) throw new BusinessError(ErrorCode.DATA_EXISTED, '您有未处理提现申请,请联系管理员先处理之前的申请');
+    return data;
+  }
+
+  async beforeUpdate(filter, update) {
+    if (_.get(update, 'status') !== '0') {
+      update.deal_person = _.get(this.ctx, 'admin._id');
+    }
+    return { filter, update };
+  }
+
+  async afterUpdate(filter, body, data) {
+    const { status } = body;
+    if (status === '1') {
+      const { money: receipts, shop } = data;
+      const obj = { shop, receipts, time: moment().format('YYYY-MM-DD HH:mm:ss'), status: '-1', source: '-1', source_id: data._id };
+      const num = await this.shopInBillModel.count({ shop, status: '-1', source: '-1', source_id: data._id });
+      // 说明该申请没有流水,添加流水;有流水就不加了
+      if (num <= 0) await this.shopInBillModel.create(obj);
+    }
+    return data;
+  }
+}
+
+module.exports = ShopCashOutService;

+ 107 - 0
app/service/shop/shopInBill.js

@@ -0,0 +1,107 @@
+'use strict';
+const { CrudService } = require('naf-framework-mongoose-free/lib/service');
+const { BusinessError, ErrorCode } = require('naf-core').Error;
+const _ = require('lodash');
+const assert = require('assert');
+const moment = require('moment');
+
+//
+class ShopInBillService extends CrudService {
+  constructor(ctx) {
+    super(ctx, 'shopinbill');
+    this.model = this.ctx.model.Shop.ShopInBill;
+    this.shopModel = this.ctx.model.Shop.Shop;
+    this.orderUtil = this.ctx.service.util.orderDetail;
+    this.configModel = this.ctx.model.System.Config;
+  }
+  /**
+   * 正常购物创建店铺流水
+   * @param {object} orderDetail 订单详情数据
+   * @param {Transaction} tran 数据库事务
+   */
+  async createByOrder(orderDetail, tran) {
+    const obj = { shop: _.get(orderDetail, 'shop') };
+    const shopData = await this.shopModel.findById(_.get(orderDetail, 'shop'), { cut: 1 });
+    if (!shopData) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到店铺数据');
+    obj.cut = _.get(shopData, 'cut', 0);
+    const real_pay = this.orderUtil.computedRealPay(orderDetail);
+    obj.total = real_pay;
+    obj.receipts = this.ctx.multiply(this.ctx.minus(1, this.ctx.divide(obj.cut, 100)), real_pay);
+    obj.time = moment().format('YYYY-MM-DD HH:mm:ss');
+    obj.source = '3';
+    obj.source_id = _.get(orderDetail, '_id');
+    const num = await this.model.count({ source: obj.source, source_id: obj.source_id });
+    if (num <= 0) tran.insert('ShopInBill', obj);
+  }
+
+  /**
+   * 售后创建流水
+   * @param {object} afterSale 订单详情数据
+   * @param {number} returnMoney 退款金额
+   * @param {Transaction} tran 数据库事务
+   */
+  async createByAfterSale(afterSale, returnMoney, tran) {
+    const query = { source_id: _.get(afterSale, 'order_detail'), source: '3' };
+    const inBill = await this.model.findOne(query);
+    // 该订单没有入账,就不需要退
+    if (!inBill) return;
+    const q2 = { source: '-3', source_id: _.get(afterSale, '_id') };
+    const n2 = await this.model.count(q2);
+    // 有过售后退钱记录,不需要再生成
+    if (n2 > 0) return;
+    const obj = { shop: _.get(afterSale, 'shop') };
+    obj.time = moment().format('YYYY-MM-DD HH:mm:ss');
+    obj.source = '-3';
+    obj.source_id = _.get(afterSale, '_id');
+    const limit = _.get(inBill, 'receipts');
+    if (this.ctx.minus(limit, returnMoney) >= 0) obj.receipts = returnMoney;
+    else obj.receipts = limit;
+    tran.insert('ShopInBill', obj);
+  }
+
+  async computedTotal({ shop }) {
+    const list = await this.model.find({ shop }).lean();
+    const config = await this.configModel.findOne({}, { reward_day: 1 }).lean();
+    const rd = _.get(config, 'reward_day', 14);
+    const min = this.ctx.multiply(rd, this.ctx.multiply(24, 60));
+    let total = 0;
+    for (const i of list) {
+      const { source, receipts: money } = i;
+      const sn = parseInt(source);
+      if (sn >= 0) total = this.ctx.plus(total, money);
+      else total = this.ctx.minus(total, money);
+    }
+    let canGet = 0;
+    const inBill = list.filter(f => parseInt(f.source) >= 0);
+    const outBill = list.filter(f => parseInt(f.source) < 0);
+    const getOutBill = list.filter(f => f.source === '-1');
+    const outBillMoney = getOutBill.reduce((p, n) => this.ctx.plus(p, n.money), 0);
+    for (const i of inBill) {
+      const cAt = _.get(i, 'time');
+      const m = moment().diff(cAt, 'm');
+      if (m >= min) {
+        // 已经过了提款时间,那就再找下,是否有该记录相应的退款
+        const { receipts: money, source_id } = i;
+        let cg = money;
+        const os = outBill.filter(f => f.source_id === source_id);
+        for (const o of os) {
+          cg = this.ctx.minus(cg, o.receipts);
+        }
+        canGet = this.ctx.plus(canGet, cg);
+      }
+    }
+    canGet = this.ctx.minus(canGet, outBillMoney);
+    return { total, canGet };
+  }
+
+  async afterQuery(filter, data) {
+    for (const i of data) {
+      const { source } = i;
+      if (parseInt(source) >= 0) i.receipts = `+${i.receipts}`;
+      else i.receipts = `-${i.receipts}`;
+    }
+    return data;
+  }
+}
+
+module.exports = ShopInBillService;

+ 2 - 0
app/service/trade/afterSale.js

@@ -198,6 +198,8 @@ class AfterSaleService extends CrudService {
     const refundInfo = { reason: _.get(data, 'desc', '购物退款'), money: returnMoney, order_no, out_refund_no };
     // 退积分
     await this.ctx.service.user.point.refundOrderPoint(order_detail, tran);
+    // 退商铺的入账流水金额
+    await this.ctx.service.shop.shopInBill.createByAfterSale(data, returnMoney, tran);
     return refundInfo;
   }
   /**

+ 9 - 9
app/service/trade/orderDetail.js

@@ -26,10 +26,10 @@ class OrderDetailService extends CrudService {
     if (goods_id) {
       // 传来指定商品,查有该商品的订单,但是如果没有,就查每一项中是否有 shop_transport_no 和 shop_transport_type
       // 如果有这俩属性,说明也有单子,也查出来
-      toSearch = transport.filter(f => _.isArray(f.goods) && f.goods.find(fg => fg.goods_id === goods_id));
+      toSearch = transport.filter((f) => _.isArray(f.goods) && f.goods.find((fg) => fg.goods_id === goods_id));
       console.log(toSearch);
       if (toSearch.length <= 0) {
-        toSearch = transport.filter(f => f.shop_transport_no && f.shop_transport_type);
+        toSearch = transport.filter((f) => f.shop_transport_no && f.shop_transport_type);
       }
     } else {
       toSearch = transport;
@@ -86,7 +86,6 @@ class OrderDetailService extends CrudService {
     // await this.model.insertMany(list);
   }
 
-
   /**
    * 将商品规格列表中,优惠的部分提取出来,分单用
    * @param {Array} goodsList 某店的商品列表
@@ -130,10 +129,10 @@ class OrderDetailService extends CrudService {
     const rate = await this.goodsRateModel.find({ orderDetail: res._id });
     const goods = _.get(res, 'goods', []);
     for (const g of goods) {
-      const r = afterSale.find(f => ObjectId(_.get(f, 'goods._id')).equals(g._id));
+      const r = afterSale.find((f) => ObjectId(_.get(f, 'goods._id')).equals(g._id));
       if (r) g.is_afterSale = true;
       else g.is_afterSale = false;
-      const r2 = rate.find(f => ObjectId(_.get(f, 'goodsSpec')).equals(g._id));
+      const r2 = rate.find((f) => ObjectId(_.get(f, 'goodsSpec')).equals(g._id));
       if (r2) {
         g.is_rate = true;
         g.rate = r2._id;
@@ -179,7 +178,7 @@ class OrderDetailService extends CrudService {
     if (sort && _.isString(sort)) {
       sort = { [sort]: desc ? -1 : 1 };
     } else if (sort && _.isArray(sort)) {
-      sort = sort.map(f => ({ [f]: desc ? -1 : 1 })).reduce((p, c) => ({ ...p, ...c }), {});
+      sort = sort.map((f) => ({ [f]: desc ? -1 : 1 })).reduce((p, c) => ({ ...p, ...c }), {});
     }
     let condition = _.cloneDeep(filter);
     condition = await this.beforeQuery(condition);
@@ -266,7 +265,7 @@ class OrderDetailService extends CrudService {
       for (const og of obj.goods) {
         const { file = [], _id: goodsSpec } = og;
         const gfile = _.get(og, 'goods.file', []);
-        const nf = [ ...file, ...gfile ];
+        const nf = [...file, ...gfile];
         const url = _.get(_.head(nf), 'url');
         og.url = url;
         delete og.file;
@@ -278,7 +277,7 @@ class OrderDetailService extends CrudService {
         obj.price = _.get(obj, 'price', obj.sell_money);
       }
       // 售后
-      const asum = await this.afterSaleModel.count({ order_detail: obj._id, status: { $nin: [ '-1', '!1', '-2', '!2', '-3', '!3', '-4', '!4', '-5', '!5' ] } });
+      const asum = await this.afterSaleModel.count({ order_detail: obj._id, status: { $nin: ['-1', '!1', '-2', '!2', '-3', '!3', '-4', '!4', '-5', '!5'] } });
       obj.is_afterSale = asum > 0;
       list.push(obj);
     }
@@ -300,6 +299,8 @@ class OrderDetailService extends CrudService {
         await this.ctx.service.user.point.addPoints(filter._id, this.tran);
         // 返现部分
         await this.ctx.service.user.cashBack.create(filter._id, this.tran);
+        // 店铺流水部分
+        await this.ctx.service.shop.shopInBill.createByOrder(entity, this.tran);
       }
 
       await this.tran.run();
@@ -307,7 +308,6 @@ class OrderDetailService extends CrudService {
       return e;
     } catch (error) {
       await this.tran.rollback();
-
     } finally {
       this.tran.clean();
     }

+ 1 - 1
app/service/user/userCoupon.js

@@ -213,7 +213,7 @@ class UserCouponService extends CrudService {
         const r = arr.findIndex((f) => arr1.find((ff) => _.isEqual(f, ff)));
         console.log(r);
        */
-      const r = s.goods.some(g => g.tags.find(f => tags.find(ff => _.isEqual(f, ff))));
+      const r = s.goods.some(g => g.tags && g.tags.find(f => tags && tags.find(ff => _.isEqual(f, ff))));
       if (r) {
         result = true;
         break;

+ 2 - 0
app/z_router/shop/index.js

@@ -8,4 +8,6 @@ module.exports = app => {
   require('./goodsSpec')(app); // 商品规格
   require('./goodsRate')(app); // 商品评价
   require('./goodsJoinAct')(app); // 平台活动商品关联
+  require('./shopInBill')(app); // 店铺流水
+  require('./shopCashOut')(app); // 店铺申请提现
 };

+ 19 - 0
app/z_router/shop/shopCashOut.js

@@ -0,0 +1,19 @@
+'use strict';
+// 路由配置
+const path = require('path');
+const regPath = path.resolve('app', 'public', 'routerRegister');
+const routerRegister = require(regPath);
+const rkey = 'shopCashOut';
+const ckey = 'shop.shopCashOut';
+const keyZh = '店铺提现申请';
+const routes = [
+  { method: 'get', path: `${rkey}`, controller: `${ckey}.index`, name: `${ckey}Query`, zh: `${keyZh}列表查询` },
+  { method: 'get', path: `${rkey}/:id`, controller: `${ckey}.show`, name: `${ckey}Show`, zh: `${keyZh}查询` },
+  { method: 'post', path: `${rkey}`, controller: `${ckey}.create`, name: `${ckey}Create`, zh: `创建${keyZh}` },
+  { method: 'post', path: `${rkey}/:id`, controller: `${ckey}.update`, name: `${ckey}Update`, zh: `修改${keyZh}` },
+  { method: 'delete', path: `${rkey}/:id`, controller: `${ckey}.destroy`, name: `${ckey}Delete`, zh: `删除${keyZh}` },
+];
+
+module.exports = app => {
+  routerRegister(app, routes, keyZh, rkey, ckey);
+};

+ 20 - 0
app/z_router/shop/shopInBill.js

@@ -0,0 +1,20 @@
+'use strict';
+// 路由配置
+const path = require('path');
+const regPath = path.resolve('app', 'public', 'routerRegister');
+const routerRegister = require(regPath);
+const rkey = 'shopInBill';
+const ckey = 'shop.shopInBill';
+const keyZh = '店铺流水信息';
+const routes = [
+  { method: 'post', path: `${rkey}/total/:shop`, controller: `${ckey}.computedTotal`, name: `${ckey}computedTotal`, zh: `${keyZh}-计算金额` },
+  { method: 'get', path: `${rkey}`, controller: `${ckey}.index`, name: `${ckey}Query`, zh: `${keyZh}列表查询` },
+  { method: 'get', path: `${rkey}/:id`, controller: `${ckey}.show`, name: `${ckey}Show`, zh: `${keyZh}查询` },
+  // { method: 'post', path: `${rkey}`, controller: `${ckey}.create`, name: `${ckey}Create`, zh: `创建${keyZh}` },
+  // { method: 'post', path: `${rkey}/:id`, controller: `${ckey}.update`, name: `${ckey}Update`, zh: `修改${keyZh}` },
+  // { method: 'delete', path: `${rkey}/:id`, controller: `${ckey}.destroy`, name: `${ckey}Delete`, zh: `删除${keyZh}` },
+];
+
+module.exports = app => {
+  routerRegister(app, routes, keyZh, rkey, ckey);
+};