lrf 2 anni fa
parent
commit
7da637aa0f

+ 35 - 0
app/controller/home.js

@@ -5,6 +5,41 @@ class HomeController extends Controller {
   async index() {
     const { ctx } = this;
     ctx.body = 'hi, egg';
+    // 模拟优惠券发行
+    // const data = await this.makeCoupons();
+    // this.ctx.ok({ data, total: data.length });
+  }
+
+  async makeCoupons() {
+    const dictDataModel = this.ctx.model.Dev.DictData;
+    const couponModel = this.ctx.model.Trade.Coupon;
+    // 过期字典
+    const expList = await dictDataModel.find({ code: 'coupon_expire_type' });
+    // 减免字典
+    const disList = await dictDataModel.find({ code: 'coupon_discount_type' });
+    // 使用字典
+    const useList = await dictDataModel.find({ code: 'coupon_use_limit' });
+    // 领取字典
+    const getList = await dictDataModel.find({ code: 'coupon_get_limit' });
+
+    const arr = [];
+    for (const e of expList) {
+      const { value: expire_type, label: el } = e;
+      for (const d of disList) {
+        const { value: discount_type, label: dl } = d;
+        for (const u of useList) {
+          const { value: use_limit, label: ul } = u;
+          for (const g of getList) {
+            const { value: get_limit, label: gl } = g;
+            const obj = { issue: '0', expire_type, discount_type, use_limit, get_limit, num: 100, status: '0' };
+            obj.name = `平台测试优惠券-${el}-${dl}-${ul}-${gl}`;
+            arr.push(obj);
+          }
+        }
+      }
+    }
+    await couponModel.insertMany(arr);
+    return arr;
   }
 }
 

+ 6 - 4
app/controller/trade/config/.afterSale.js

