bill.js 5.1 KB

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