bill.js 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. 'use strict';
  2. const { CrudService } = require('naf-framework-mongoose-free/lib/service');
  3. const { BusinessError, ErrorCode } = require('naf-core').Error;
  4. const _ = require('lodash');
  5. const assert = require('assert');
  6. const Transaction = require('mongoose-transactions');
  7. const { ObjectId } = require('mongoose').Types;
  8. // 对账
  9. class BillService extends CrudService {
  10. constructor(ctx) {
  11. super(ctx, 'bill');
  12. this.orderDetailModel = this.ctx.model.Trade.OrderDetail;
  13. this.afterSaleModel = this.ctx.model.Trade.AfterSale;
  14. this.tran = new Transaction();
  15. }
  16. /**
  17. * 对账标记
  18. * @param {Object} body 参数体
  19. * @param body.order 对账的订单内容
  20. // ** _id:orderDetail的id
  21. // ** spec_id: 商品规格id
  22. * @param body.afterSale 对账的售后id集合
  23. */
  24. async outBill({ order = [], afterSale = [] }) {
  25. const data = { out_bill: '0' };
  26. await this.orderDetailModel.updateMany({ _id: order.map(i => ObjectId(i)) }, data);
  27. await this.afterSaleModel.updateMany({ _id: afterSale.map(i => ObjectId(i)) }, data);
  28. }
  29. /**
  30. * 生成店铺对账单
  31. ** 根据店铺id,开始时间和结束时间,形成对账单
  32. * @param {Object} query 查询条件
  33. */
  34. async getBill(query) {
  35. const { shop, start, end } = query;
  36. assert(start, '缺少开始时间');
  37. assert(end, '缺少结束时间');
  38. const orderList = await this.makeBillOrderPart(query);
  39. const afterSaleList = await this.makeBillAfterSalePart(query);
  40. const ot = orderList.reduce((p, n) => this.ctx.plus(p, n.total), 0);
  41. const oa = afterSaleList.reduce((p, n) => this.ctx.plus(p, n.money), 0);
  42. const total = this.ctx.minus(ot, oa);
  43. return { total, orderList, afterSaleList };
  44. }
  45. /**
  46. * 对账单售后部分
  47. * @param {Object} query 查询条件
  48. */
  49. async makeBillAfterSalePart(query) {
  50. const { shop, start, end } = query;
  51. const pipline = [];
  52. // 商店过滤&时间过滤
  53. const q = { $match: { $and: [{ apply_time: { $gte: start } }, { apply_time: { $lte: end } }], status: { $in: [ '-1', '-2' ] } } }; // 退款,退货的完成状态, status:{$in:['-1','-2']}, out_bill:{$ne:'0'}
  54. if (shop) q.$match.shop = shop;
  55. pipline.push(q);
  56. // 组织数据
  57. // 单号,商品,规格,退款金额,退款时间
  58. // 单号是要用orderDetail关联获取;商品&规格&退款时间&退款金额有;
  59. pipline.push({ $addFields: { orderDetail_id: { $toObjectId: '$order_detail' } } });
  60. pipline.push({
  61. $lookup: {
  62. from: 'orderDetail',
  63. localField: 'orderDetail_id',
  64. foreignField: '_id',
  65. pipeline: [{ $project: { no: 1, _id: 1 } }],
  66. as: 'orderDetailInfo',
  67. },
  68. });
  69. // 组织数据
  70. pipline.push({ $unwind: '$orderDetailInfo' });
  71. pipline.push({
  72. $project: {
  73. no: '$orderDetailInfo.no',
  74. goods: '$goods.goods.name',
  75. spec: '$goods.name',
  76. end_time: 1,
  77. money: { $toString: '$money' },
  78. rowKey: { $concat: [{ $toString: '$_id' }, '_', '$goods.goods._id', '_', '$goods._id', '_', '$apply_time' ] },
  79. },
  80. });
  81. const afterSaleList = await this.afterSaleModel.aggregate(pipline);
  82. return afterSaleList;
  83. }
  84. /**
  85. * 对账单订单部分
  86. * @param {Object} query 查询条件
  87. */
  88. async makeBillOrderPart(query) {
  89. const { shop, start, end } = query;
  90. const pipline = [];
  91. // 商店过滤&时间过滤
  92. const q = { $match: { $and: [{ pay_time: { $gte: start } }, { pay_time: { $lte: end } }] } }; // , out_bill:{$ne:'0'}
  93. if (shop) q.$match.shop = shop;
  94. pipline.push(q);
  95. // #region 整理数据
  96. // 整理最外层的orderDetail,没用的裁掉
  97. const $project = {
  98. type: 1,
  99. total_detail: 1,
  100. no: 1,
  101. pay_time: 1,
  102. goods: {
  103. _id: 1,
  104. sell_money: 1,
  105. buy_num: 1,
  106. freight: 1,
  107. group_config: { money: 1 },
  108. name: 1,
  109. goods: { name: 1, _id: 1 },
  110. },
  111. };
  112. pipline.push({ $project });
  113. // 按规格平铺开
  114. pipline.push({ $unwind: '$goods' });
  115. // #endregion
  116. const orderList = await this.orderDetailModel.aggregate(pipline);
  117. const dictData = await this.ctx.model.Dev.DictData.find({ code: 'order_type' });
  118. const list = [];
  119. for (const order of orderList) {
  120. const o = _.cloneDeep(order);
  121. const type = dictData.find(f => f.value === o.type);
  122. const moneyDetail = this.moneyDetail(order);
  123. const obj = {
  124. _id: _.get(o, '_id'),
  125. no: _.get(o, 'no'),
  126. type: _.get(type, 'label'),
  127. pay_time: _.get(o, 'pay_time'),
  128. goods_id: _.get(o, 'goods._id'),
  129. goods: _.get(o, 'goods.goods.name'),
  130. spec: _.get(o, 'goods.name'),
  131. spec_id: _.get(o, 'goods._id'),
  132. freight: _.get(o, 'goods.freight'),
  133. buy_num: _.get(o, 'goods.buy_num'),
  134. price: o.type === '1' ? _.get(o, 'goods.group_config.money') : _.get(o, 'goods.sell_money'),
  135. discount: _.get(moneyDetail, 'dt'),
  136. total: o.type === '1' ? _.get(moneyDetail, 'ggrp') : _.get(moneyDetail, 'grp'),
  137. rowKey: `${_.get(o, '_id')}_${_.get(o, 'goods.goods._id')}_${_.get(o, 'goods._id')}`,
  138. };
  139. list.push(obj);
  140. }
  141. return list;
  142. }
  143. moneyDetail(data) {
  144. const ddt = _.get(data, 'total_detail.discount_detail', {});
  145. const { sell_money: sm, freight: f, buy_num: bn, group_config, _id } = data.goods;
  146. const st = this.ctx.multiply(sm, bn);
  147. const ft = this.ctx.multiply(f, bn);
  148. const gt = this.ctx.plus(st, ft);
  149. const dd = {};
  150. for (const uc_id in ddt) {
  151. const detail = _.get(ddt, uc_id, {});
  152. const value = detail[_id];
  153. if (value) dd[uc_id] = value;
  154. }
  155. const dt = Object.values(dd).reduce((p, n) => this.ctx.plus(p, n), 0);
  156. const grp = this.ctx.minus(gt, dt);
  157. let obj = { sm, f, bn, st, ft, gt, dd, dt, grp };
  158. const gsm = _.get(group_config, 'money');
  159. if (gsm) {
  160. const gst = this.ctx.multiply(gsm, bn);
  161. const ggt = this.ctx.plus(gst, ft);
  162. const ggrp = this.ctx.minus(ggt, dt);
  163. obj = { ...obj, gsm, gst, ggt, ggrp };
  164. }
  165. return obj;
  166. }
  167. }
  168. module.exports = BillService;