@@ -1,6 +1,6 @@
 module.exports = {
   create: {
-    requestBody: ['!order_id', '!goods_id', 'type', 'reason', 'desc', 'file'],
+    requestBody: ['order_detail', 'customer', 'shop', 'goods', 'type', 'reason', 'desc', 'file', 'transport', 'apply_time', 'end_time', 'status', 'result'],
   },
   destroy: {
     params: ['!id'],
@@ -8,7 +8,7 @@ module.exports = {
   },
   update: {
     params: ['!id'],
-    requestBody: ['order_detail', 'customer', 'shop', 'goods', 'type', 'reason', 'desc', 'file', 'transport', 'apply_time', 'end_time', 'status'],
+    requestBody: ['order_detail', 'customer', 'shop', 'goods', 'type', 'reason', 'desc', 'file', 'transport', 'apply_time', 'end_time', 'status', 'result'],
   },
   show: {
     parameters: {
@@ -22,8 +22,10 @@ module.exports = {
         'meta.createdAt@start': 'meta.createdAt@start',
         'meta.createdAt@end': 'meta.createdAt@end',
         type: 'type',
-        apply_time: 'apply_time',
-        end_time: 'end_time',
+        'apply_time@start': 'apply_time@start',
+        'apply_time@end': 'apply_time@end',
+        'end_time@start': 'end_time@start',
+        'end_time@end': 'end_time@end',
       },
       // options: {
       //   "meta.state": 0 // 默认条件

+ 37 - 0
app/extend/context.js

@@ -0,0 +1,37 @@
+'use strict';
+const Decimal = require('decimal.js');
+Decimal.set({ precision: 2 });
+module.exports = {
+  // 加法
+  plus(n1 = 0, n2 = 0) {
+    const number1 = new Decimal(n1);
+    const number2 = new Decimal(n2);
+    const result = number1.add(number2).toFixed(2, Decimal.ROUND_DOWN);
+    return this.toNumber(result);
+  },
+  // 减法
+  minus(n1 = 0, n2 = 0) {
+    const number1 = new Decimal(n1);
+    const number2 = new Decimal(n2);
+    const result = number1.minus(number2).toFixed(2, Decimal.ROUND_DOWN);
+    return this.toNumber(result);
+  },
+  // 乘法
+  multiply(n1 = 0, n2 = 0) {
+    const number1 = new Decimal(n1);
+    const number2 = new Decimal(n2);
+    const result = number1.mul(number2).toFixed(2, Decimal.ROUND_DOWN);
+    return this.toNumber(result);
+  },
+  // 除法
+  divide(n1 = 0, n2 = 0) {
+    const number1 = new Decimal(n1);
+    const number2 = new Decimal(n2);
+    const result = number1.div(number2).toFixed(2, Decimal.ROUND_DOWN);
+    return this.toNumber(result);
+  },
+
+  toNumber(num) {
+    return new Decimal(num).toNumber();
+  },
+};

+ 1 - 0
app/model/trade/afterSale.js

@@ -16,6 +16,7 @@ const afterSale = {
   apply_time: { type: String, required: false, zh: '售后申请时间' }, //
   end_time: { type: String, required: false, zh: '售后结束时间' }, //
   status: { type: String, required: false, zh: '售后状态' }, // 字典:afterSale_status
+  result: { type: Object, required: false, zh: '售后结果' }, // 售后完成后需要补充的内容,例如:退款的金额
 };
 const schema = new Schema(afterSale, { toJSON: { getters: true, virtuals: true } });
 schema.index({ id: 1 });

+ 42 - 7
app/service/trade/afterSale.js

@@ -49,11 +49,11 @@ class AfterSaleService extends CrudService {
     update = beforeUpdateResult.update;
     const { _id, id } = filter;
     if (_id || id) filter = { _id: ObjectId(_id || id) };
-    // TODO:检查数据是否存在
+    // 检查数据是否存在
     const entity = await this.model.findOne(filter).exec();
     if (!entity) throw new BusinessError(ErrorCode.DATA_NOT_EXIST);
 
-    // TODO: 修改数据
+    // 修改数据
     try {
       this.tran.update('AfterSale', entity._id, update);
       await this.tran.run();
@@ -87,21 +87,56 @@ class AfterSaleService extends CrudService {
     const { populate } = this.ctx.service.trade.orderDetail.getRefMods();
     const orderDetail = await this.orderDetailModel.findById(data.order_detail).populate(populate);
     if (!orderDetail) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到售后信息的订单');
-    const money = _.get(data, 'goods.sell_money');
+    // 计算商品原价
+    let money = this.ctx.multiply(_.get(data, 'goods.sell_money'), _.get(data, 'goods.buy_num'));
     const reason = _.get(data, 'desc');
     const order_no = _.get(orderDetail, 'order.pay.pay_no');
     if (!order_no) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到支付订单号');
+    // 查查优惠中,是否有这个商品:将这个商品的每一个优惠券的优惠部分都加一起,然后用原价-优惠价=实付价
+    const discount_detail = _.get(orderDetail, 'total_detail.discount_detail');
+    if (discount_detail) {
+      let discountMoney = 0;
+      for (const uc_id in discount_detail) {
+        const detail = discount_detail[uc_id];
+        const gd = detail[goods_id];
+        if (gd && !_.get(gd, 'refund', false)) {
+          discountMoney = this.ctx.plus(discountMoney, gd.discountMoney);
+          gd.refund = true;
+        }
+      }
+      money = this.ctx.minus(money, discountMoney);
+    }
+
     // 找下当前这个订单有多少次售后记录
     let num = await this.model.count({ order_detail: data.order_detail });
     num += 1;
     // 组成退款单号
     const out_refund_no = `${order_no}-r${num}`;
     const obj = { reason, money, order_no, out_refund_no };
-    // TODO优惠部分
-
     // 退款请求
-    const refundRes = await this.ctx.service.trade.pay.refund(obj);
-    // console.log(refundRes);
+    await this.ctx.service.trade.pay.refund(obj);
+
+    // 检查优惠券是否都退了
+    let allRefund = true;
+    for (const dd of discount_detail) {
+      for (const d in dd) {
+        if (!_.get(d, 'refund')) {
+          allRefund = false;
+          break;
+        }
+      }
+    }
+
+    if (allRefund) {
+      // 优惠券部分全都退了,那就把优惠券退了
+      const couponIds = Object.keys(discount_detail);
+      for (const id of couponIds) {
+        tran.update('UserCoupon', id, { status: '0' });
+      }
+    }
+
+    // 修改订单详情的优惠券标记
+    tran.update('OrderDetail', orderDetail._id, { 'total_detail.discount_detail': discount_detail });
   }
 }
 

+ 1 - 1
app/service/trade/cart.js

@@ -79,7 +79,7 @@ class CartService extends CrudService {
     assert(goodsSpec, '缺少商品规格信息');
     const data = await this.model.findOne(body);
     if (data) {
-      const buyNum = parseInt(data.num) + parseInt(num);
+      const buyNum = this.ctx.plus(data.num, num);
       const { enough } = await this.checkGoodsNum({ goodsSpecId: goodsSpec, num: buyNum });
       if (!enough) throw new BusinessError(ErrorCode.SERVICE_FAULT, '库存不足,无法添加至购物车');
       data.num = buyNum;

+ 7 - 20
app/service/trade/order.js

@@ -126,7 +126,7 @@ class OrderService extends CrudService {
         for (const i of list) {
           const goodsSpec = await this.goodsSpecModel.findById(i._id, { num: 1 });
           if (!goodsSpec) continue;
-          const newNum = (parseInt(goodsSpec.num) || 0) + (parseInt(i.buy_num) || 0);
+          const newNum = this.ctx.plus(goodsSpec.num, i.buy_num);
           this.tran.update('GoodsSpec', i._id, { num: newNum });
         }
       }
@@ -144,14 +144,13 @@ class OrderService extends CrudService {
       await this.tran.run();
     } catch (error) {
       await this.tran.rollback();
-      console.log(error);
+      console.error(error);
       throw new BusinessError(ErrorCode.SERVICE_FAULT, '订单取消失败');
     } finally {
       this.tran.clean();
     }
   }
 
-
   /**
    * 减库存,删除购物车
    * @param {Array} list 商品
@@ -161,7 +160,7 @@ class OrderService extends CrudService {
       for (const g of i.goods) {
         const { _id, buy_num, cart_id } = g;
         const goodsSpec = await this.goodsSpecModel.findById(_id);
-        const newNum = parseInt(goodsSpec.num - buy_num);
+        const newNum = this.ctx.minus(goodsSpec.num, buy_num);
         this.tran.update('GoodsSpec', _id, { num: newNum });
         if (cart_id) this.tran.remove('Cart', cart_id);
       }
@@ -221,14 +220,8 @@ class OrderService extends CrudService {
    */
   computedShopTotal(list) {
     for (const i of list) {
-      i.goods_total = _.floor(
-        i.goods.reduce((p, n) => p + (n.money || 0) * (n.num || 0), 0),
-        2
-      );
-      i.freight_total = _.floor(
-        i.goods.reduce((p, n) => p + (n.freight || 0) * (n.num || 0), 0),
-        2
-      );
+      i.goods_total = i.goods.reduce((p, n) => this.ctx.plus(p, this.ctx.multiply(n.money, n.num)), 0);
+      i.freight_total = i.goods.reduce((p, n) => this.ctx.plus(p, this.ctx.multiply(n.freight, n.num)), 0);
     }
     return list;
   }
@@ -239,14 +232,8 @@ class OrderService extends CrudService {
    */
   computedAllTotal(list) {
     const obj = {
-      goods_total: _.floor(
-        list.reduce((p, n) => p + (n.goods_total || 0), 0),
-        2
-      ),
-      freight_total: _.floor(
-        list.reduce((p, n) => p + (n.freight_total || 0), 0),
-        2
-      ),
+      goods_total: list.reduce((p, n) => this.ctx.plus(p, n.goods_total), 0),
+      freight_total: list.reduce((p, n) => this.ctx.plus(p, n.freight_total), 0),
     };
     return obj;
   }

+ 3 - 11
app/service/trade/orderDetail.js

@@ -26,7 +26,7 @@ class OrderDetailService extends CrudService {
     const { customer, address, goods, no, status, buy_time, pay, total_detail: otd } = order;
     if (status === '0') throw new BusinessError(ErrorCode.DATA_INVALID, '订单未支付');
     const orderDetailData = { customer, address, order: order_id, buy_time, pay_time: _.get(pay, 'pay_time'), status };
-    // 补全 shop, goods, total_detail TODO: 补全 discount;
+    // 补全 shop, goods, total_detail;
     // const arr = [];
     // 分订单计数器
     let noTimes = 1;
@@ -36,11 +36,9 @@ class OrderDetailService extends CrudService {
       const detailNo = `${no}-${noTimes}`;
       const total_detail = this.getTotalDetail(goodsList);
       // 优惠部分分割
-      console.log(otd);
       if (_.get(otd, 'discount_detail')) {
         // 如果有优惠部分,那就得找,优惠里面有没有对应的商品规格
         const discount_detail = this.getGoodsListDiscountDetail(goodsList, _.get(otd, 'discount_detail'));
-        console.log(discount_detail);
         total_detail.discount_detail = discount_detail;
       }
       noTimes++;
@@ -75,14 +73,8 @@ class OrderDetailService extends CrudService {
    * @param {Array} goodsList 商品规格列表
    */
   getTotalDetail(goodsList) {
-    const goods_total = _.floor(
-      goodsList.reduce((p, n) => p + (parseFloat(n.sell_money) || 0) * (parseInt(n.buy_num) || 0), 0),
-      2
-    );
-    const freight_total = _.floor(
-      goodsList.reduce((p, n) => p + (parseFloat(n.freight) || 0), 0),
-      2
-    );
+    const goods_total = goodsList.reduce((p, n) => this.ctx.plus(p, this.ctx.multiply(n.sell_money, n.buy_num)), 0);
+    const freight_total = goodsList.reduce((p, n) => this.ctx.plus(p, this.ctx.multiply(n.freight, n.buy_num)), 0);
     return { goods_total, freight_total };
   }
 }

+ 6 - 5
app/service/trade/pay.js

@@ -43,9 +43,8 @@ class PayService extends CrudService {
         // 1.如果有支付信息及支付单号,直接关闭.重开
         const arr = pay_no.split('-');
         // 获取重支付的次数,重支付次数+1
-        let last = _.last(arr);
-        last = parseInt(last);
-        rePayTimes = (last || 0) + 1;
+        const last = _.last(arr);
+        rePayTimes = this.ctx.plus(last, 1);
       }
       await this.closeOrder(pay);
     }
@@ -180,10 +179,11 @@ class PayService extends CrudService {
     const { total_detail = {} } = order;
     const { discount_detail, ...others } = total_detail;
     for (const key in others) {
-      total = _.floor(total_detail[key] + total, 2);
+      total = this.ctx.plus(total_detail[key], total);
     }
     // 优惠券部分
     if (discount_detail) {
+      let totalDiscount = 0;
       for (const uc in discount_detail) {
         // uc:用户领取的优惠券id
         // detail: 该优惠券下的明细
@@ -194,9 +194,10 @@ class PayService extends CrudService {
           // gs:该商品的价格明细,只取出discountMoney就行
           const gs = detail[gsid];
           const dm = _.get(gs, 'discountMoney', 0);
-          total = _.floor(total - dm, 2);
+          totalDiscount = this.ctx.plus(totalDiscount, dm);
         }
       }
+      total = this.ctx.minus(total, totalDiscount);
     }
     return total;
   }

+ 1 - 0
package.json

@@ -7,6 +7,7 @@
     "framework": "naf-framework-mongoose-free"
   },
   "dependencies": {
+    "decimal.js": "^10.4.1",
     "egg": "^2",
     "egg-redis": "^2.4.0",
     "egg-scripts": "^2",