|
@@ -3,7 +3,8 @@ 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');
|
|
|
+const Transaction = require('mongoose-transactions');
|
|
|
//
|
|
|
class OrderService extends CrudService {
|
|
|
constructor(ctx) {
|
|
@@ -14,17 +15,103 @@ class OrderService extends CrudService {
|
|
|
this.goodsModel = this.ctx.model.Shop.Goods;
|
|
|
this.goodsSpecModel = this.ctx.model.Shop.GoodsSpec;
|
|
|
this.addressModel = this.ctx.model.User.Address;
|
|
|
-
|
|
|
this.cartModel = this.ctx.model.Trade.Cart;
|
|
|
+ this.tran = new Transaction();
|
|
|
}
|
|
|
-
|
|
|
/**
|
|
|
* 创建订单
|
|
|
* 1.检测商品是否可以购买
|
|
|
- * 2.
|
|
|
+ * 2.数据做快照处理
|
|
|
* @param {Object} body
|
|
|
*/
|
|
|
- async create(body) {}
|
|
|
+ async create(body) {
|
|
|
+ // 声明事务
|
|
|
+ try {
|
|
|
+ const user = this.ctx.user;
|
|
|
+ const customer = _.get(user, '_id');
|
|
|
+ if (!customer) throw new BusinessError(ErrorCode.NOT_LOGIN, '未找到用户信息');
|
|
|
+ const { address, goods, total_detail } = body;
|
|
|
+ // 检测商品是否可以下单
|
|
|
+ for (const i of goods) {
|
|
|
+ const { shop } = i;
|
|
|
+ for (const g of i.goods) {
|
|
|
+ const { goods_id: goods, goodsSpec_id: goodsSpec, num } = g;
|
|
|
+ const { result, msg } = await this.ctx.service.util.trade.checkCanBuy({ shop, goods, goodsSpec, num }, false);
|
|
|
+ if (!result) throw new BusinessError(ErrorCode.DATA_INVALID, msg);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ const orderData = {};
|
|
|
+ // 数据做快照处理
|
|
|
+ // 1.地址快照
|
|
|
+ const addressData = await this.addressModel.findById(address._id);
|
|
|
+ if (!addressData) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到邮寄地址数据');
|
|
|
+ // 2.商品快照
|
|
|
+ const goodsData = [];
|
|
|
+ // 商店不做快照,但是商品和商品对应的规格做快照
|
|
|
+ const { populate } = this.ctx.service.shop.goodsSpec.getRefMods();
|
|
|
+ for (const i of goods) {
|
|
|
+ const { goods: goodsList, ...others } = i;
|
|
|
+ const qp = [];
|
|
|
+ for (const g of goodsList) {
|
|
|
+ const { goodsSpec_id, num, cart_id } = g;
|
|
|
+ let d = await this.goodsSpecModel.findById(goodsSpec_id).populate(populate);
|
|
|
+ if (!d) continue;
|
|
|
+ d = JSON.parse(JSON.stringify(d));
|
|
|
+ // 将商店内容剔除
|
|
|
+ const { goods: gd, ...dOthers } = d;
|
|
|
+ const gdOthers = _.omit(gd, [ 'shop' ]);
|
|
|
+ const obj = { ...dOthers, goods: gdOthers, buy_num: num };
|
|
|
+ if (cart_id) obj.cart_id = cart_id;
|
|
|
+ qp.push(obj);
|
|
|
+ }
|
|
|
+ goodsData.push({ ...others, goods: qp });
|
|
|
+ }
|
|
|
+ // TODO: 3.商品总计明细.这地方没加优惠券,所以先直接复制即可
|
|
|
+ const totalDetailData = total_detail;
|
|
|
+ // 接下来组织订单数据
|
|
|
+ orderData.address = addressData;
|
|
|
+ orderData.goods = goodsData;
|
|
|
+ orderData.total_detail = totalDetailData;
|
|
|
+ // 1.用户数据
|
|
|
+ orderData.customer = customer;
|
|
|
+ // 2.下单时间
|
|
|
+ orderData.buy_time = moment().format('YYYY-MM-DD HH:mm:ss');
|
|
|
+ // 3.订单号
|
|
|
+ const str = this.ctx.service.util.trade.createNonceStr();
|
|
|
+ orderData.no = `${moment().format('YYYYMMDDHHmmss')}-${str}`;
|
|
|
+ // 4.状态
|
|
|
+ orderData.status = '0';
|
|
|
+ // 生成数据
|
|
|
+ // const order = await this.model.create(orderData);
|
|
|
+ this.tran.insert('Order', orderData);
|
|
|
+ // 处理库存问题
|
|
|
+ // 处理库存,删除购物车
|
|
|
+ await this.dealGoodsNum(goodsData);
|
|
|
+ await this.tran.run();
|
|
|
+ } catch (error) {
|
|
|
+ await this.tran.rollback();
|
|
|
+ console.error(error);
|
|
|
+ throw new BusinessError(ErrorCode.SERVICE_FAULT, '订单发生错误,下单失败');
|
|
|
+ } finally {
|
|
|
+ // 清空事务
|
|
|
+ this.tran.clean();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * 减库存,删除购物车
|
|
|
+ * @param {Array} list 商品
|
|
|
+ */
|
|
|
+ async dealGoodsNum(list) {
|
|
|
+ for (const i of list) {
|
|
|
+ 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);
|
|
|
+ this.tran.update('GoodsSpec', _id, { num: newNum });
|
|
|
+ if (cart_id) this.tran.remove('Cart', cart_id);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
/**
|
|
|
* 进入下单页面
|
|
@@ -75,8 +162,14 @@ 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 = _.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
|
|
|
+ );
|
|
|
console.log(i);
|
|
|
}
|
|
|
return list;
|
|
@@ -88,8 +181,14 @@ 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: _.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
|
|
|
+ ),
|
|
|
};
|
|
|
return obj;
|
|
|
}
|