Parcourir la source

店铺系统消息

lrf il y a 2 ans
Parent
commit
c83ab18c42

+ 51 - 0
app/controller/shop/config/.shopNotice.js

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

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

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

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

@@ -0,0 +1,30 @@
+'use strict';
+const Schema = require('mongoose').Schema;
+const metaPlugin = require('naf-framework-mongoose-free/lib/model/meta-plugin');
+
+// 店铺系统消息
+const shopNotice = {
+  shop: { type: String, required: false, zh: '店铺' }, //
+  source: { type: String, required: false, zh: '消息来源' }, // 字典:notice_source
+  source_id: { type: String, required: false, zh: '来源id' }, //
+  time: { type: String, required: false, zh: '发送时间' }, //
+  content: { type: String, required: false, zh: '内容' }, //
+  type: { type: String, required: false, default: '1', zh: '发送类型' }, // 字典:notice_type;只是显示;默认:人为发送
+  status: { type: String, required: false, default: '0', zh: '状态' }, // 字典:notice_status
+};
+const schema = new Schema(shopNotice, { 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.index({ time: 1 });
+schema.index({ type: 1 });
+schema.index({ status: 1 });
+
+schema.plugin(metaPlugin);
+
+module.exports = app => {
+  const { mongoose } = app;
+  return mongoose.model('ShopNotice', schema, 'shopNotice');
+};

+ 83 - 0
app/service/shop/shopNotice.js

@@ -0,0 +1,83 @@
+'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 ShopNoticeService extends CrudService {
+  constructor(ctx) {
+    super(ctx, 'shopnotice');
+    this.model = this.ctx.model.Shop.ShopNotice;
+    this.orderDetailModel = this.ctx.model.Trade.OrderDetail;
+    this.afterSaleModel = this.ctx.model.Trade.AfterSale;
+  }
+
+  /**
+   * 提醒发货; 可单发,可群发
+   * @param body 发送消息参数
+   * @property source_id orderDetail的id
+   */
+  async remindToSend(body) {
+    const { source_id } = body;
+    const type = _.get(body, 'type', '1');
+    const list = [];
+    if (_.isString(source_id)) {
+      const od = await this.orderDetailModel.findById(source_id);
+      const content = this.toSendMsg(_.get(od, 'no'));
+      const obj = { shop: _.get(od, 'shop'), source: '1', source_id, time: moment().format('YYYY-MM-DD HH:mm:ss'), content, type };
+      list.push(obj);
+    } else if (_.isArray(source_id)) {
+      for (const id of source_id) {
+        const od = await this.orderDetailModel.findById(id);
+        const content = this.toSendMsg(_.get(od, 'no'));
+        const obj = { shop: _.get(od, 'shop'), source: '1', source_id: id, time: moment().format('YYYY-MM-DD HH:mm:ss'), content, type };
+        list.push(obj);
+      }
+    }
+    await this.model.insertMany(list);
+
+  }
+  /**
+   * 提醒发货消息
+   * @param no 订单号
+   */
+  toSendMsg(no) {
+    return `您的订单号为: ${no} 的订单需要发货,请您及时处理`;
+  }
+  /**
+   * 提醒处理售后
+   * @param body
+   * @property source_id 售后数据id
+   */
+  async remindToAfterSale(body) {
+    const { source_id } = body;
+    const type = _.get(body, 'type', '1');
+    const list = [];
+    if (_.isString(source_id)) {
+      const data = await this.afterSaleModel.findById(source_id);
+      const od = await this.orderDetailModel.findById(data.order_detail);
+      const content = this.toAfterSaleMsg(_.get(od, 'no'));
+      const obj = { shop: _.get(data, 'shop'), source: '1', source_id, time: moment().format('YYYY-MM-DD HH:mm:ss'), content, type };
+      list.push(obj);
+    } else if (_.isArray(source_id)) {
+      for (const id of source_id) {
+        const data = await this.afterSaleModel.findById(id);
+        const od = await this.orderDetailModel.findById(data.order_detail);
+        const content = this.toAfterSaleMsg(_.get(od, 'no'));
+        const obj = { shop: _.get(data, 'shop'), source: '1', source_id: id, time: moment().format('YYYY-MM-DD HH:mm:ss'), content, type };
+        list.push(obj);
+      }
+    }
+    await this.model.insertMany(list);
+  }
+  /**
+   * 提示售后消息
+   * @param {String} no 订单号
+   */
+  toAfterSaleMsg(no) {
+    return `您的订单号为: ${no} 的订单有售后未处理,请您及时处理`;
+  }
+}
+
+module.exports = ShopNoticeService;

+ 18 - 11
app/service/trade/afterSale.js

@@ -35,11 +35,11 @@ class AfterSaleService extends CrudService {
     if (!orderDetail) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到订单信息');
     // 查看该商品是否已经申请售后
     let goods;
-    const hasData = await this.model.count({ order_detail, 'goods._id': goods_id, status: { $nin: ['!1', '!2', '!3', '!4', '!5'] } });
+    const hasData = await this.model.count({ order_detail, 'goods._id': goods_id, status: { $nin: [ '!1', '!2', '!3', '!4', '!5' ] } });
     if (hasData > 0) throw new BusinessError(ErrorCode.DATA_EXISTED, '该商品已有正在处理中的售后申请.请勿重复申请');
     if (type !== '4' && type !== '5') {
       const { goods: goodsList } = orderDetail;
-      goods = goodsList.find((f) => {
+      goods = goodsList.find(f => {
         return ObjectId(f._id).equals(goods_id);
       });
       if (!goods) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未在当前订单中搜索到要售后的商品');
@@ -51,7 +51,14 @@ class AfterSaleService extends CrudService {
     const { shop, customer } = orderDetail;
     const apply_time = moment().format('YYYY-MM-DD HH:mm:ss');
     const obj = { order_detail, customer, shop, goods, type, ...others, apply_time, status: '0' };
-    await this.model.create(obj);
+    const res = await this.model.create(obj);
+    const msgData = { source_id: res._id, type: '0' };
+    try {
+      await this.ctx.service.shop.shopNotice.remindToAfterSale(msgData);
+    } catch (error) {
+      const errobj = error;
+      await this.ctx.service.util.email.errorEmail(errobj);
+    }
   }
 
   async update(filter, update, { projection } = {}) {
@@ -219,7 +226,7 @@ class AfterSaleService extends CrudService {
     // 已退款记录
     const goodsRefundList = [];
     // 在下面处理已退款记录中,应该把当前的这个售后项,作为已处理售后
-    const tasq = { order_detail: data.order_detail, 'goods._id': _.get(data, 'goods._id'), status: ['-1', '-2'] };
+    const tasq = { order_detail: data.order_detail, 'goods._id': _.get(data, 'goods._id'), status: [ '-1', '-2' ] };
     const asdd = JSON.parse(JSON.stringify(data));
     if (_.get(update, 'money')) asdd.money = _.get(update, 'money');
     const tr = await this.checkIsAllRefund(data);
@@ -230,7 +237,7 @@ class AfterSaleService extends CrudService {
       const { goods, _id: order_detail } = od;
       // 组合成查售后的条件
       // 然后查这些商品有没有退款审核成功的记录, 且只有退全款的商品才能退券
-      const afterSaleQuerys = goods.map((i) => ({ order_detail, 'goods._id': i._id, status: ['-1', '-2'] }));
+      const afterSaleQuerys = goods.map(i => ({ order_detail, 'goods._id': i._id, status: [ '-1', '-2' ] }));
       for (const asq of afterSaleQuerys) {
         const asd = await this.model.findOne(asq);
         if (asd) {
@@ -246,7 +253,7 @@ class AfterSaleService extends CrudService {
       // 该优惠券影响的商品id列表
       const goodsIds = Object.keys(_.get(dd, uc_id, {}));
       // 然后在已退款/退货记录中找,这个优惠券影响的商品是否都退款了.退全额
-      const r = goodsIds.every((i) => goodsRefundList.find((f) => i === f['goods._id']));
+      const r = goodsIds.every(i => goodsRefundList.find(f => i === f['goods._id']));
       if (r) {
         // 说明这个优惠券影响的商品都退了,这个优惠券也就能退了
         tran.update('UserCoupon', uc_id, { status: '0' });
@@ -265,15 +272,15 @@ class AfterSaleService extends CrudService {
     // 获取拆分订单的数据,并找到商品列表
     const goodsList = _.get(orderDetail, 'goods');
     // 依次找这些商品是否都售后完成,都售后完成,就改订单状态
-    const asList = await this.model.find({ order_detail, status: { $nin: ['0', '!1', '!2', '!3', '!4', '!5'] } });
+    const asList = await this.model.find({ order_detail, status: { $nin: [ '0', '!1', '!2', '!3', '!4', '!5' ] } });
     let status;
     let fl = [];
     // 将当前数据添加进去
     fl.push({ goods: _.get(data, 'goods._id'), status: 'finish' });
     for (const gs of goodsList) {
-      const r = asList.find((f) => ObjectId(_.get(f, 'goods._id')).equals(_.get(gs, '_id')));
+      const r = asList.find(f => ObjectId(_.get(f, 'goods._id')).equals(_.get(gs, '_id')));
       if (r) {
-        const finishList = ['-1', '-2', '-3', '-4', '-5'];
+        const finishList = [ '-1', '-2', '-3', '-4', '-5' ];
         if (finishList.includes(r.status)) fl.push({ goods: gs._id, status: 'finish' });
       }
     }
@@ -321,7 +328,7 @@ class AfterSaleService extends CrudService {
       const { goods, _id: order_detail } = od;
       // 组合成查售后的条件
       // 然后查这些商品有没有退款审核成功的记录, 且只有退全款的商品才能退券
-      const afterSaleQuerys = goods.map((i) => ({ order_detail, 'goods._id': i._id, status: ['-1', '-2'] }));
+      const afterSaleQuerys = goods.map(i => ({ order_detail, 'goods._id': i._id, status: [ '-1', '-2' ] }));
       for (const asq of afterSaleQuerys) {
         const asd = await this.model.findOne(asq);
         if (asd) {
@@ -337,7 +344,7 @@ class AfterSaleService extends CrudService {
       // 该优惠券影响的商品id列表
       const goodsIds = Object.keys(_.get(dd, uc_id, {}));
       // 然后在已退款/退货记录中找,这个优惠券影响的商品是否都退款了.退全额
-      const r = goodsIds.every((i) => goodsRefundList.find((f) => i === f['goods._id']));
+      const r = goodsIds.every(i => goodsRefundList.find(f => i === f['goods._id']));
       if (r) {
         // 说明这个优惠券影响的商品都退了,这个优惠券也就能退了
         tran.update('UserCoupon', uc_id, { status: '0' });

+ 3 - 0
app/service/trade/pay.js

@@ -159,6 +159,9 @@ class PayService extends CrudService {
       // 清空事务
       this.tran.clean();
     }
+    // 发送系统消息,让对应的店铺接收消息
+    const msgData = { source_id: orderData._id, type: '0' };
+    await this.ctx.service.shop.shopNotice.remindToSend(msgData);
   }
   /**
    * 加销量

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

@@ -10,4 +10,5 @@ module.exports = app => {
   require('./goodsJoinAct')(app); // 平台活动商品关联
   require('./shopInBill')(app); // 店铺流水
   require('./shopCashOut')(app); // 店铺申请提现
+  require('./shopNotice')(app); // 店铺系统消息
 };

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

@@ -0,0 +1,20 @@
+'use strict';
+// 路由配置
+const path = require('path');
+const regPath = path.resolve('app', 'public', 'routerRegister');
+const routerRegister = require(regPath);
+const rkey = 'shopNotice';
+const ckey = 'shop.shopNotice';
+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}/rts`, controller: `${ckey}.rts`, name: `${ckey}rts`, zh: `发送-处理发货-${keyZh}` },
+  { method: 'post', path: `${rkey}/rtas`, controller: `${ckey}.rtas`, name: `${ckey}rtas`, 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);
+};