123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175 |
- '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 Transaction = require('mongoose-transactions');
- const { ObjectId } = require('mongoose').Types;
- // 对账
- class BillService extends CrudService {
- constructor(ctx) {
- super(ctx, 'bill');
- this.orderDetailModel = this.ctx.model.Trade.OrderDetail;
- this.afterSaleModel = this.ctx.model.Trade.AfterSale;
- this.tran = new Transaction();
- }
- /**
- * 对账标记
- * @param {Object} body 参数体
- * @param body.order 对账的订单内容
- // ** _id:orderDetail的id
- // ** spec_id: 商品规格id
- * @param body.afterSale 对账的售后id集合
- */
- async outBill({ order = [], afterSale = [] }) {
- const data = { out_bill: '0' };
- await this.orderDetailModel.updateMany({ _id: order.map(i => ObjectId(i)) }, data);
- await this.afterSaleModel.updateMany({ _id: afterSale.map(i => ObjectId(i)) }, data);
- }
- /**
- * 生成店铺对账单
- ** 根据店铺id,开始时间和结束时间,形成对账单
- * @param {Object} query 查询条件
- */
- async getBill(query) {
- const { shop, start, end } = query;
- assert(start, '缺少开始时间');
- assert(end, '缺少结束时间');
- const orderList = await this.makeBillOrderPart(query);
- const afterSaleList = await this.makeBillAfterSalePart(query);
- const ot = orderList.reduce((p, n) => this.ctx.plus(p, n.total), 0);
- const oa = afterSaleList.reduce((p, n) => this.ctx.plus(p, n.money), 0);
- const total = this.ctx.minus(ot, oa);
- return { total, orderList, afterSaleList };
- }
- /**
- * 对账单售后部分
- * @param {Object} query 查询条件
- */
- async makeBillAfterSalePart(query) {
- const { shop, start, end } = query;
- const pipline = [];
- // 商店过滤&时间过滤
- const q = { $match: { $and: [{ apply_time: { $gte: start } }, { apply_time: { $lte: end } }], status: { $in: [ '-1', '-2' ] } } }; // 退款,退货的完成状态, status:{$in:['-1','-2']}, out_bill:{$ne:'0'}
- if (shop) q.$match.shop = shop;
- pipline.push(q);
- // 组织数据
- // 单号,商品,规格,退款金额,退款时间
- // 单号是要用orderDetail关联获取;商品&规格&退款时间&退款金额有;
- pipline.push({ $addFields: { orderDetail_id: { $toObjectId: '$order_detail' } } });
- pipline.push({
- $lookup: {
- from: 'orderDetail',
- localField: 'orderDetail_id',
- foreignField: '_id',
- pipeline: [{ $project: { no: 1, _id: 1 } }],
- as: 'orderDetailInfo',
- },
- });
- // 组织数据
- pipline.push({ $unwind: '$orderDetailInfo' });
- pipline.push({
- $project: {
- no: '$orderDetailInfo.no',
- goods: '$goods.goods.name',
- spec: '$goods.name',
- end_time: 1,
- money: { $toString: '$money' },
- rowKey: { $concat: [{ $toString: '$_id' }, '_', '$goods.goods._id', '_', '$goods._id', '_', '$apply_time' ] },
- },
- });
- const afterSaleList = await this.afterSaleModel.aggregate(pipline);
- return afterSaleList;
- }
- /**
- * 对账单订单部分
- * @param {Object} query 查询条件
- */
- async makeBillOrderPart(query) {
- const { shop, start, end } = query;
- const pipline = [];
- // 商店过滤&时间过滤
- const q = { $match: { $and: [{ pay_time: { $gte: start } }, { pay_time: { $lte: end } }] } }; // , out_bill:{$ne:'0'}
- if (shop) q.$match.shop = shop;
- pipline.push(q);
- // #region 整理数据
- // 整理最外层的orderDetail,没用的裁掉
- const $project = {
- type: 1,
- total_detail: 1,
- no: 1,
- pay_time: 1,
- goods: {
- _id: 1,
- sell_money: 1,
- buy_num: 1,
- freight: 1,
- group_config: { money: 1 },
- name: 1,
- goods: { name: 1, _id: 1 },
- },
- };
- pipline.push({ $project });
- // 按规格平铺开
- pipline.push({ $unwind: '$goods' });
- // #endregion
- const orderList = await this.orderDetailModel.aggregate(pipline);
- const dictData = await this.ctx.model.Dev.DictData.find({ code: 'order_type' });
- const list = [];
- for (const order of orderList) {
- const o = _.cloneDeep(order);
- const type = dictData.find(f => f.value === o.type);
- const moneyDetail = this.moneyDetail(order);
- const obj = {
- _id: _.get(o, '_id'),
- no: _.get(o, 'no'),
- type: _.get(type, 'label'),
- pay_time: _.get(o, 'pay_time'),
- goods_id: _.get(o, 'goods._id'),
- goods: _.get(o, 'goods.goods.name'),
- spec: _.get(o, 'goods.name'),
- spec_id: _.get(o, 'goods._id'),
- freight: _.get(o, 'goods.freight'),
- buy_num: _.get(o, 'goods.buy_num'),
- price: o.type === '1' ? _.get(o, 'goods.group_config.money') : _.get(o, 'goods.sell_money'),
- discount: _.get(moneyDetail, 'dt'),
- total: o.type === '1' ? _.get(moneyDetail, 'ggrp') : _.get(moneyDetail, 'grp'),
- rowKey: `${_.get(o, '_id')}_${_.get(o, 'goods.goods._id')}_${_.get(o, 'goods._id')}`,
- };
- list.push(obj);
- }
- return list;
- }
- moneyDetail(data) {
- const ddt = _.get(data, 'total_detail.discount_detail', {});
- const { sell_money: sm, freight: f, buy_num: bn, group_config, _id } = data.goods;
- const st = this.ctx.multiply(sm, bn);
- const ft = this.ctx.multiply(f, bn);
- const gt = this.ctx.plus(st, ft);
- const dd = {};
- for (const uc_id in ddt) {
- const detail = _.get(ddt, uc_id, {});
- const value = detail[_id];
- if (value) dd[uc_id] = value;
- }
- const dt = Object.values(dd).reduce((p, n) => this.ctx.plus(p, n), 0);
- const grp = this.ctx.minus(gt, dt);
- let obj = { sm, f, bn, st, ft, gt, dd, dt, grp };
- const gsm = _.get(group_config, 'money');
- if (gsm) {
- const gst = this.ctx.multiply(gsm, bn);
- const ggt = this.ctx.plus(gst, ft);
- const ggrp = this.ctx.minus(ggt, dt);
- obj = { ...obj, gsm, gst, ggt, ggrp };
- }
- return obj;
- }
- }
- module.exports = BillService;
|