order.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. 'use strict';
  2. const assert = require('assert');
  3. const _ = require('lodash');
  4. const { ObjectId } = require('mongoose').Types;
  5. const { CrudService } = require('naf-framework-mongoose/lib/service');
  6. const { BusinessError, ErrorCode } = require('naf-core').Error;
  7. class OrderService extends CrudService {
  8. constructor(ctx) {
  9. super(ctx, 'order');
  10. this.model = this.ctx.model.Order;
  11. }
  12. /**
  13. * 新添订单
  14. * @param {Object} data 订单数据
  15. */
  16. async create(data) {
  17. const res = await this.model.create(data);
  18. // 复制进split中
  19. if (!res) throw new BusinessError(ErrorCode.SERVICE_FAULT, '订单创建失败');
  20. await this.copyToSplit(res._id);
  21. try {
  22. this.record(res._id, { method: 'create' });
  23. } catch (error) {
  24. this.logger.error(`订单id:${res.id}记录创建失败:${error.toString()}`);
  25. }
  26. return res;
  27. }
  28. /**
  29. * 修改订单
  30. * @param {Object} { id, ...data } 要修改的订单数据
  31. */
  32. async update({ id, ...data }) {
  33. const res = await this.model.findById(id);
  34. const { goods: newGoods, ...info } = data;
  35. let { goods: oldGoods, split } = res;
  36. if (oldGoods) oldGoods = JSON.parse(JSON.stringify(oldGoods));
  37. if (split) split = JSON.parse(JSON.stringify(split));
  38. // 找到删除项
  39. // oldGoods中有,但是newGoods中却没有的数据,就是要删除的;且需要检验被删除的数据有没有被拆分
  40. oldGoods = oldGoods.map(og => {
  41. const need_delete = newGoods.find(f => ObjectId(f._id).equals(og._id));
  42. if (!need_delete) {
  43. const sobj = split.find(f => ObjectId(f.pid).equals(og._id));
  44. if (sobj) {
  45. // 查找其有没有被拆分
  46. const r = split.find(f => ObjectId(f.pid).equals(sobj._id));
  47. if (r) throw new BusinessError(ErrorCode.DATA_INVALID, '无法删除已被拆分过的货物');
  48. const s_index = split.findIndex(f => ObjectId(f.pid).equals(og._id));
  49. split.splice(s_index, 1);
  50. }
  51. return undefined;
  52. }
  53. return og;
  54. });
  55. oldGoods = _.compact(oldGoods);
  56. // 判断是否有修改项
  57. const updateRes = await this.goodsUpdate(oldGoods, newGoods, split);
  58. if (updateRes) {
  59. const { oldGoods: ogs, split: splist } = updateRes;
  60. if (ogs) oldGoods = ogs;
  61. if (splist) split = splist;
  62. }
  63. // 判断有没有新添的数据
  64. const addGoods = newGoods.filter(f => !f._id);
  65. if (addGoods.length > 0) {
  66. // 有新增货物项
  67. // TODO,复制到split中和oldGoods中
  68. for (const ng of addGoods) {
  69. oldGoods.push(ng);
  70. }
  71. }
  72. res.goods = oldGoods;
  73. res.split = split;
  74. // console.group('oldGoods');
  75. // console.log(oldGoods);
  76. // console.groupEnd();
  77. // console.group('split');
  78. // console.log(split);
  79. // console.groupEnd();
  80. await this.model.update({ _id: ObjectId(id) }, info);
  81. await res.save();
  82. this.copyToSplit(id);
  83. try {
  84. this.record(res._id, { method: 'update' });
  85. } catch (error) {
  86. this.logger.error(`订单id:${res.id}记录创建失败:${error.toString()}`);
  87. }
  88. return;
  89. }
  90. /**
  91. * 检查并处理有修改的货物:拆分就不允许修改了
  92. * @param {Array} oldGoods 查出修改前的货物列表
  93. * @param {Array} newGoods 修改后的货物列表
  94. * @param {Array} split 原拆分货物列表,用来检查是否可以修改
  95. */
  96. async goodsUpdate(oldGoods, newGoods, split) {
  97. oldGoods = oldGoods.map(og => {
  98. const is_split = split.find(f => ObjectId(f.pid).equals(og._id) && f.type === '1');
  99. if (is_split) return og;
  100. // 没有拆分,可以直接更换
  101. const ng = newGoods.find(f => ObjectId(f._id).equals(og._id));
  102. if (ng) return { ...ng, update: true };
  103. return og;
  104. });
  105. // 修改拆分货物列表
  106. const toUpdateSplit = oldGoods.filter(f => f.update);
  107. split = split.map(i => {
  108. const res = toUpdateSplit.find(f => ObjectId(f._id).equals(i.pid));
  109. if (res) {
  110. const obj = this.goodsCopy(res);
  111. return obj;
  112. }
  113. return i;
  114. });
  115. // 将oldGoods的update摘出去
  116. oldGoods = oldGoods.map(i => _.omit(i, [ 'update' ]));
  117. return { oldGoods, split };
  118. }
  119. /**
  120. * 将货物复制成拆分货物的数据并返回
  121. * @param {Object} data 货物列表的每项
  122. * @return split
  123. */
  124. goodsCopy(data) {
  125. const split = _.pick(data, [
  126. 'name',
  127. 'number',
  128. 'weight',
  129. 'volume',
  130. 'transport_type',
  131. 'remark',
  132. ]);
  133. split.pid = data._id;
  134. return split;
  135. }
  136. /**
  137. * 根据订单id,复制货物 到 拆分货物,只是复制,其他操作在各自的方法中,这里只是复制
  138. * @param {String} id 订单id
  139. */
  140. async copyToSplit(id) {
  141. const order = await this.model.findById(id);
  142. if (!order) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到订单');
  143. const { goods, split } = order;
  144. for (const g of goods) {
  145. const has = split.find(f => ObjectId(f.pid).equals(g._id));
  146. if (!has) {
  147. order.split.push(this.goodsCopy(g));
  148. }
  149. }
  150. await order.save();
  151. }
  152. /**
  153. * 发货,添加记录及修改状态
  154. * @param {Array} goods 发货的货物列表
  155. * @param {String} no 运输单号
  156. * @param {String} time 发货日期
  157. */
  158. async sendGoods(goods, no, time) {
  159. for (const g of goods) {
  160. const { split_id, name, number, weight, volume } = g;
  161. const order = await this.model.findOne({ 'split._id': ObjectId(split_id) });
  162. if (!order) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, `未找到该${name}所在的订单信息`);
  163. const obj = { split_id, name, number, weight, volume, no, time };
  164. // 添加该货物的发货记录
  165. order.send_time.push(obj);
  166. // 修改该货物的状态
  167. const good = order.split.id(split_id);
  168. good.status = '1';
  169. order.goods_status = await this.checkGoodsStatus(order.split);
  170. await order.save();
  171. // 更新记录
  172. let message = `${name}已发货(数量:${number};重量:${weight}吨;体积:${volume}m³)`;
  173. const all_send = order.split.every(e => e.status === '0');
  174. if (all_send) message = `${message}; 所有货物已发出`;
  175. try {
  176. this.record(order._id, { method: 'send', message });
  177. } catch (error) {
  178. this.logger.error(`订单id:${order.id}记录创建失败:${error.toString()}`);
  179. }
  180. }
  181. }
  182. /**
  183. * 签收,添加记录及修改状态
  184. * @param {Array} goods 签收的货物列表
  185. * @param {String} no 运输单号
  186. * @param {String} time 签收时间
  187. */
  188. async arriveGoods(goods, no, time) {
  189. for (const g of goods) {
  190. const { split_id, name, number, weight, volume } = g;
  191. const order = await this.model.findOne({ 'split._id': ObjectId(split_id) });
  192. if (!order) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, `未找到该${name}所在的订单信息`);
  193. const obj = { split_id, name, number, weight, volume, no };
  194. if (time) obj.time = time;
  195. // 添加收货记录
  196. order.arrive_time.push(obj);
  197. // 修改该货物的状态
  198. const good = order.split.id(split_id);
  199. good.status = '-1';
  200. order.goods_status = await this.checkGoodsStatus(order.split);
  201. await order.save();
  202. // 更新记录
  203. let message = `${name}已签收(数量:${number};重量:${weight}吨;体积:${volume}m³)`;
  204. const all_arrive = order.split.every(e => e.status === '-1');
  205. if (all_arrive) message = `${message}; 所有货物已签收`;
  206. try {
  207. this.record(order._id, { method: 'arrive', message });
  208. } catch (error) {
  209. this.logger.error(`订单id:${order.id}记录创建失败:${error.toString()}`);
  210. }
  211. }
  212. }
  213. /**
  214. * 检查拆分货物列表,更新goods_status
  215. * @param {Array} splitList 拆分货物列表
  216. */
  217. async checkGoodsStatus(splitList) {
  218. // 未发车
  219. const res = splitList.every(e => e.status === '0');
  220. if (res) return '未发货';
  221. // 检查是否全发车的货物
  222. const all_send = splitList.every(e => e.status === '1');
  223. if (all_send) return '所有货物已发出';
  224. // 检查是否全到达了
  225. const all_arrive = splitList.every(e => e.status === '-1');
  226. if (all_arrive) return '所有货物全部到达';
  227. // 检查是否有发货的
  228. const is_send = splitList.some(e => e.status === '1');
  229. // 检查是否有到达的
  230. const is_arrive = splitList.some(e => e.status === '-1');
  231. const word = [];
  232. if (is_send)word.push('部分货物已发出');
  233. if (is_arrive)word.push('部分货物已到达');
  234. if (word.length > 0) return word.join(';');
  235. return '状态错误';
  236. }
  237. async principalChange(data) {
  238. const { principal, _id } = data;
  239. const res = await this.model.update({ _id: ObjectId(_id) }, { principal });
  240. try {
  241. // TODO 跨库查询该用户姓名
  242. const message = '变更订单负责人';
  243. this.record(_id, { method: 'principal', message });
  244. } catch (error) {
  245. this.logger.error(`订单id:${res.id}记录创建失败:${error.toString()}`);
  246. }
  247. return res;
  248. }
  249. /**
  250. * 订单操作记录
  251. * @param {String} id 订单id
  252. * @param {Object} {method:方法, message:自定义文字} 参数
  253. */
  254. async record(id, { method, message }) {
  255. const order = await this.model.findById(id);
  256. if (!order) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, `未找到订单,传入id:${id}`);
  257. const { authorization } = this.ctx.request.header;
  258. let user = decodeURI(authorization);
  259. if (!user) { throw new BusinessError(ErrorCode.USER_NOT_EXIST, '未找到操作人'); }
  260. user = JSON.parse(user);
  261. const { id: userid, name: username } = user;
  262. const record = { opera: username, operaid: userid };
  263. // 创建记录
  264. if (method === 'create') record.message = `${username}创建订单`;
  265. else if (method === 'update') record.message = `${username}修改订单`;
  266. else if (method === 'in') record.message = `${username}修改收入`;
  267. else if (method === 'out') record.message = `${username}修改支出`;
  268. else if (method === 'split') record.message = `${username}拆分货物`;
  269. else if (method === 'send' || method === 'arrive' || method === 'principal') record.message = `${message}`;
  270. order.record.push(record);
  271. await order.save();
  272. }
  273. }
  274. module.exports = OrderService;