Compare commits

1165 Commits

Author SHA1 Message Date
邹宗楠
376a5b89c2 1 2022-12-23 11:09:38 +08:00
邹宗楠
cd3b091649 1 2022-12-23 11:02:50 +08:00
邹宗楠
1df7d0b2c3 1 2022-12-23 10:59:41 +08:00
邹宗楠
485e2ff3d7 1 2022-12-23 10:57:18 +08:00
邹宗楠
898aca526d 1 2022-12-17 17:07:17 +08:00
邹宗楠
129a386f42 1 2022-12-17 12:51:46 +08:00
邹宗楠
bbb9f2d906 1 2022-12-16 18:18:20 +08:00
邹宗楠
1bc8826aac 1 2022-12-16 17:51:22 +08:00
邹宗楠
586490c31a 1 2022-12-16 17:47:14 +08:00
邹宗楠
a2a142e546 1 2022-12-16 17:38:11 +08:00
邹宗楠
e138e49e27 1 2022-12-16 12:52:24 +08:00
邹宗楠
9212f14ffd 1 2022-12-16 11:48:19 +08:00
邹宗楠
27379c8f3f 1 2022-12-16 11:11:22 +08:00
邹宗楠
331dd51255 1 2022-12-16 11:09:56 +08:00
邹宗楠
29bb629928 1 2022-12-16 09:56:50 +08:00
邹宗楠
a5652f24f3 1 2022-12-16 09:44:52 +08:00
邹宗楠
299db632be 1 2022-12-12 13:49:55 +08:00
邹宗楠
dc8e726b26 1 2022-12-12 13:49:28 +08:00
邹宗楠
4398b0dde6 1 2022-12-12 13:45:44 +08:00
邹宗楠
404379287f 1 2022-12-12 11:57:47 +08:00
邹宗楠
1a5a0a798a 1 2022-12-12 11:47:51 +08:00
邹宗楠
2793c61436 1 2022-12-12 11:39:44 +08:00
邹宗楠
bfd18f1e3c 1 2022-12-12 11:33:46 +08:00
邹宗楠
271889cb78 1 2022-12-12 11:28:44 +08:00
邹宗楠
62722e26b9 1 2022-12-12 11:11:45 +08:00
邹宗楠
ff8e97bb97 1 2022-12-12 11:07:39 +08:00
邹宗楠
4a2213c856 1 2022-12-07 13:49:27 +08:00
邹宗楠
4eb0810099 1 2022-10-21 15:12:02 +08:00
邹宗楠
63fe824223 1 2022-10-21 11:46:04 +08:00
邹宗楠
7ee376827b 1 2022-10-19 18:24:49 +08:00
邹宗楠
9ffc6dd32d 1 2022-10-19 17:11:02 +08:00
邹宗楠
80230993c6 1 2022-10-19 13:38:35 +08:00
邹宗楠
7b4f62ad1c 1 2022-10-19 09:02:34 +08:00
邹宗楠
3555582349 1 2022-10-18 17:31:03 +08:00
邹宗楠
1e220ea385 1 2022-08-30 13:52:31 +08:00
邹宗楠
a5d516f340 1 2022-08-29 15:14:45 +08:00
邹宗楠
690763db2c 1 2022-08-29 14:17:02 +08:00
邹宗楠
a7c6200601 1 2022-08-29 11:39:02 +08:00
邹宗楠
396ab56265 1 2022-08-29 11:28:40 +08:00
邹宗楠
4f0b158c7d 1 2022-08-29 11:26:12 +08:00
邹宗楠
c7fa7bce3d 1 2022-08-29 10:36:18 +08:00
邹宗楠
10736d0638 1 2022-08-29 10:26:46 +08:00
邹宗楠
7a13c37ead 1 2022-08-29 10:17:21 +08:00
邹宗楠
782c970228 1 2022-08-26 11:38:47 +08:00
邹宗楠
6eb1da80c8 1 2022-08-25 17:41:55 +08:00
邹宗楠
c612b569e0 1 2022-08-25 17:18:29 +08:00
邹宗楠
9dafa1729d 1 2022-08-25 16:43:34 +08:00
邹宗楠
e245405325 1 2022-08-25 16:36:53 +08:00
邹宗楠
1e0194d4bb 1 2022-08-25 15:45:09 +08:00
邹宗楠
7881a34fec 1 2022-08-25 15:21:47 +08:00
邹宗楠
1e206d4af6 1 2022-08-25 15:18:12 +08:00
邹宗楠
049a5ffc9f 1 2022-08-25 15:15:05 +08:00
邹宗楠
51390bf6ca 1 2022-08-25 15:08:05 +08:00
邹宗楠
c9f905b396 1 2022-08-25 14:58:54 +08:00
邹宗楠
58f36787f5 1 2022-08-25 14:38:51 +08:00
邹宗楠
e750422cee 1 2022-08-25 14:04:59 +08:00
邹宗楠
66516f7a47 1 2022-08-25 13:47:14 +08:00
邹宗楠
8152b8daea 1 2022-08-25 11:59:31 +08:00
邹宗楠
6245d4fb61 1 2022-08-25 11:55:16 +08:00
邹宗楠
fce2753666 1 2022-08-25 11:22:14 +08:00
邹宗楠
d9ee8386a3 1 2022-08-25 11:02:11 +08:00
邹宗楠
c41e99f7e0 1 2022-08-25 10:57:10 +08:00
邹宗楠
74b18e1d4f 1 2022-08-25 10:35:33 +08:00
邹宗楠
3e064cf976 1 2022-08-25 10:30:16 +08:00
邹宗楠
d082a3a70b 1 2022-08-25 10:20:19 +08:00
邹宗楠
0f6f54635e 1 2022-08-25 10:01:41 +08:00
邹宗楠
a84ad79665 1 2022-08-25 09:50:52 +08:00
邹宗楠
a3ea6de99d 1 2022-08-24 17:48:04 +08:00
邹宗楠
4c37716fb1 1 2022-08-24 16:34:09 +08:00
邹宗楠
a68affad2a 1 2022-08-24 16:22:57 +08:00
邹宗楠
4a0d0ee3df 1 2022-08-24 15:12:44 +08:00
邹宗楠
b30d35b72b 1 2022-08-24 11:24:54 +08:00
邹宗楠
7190d106ab 1 2022-08-24 10:44:32 +08:00
邹宗楠
174aacd231 1 2022-08-24 10:40:42 +08:00
邹宗楠
f51c075891 修改打印机绑定 2022-08-24 09:51:39 +08:00
邹宗楠
4ed660ffe8 1 2022-08-23 16:39:09 +08:00
邹宗楠
c3609b59b2 修改打印机绑定 2022-08-23 15:46:41 +08:00
邹宗楠
14fa03b586 1 2022-08-23 15:03:57 +08:00
邹宗楠
8818dc957c 1 2022-08-22 14:20:42 +08:00
邹宗楠
123c0971da 1 2022-08-22 11:30:08 +08:00
邹宗楠
fec30ce3e7 1 2022-08-22 09:37:57 +08:00
邹宗楠
0349b56a6f 1 2022-08-19 18:33:30 +08:00
邹宗楠
4266a5b0b9 1 2022-08-19 17:31:06 +08:00
邹宗楠
c25bdc27f7 修改打印 2022-08-19 11:08:52 +08:00
邹宗楠
75ad109b81 1 2022-08-19 10:46:12 +08:00
邹宗楠
035497d3ec 1 2022-08-18 18:03:22 +08:00
邹宗楠
23473d2648 1 2022-08-18 09:34:34 +08:00
邹宗楠
80f26a9459 1 2022-08-17 17:43:34 +08:00
邹宗楠
57da276469 1 2022-08-16 14:38:23 +08:00
邹宗楠
b05b144bd9 1 2022-08-16 13:45:21 +08:00
邹宗楠
eee17ff269 1 2022-08-16 12:00:47 +08:00
邹宗楠
f8ee2f5508 1 2022-08-12 16:23:59 +08:00
邹宗楠
001cf56863 1 2022-08-12 15:51:56 +08:00
邹宗楠
4ae09764cb 1 2022-08-12 11:28:20 +08:00
邹宗楠
4759a2d6b5 1 2022-08-11 16:58:02 +08:00
邹宗楠
7e2ac57300 1 2022-08-11 16:19:43 +08:00
邹宗楠
c845eabe69 1 2022-08-11 14:23:06 +08:00
邹宗楠
7efcd3a614 1 2022-08-10 16:04:39 +08:00
邹宗楠
947a2a7ce4 1 2022-08-10 09:34:24 +08:00
邹宗楠
26c613faad 1 2022-08-09 18:01:25 +08:00
邹宗楠
4df39d1d2b 1 2022-08-09 16:00:55 +08:00
邹宗楠
0a51e4bf7c 1 2022-08-09 14:59:17 +08:00
邹宗楠
50fceedd10 1 2022-08-09 14:01:41 +08:00
邹宗楠
fde4807f95 1 2022-08-09 13:49:27 +08:00
邹宗楠
30ef1b3588 1 2022-08-09 11:56:34 +08:00
邹宗楠
b7a86c9003 1 2022-08-09 11:44:05 +08:00
邹宗楠
b47fba8d37 1 2022-08-09 10:06:23 +08:00
邹宗楠
4a655509ed 1 2022-08-08 16:44:28 +08:00
邹宗楠
7d3537dbc0 1 2022-08-08 15:42:46 +08:00
邹宗楠
c21e5ab383 1 2022-08-08 10:53:57 +08:00
邹宗楠
4430003475 1 2022-08-05 16:47:50 +08:00
邹宗楠
0e59a39006 1 2022-08-03 17:19:22 +08:00
邹宗楠
e92ee33ee0 添加日志打印 2022-08-03 11:37:59 +08:00
邹宗楠
c25f161f99 1 2022-08-03 11:33:50 +08:00
邹宗楠
886785acc2 1 2022-08-03 11:18:40 +08:00
邹宗楠
11d389a871 1 2022-08-03 11:04:43 +08:00
邹宗楠
af603074d5 1 2022-08-03 11:02:49 +08:00
邹宗楠
ef78df0887 1 2022-08-03 11:01:02 +08:00
邹宗楠
88dc9adaad 1 2022-08-03 10:58:02 +08:00
邹宗楠
5e92c69f64 1 2022-08-03 10:56:00 +08:00
邹宗楠
04c761ba5f 1 2022-08-03 10:52:29 +08:00
邹宗楠
f324fe4ce4 api 2022-08-03 10:37:10 +08:00
邹宗楠
5e15d68b9f 1 2022-08-03 10:17:07 +08:00
邹宗楠
9f61711154 1 2022-08-01 15:25:01 +08:00
邹宗楠
6e8b14ab3b 1 2022-08-01 15:18:29 +08:00
邹宗楠
2d3f85dbea 1 2022-07-29 15:07:11 +08:00
邹宗楠
cf59208d7a 1 2022-07-29 13:48:05 +08:00
邹宗楠
fecfd2ffe4 1 2022-07-29 11:58:22 +08:00
邹宗楠
2bf71c9fec api 2022-07-29 10:52:06 +08:00
邹宗楠
0fcdc4b32c 1 2022-07-29 10:38:10 +08:00
邹宗楠
3671e373ce 1 2022-07-28 18:08:16 +08:00
邹宗楠
5fd9ff5093 1 2022-07-28 17:12:02 +08:00
邹宗楠
32e4c45ef1 添加打印机所属用户 2022-07-28 16:56:55 +08:00
邹宗楠
847bd705bb 1 2022-07-28 14:51:47 +08:00
邹宗楠
a7df6a480a 1 2022-07-26 17:23:07 +08:00
邹宗楠
5aa919b200 1 2022-07-26 17:11:18 +08:00
邹宗楠
c79c8c77ca 1 2022-07-20 16:18:47 +08:00
邹宗楠
f9c4f9fa50 新修改打印机 2022-07-20 13:54:33 +08:00
邹宗楠
c1b2f097c2 1 2022-07-15 17:46:52 +08:00
邹宗楠
08e71bd933 1 2022-07-15 16:56:06 +08:00
邹宗楠
2ca1dc93c2 添加打印 2022-06-13 13:48:16 +08:00
邹宗楠
46e8de37f8 打桩 2022-06-10 15:59:07 +08:00
suyl
7c92f47be5 aa 2021-08-26 15:22:57 +08:00
suyl
24262f3812 aa 2021-08-18 10:59:45 +08:00
suyl
7fbd055c47 aa 2021-08-13 11:09:40 +08:00
suyl
25dce9601d aa 2021-07-22 18:31:26 +08:00
suyl
46e420a892 payorder 2021-07-22 17:23:55 +08:00
suyl
12d6688b6f aa 2021-07-20 17:29:57 +08:00
suyl
12c1f633cc aa 2021-07-20 16:54:43 +08:00
suyl
b94de1d201 aa 2021-07-20 16:52:41 +08:00
suyl
59cc2d4ffd flow 2021-07-20 15:10:42 +08:00
suyl
1facd77f78 aa 2021-07-20 14:15:35 +08:00
suyl
902a245674 flow 2021-07-20 14:13:39 +08:00
suyl
2fd881f172 aa 2021-07-20 11:19:56 +08:00
suyl
fb3027b34d aa 2021-07-20 11:16:51 +08:00
suyl
0145f18912 a 2021-07-20 09:04:32 +08:00
suyl
c4068f4dfc aa 2021-07-19 18:21:38 +08:00
suyl
b002522cf0 aa 2021-07-15 16:18:10 +08:00
suyl
d55fe9f988 取消打印机sim 2021-07-15 11:25:43 +08:00
suyl
a0a859cf77 aa 2021-07-15 10:46:33 +08:00
suyl
7e251151c6 aa 2021-07-15 10:45:06 +08:00
suyl
802366f44c aa 2021-07-15 10:25:26 +08:00
suyl
647ed0a861 aa 2021-07-15 09:43:26 +08:00
suyl
7c968cb91c aa 2021-07-15 09:39:24 +08:00
suyl
1677bbbee3 aa 2021-07-15 09:36:02 +08:00
suyl
fd69d4dda0 aa 2021-07-15 09:27:24 +08:00
suyl
26f5087072 aa 2021-07-14 10:07:00 +08:00
suyl
97a48e5267 不转译 2021-07-14 10:03:31 +08:00
suyl
38b2a5363b aa 2021-07-14 10:00:09 +08:00
suyl
9aafc7da9a aa 2021-07-14 09:45:23 +08:00
suyl
c0388be7c5 aa 2021-07-14 09:42:15 +08:00
suyl
7284949cd7 unicode 2021-07-14 09:38:31 +08:00
suyl
d083ca165e delseq 2021-07-14 09:31:35 +08:00
suyl
b020d4bf11 aa 2021-07-14 09:30:11 +08:00
suyl
ce62b2d01a updateprinter 2021-07-14 09:23:35 +08:00
suyl
ddfdd6c5c2 aa 2021-07-14 09:20:49 +08:00
suyl
dc0f14021d aa 2021-07-14 09:16:53 +08:00
suyl
faf6d4ff91 aa 2021-07-13 19:01:43 +08:00
suyl
688c17613c aa 2021-07-13 18:53:07 +08:00
suyl
19229449d4 aa 2021-07-13 18:42:52 +08:00
suyl
467d9b1456 aa 2021-07-13 18:41:51 +08:00
suyl
3f34e06eae aa 2021-07-13 18:19:33 +08:00
suyl
ae1ee4d1cb aa 2021-07-13 18:07:05 +08:00
suyl
572a14d171 aa' 2021-07-13 18:00:03 +08:00
suyl
cf3d09b39a check 2021-07-13 16:31:46 +08:00
suyl
41f36bd16c aa 2021-07-13 16:15:09 +08:00
suyl
3af00e3aad aa 2021-07-13 16:13:10 +08:00
suyl
a920e1fe80 param 2021-07-13 16:02:08 +08:00
suyl
7a1fb943de a 2021-07-13 15:57:31 +08:00
suyl
27655b80a5 test ip 2021-07-13 15:54:17 +08:00
suyl
1690888782 aa 2021-07-13 15:49:30 +08:00
suyl
2ef51857b5 test 2021-07-13 15:43:50 +08:00
suyl
e7460cabc5 add log 2021-07-13 15:16:22 +08:00
suyl
f588a2be99 test ip 2021-07-13 15:13:42 +08:00
suyl
3ab96bce79 添加打印机api补全 2021-07-13 14:57:55 +08:00
suyl
49e72ab6bf aa 2021-07-13 14:43:00 +08:00
suyl
da91dbf2d7 aa 2021-07-12 17:53:30 +08:00
suyl
24974efe5f aa 2021-07-12 17:38:18 +08:00
suyl
a25a63b316 a 2021-07-12 16:47:36 +08:00
suyl
335d981dee aa 2021-07-12 16:30:10 +08:00
suyl
5e493288f0 aa 2021-07-12 16:27:33 +08:00
suyl
60277b42d4 aa 2021-07-12 16:25:32 +08:00
suyl
39e0999481 sound 2021-07-09 14:53:33 +08:00
suyl
a5d4a1c5d1 aa 2021-07-09 11:12:16 +08:00
suyl
754749ff4d aa 2021-07-09 11:07:06 +08:00
suyl
295d790dab 修改 2021-07-08 18:08:39 +08:00
suyl
c20d156e19 rptin 2021-07-08 17:56:55 +08:00
suyl
a7315eeb12 aa 2021-07-08 17:15:01 +08:00
suyl
8a0d844adb temp 2021-07-08 17:02:32 +08:00
suyl
2574622760 aa 2021-07-08 14:15:51 +08:00
suyl
cc5eb45624 aa 2021-07-08 11:52:38 +08:00
suyl
9aac434f1a 删一些东西 2021-07-08 11:41:25 +08:00
suyl
9ad4d52352 menu 2021-07-08 09:44:16 +08:00
suyl
2131a724a6 aa 2021-07-07 18:24:27 +08:00
suyl
3fa0cbdfe7 aa 2021-07-07 16:59:01 +08:00
suyl
0584eeb643 aa 2021-07-07 16:39:13 +08:00
suyl
c89c320ee9 aa 2021-07-01 15:57:47 +08:00
suyl
2ee949830a aa 2021-07-01 15:50:04 +08:00
suyl
1697a85de6 aa 2021-07-01 15:47:36 +08:00
suyl
85868a322e aa 2021-07-01 15:42:31 +08:00
suyl
a85684bb96 aa 2021-07-01 15:40:16 +08:00
suyl
43b6c24919 aa 2021-07-01 15:36:58 +08:00
suyl
c5863204c8 aa 2021-07-01 15:31:26 +08:00
suyl
349d760a50 aa 2021-07-01 15:28:29 +08:00
suyl
8374e410f4 查打印机状态测试 2021-07-01 14:53:20 +08:00
suyl
3aec25bbdd 查打印机状态 2021-07-01 14:51:27 +08:00
suyl
92b6d309e4 获取打印消息 2021-07-01 13:52:06 +08:00
suyl
aa0eee9812 常量统一 2021-07-01 11:47:09 +08:00
suyl
89e48b0979 清空打印队列 2021-07-01 11:20:48 +08:00
suyl
585eb0e0de 添加修改删除打印机接口 2021-07-01 11:12:06 +08:00
suyl
58fba95c0f 参数错误处理 2021-07-01 09:07:03 +08:00
suyl
c650ae418d a 2021-06-30 18:59:51 +08:00
suyl
0ed3d3afa7 aa 2021-06-28 18:39:45 +08:00
suyl
1df97c4106 aa 2021-06-28 18:36:15 +08:00
suyl
99300a8715 调试打印 2021-06-28 18:25:23 +08:00
suyl
5a54d537b5 尝试打印 2021-06-28 18:14:46 +08:00
suyl
20fbd266f4 aa 2021-06-28 16:39:58 +08:00
suyl
a1abcff2d5 aa 2021-06-28 14:44:36 +08:00
suyl
052c1362e0 打印信息表 2021-06-28 14:41:40 +08:00
suyl
30a41b59f4 aa 2021-06-28 10:18:19 +08:00
suyl
7ae08dea69 aa 2021-06-28 10:11:07 +08:00
suyl
457bfbf6d0 尝试打印数据 2021-06-25 18:54:22 +08:00
suyl
21ab3d159e 接口返回错误设置 2021-06-25 16:00:16 +08:00
suyl
749de1b0e9 处理公共参数 2021-06-25 15:00:20 +08:00
suyl
5418ace2fc 尝试判断methid 2021-06-25 11:35:47 +08:00
suyl
e54e865ce5 aa 2021-06-25 10:50:30 +08:00
suyl
97cc8cce0d 试试统一api 2021-06-25 10:23:02 +08:00
suyl
ee02691601 aa 2021-06-25 10:11:15 +08:00
suyl
466ca12c91 aa 2021-06-25 10:06:20 +08:00
suyl
b336512a5b aa 2021-06-25 09:32:11 +08:00
suyl
cfcab79a6d aa 2021-06-25 09:00:26 +08:00
suyl
2cc0e81445 aa 2021-06-24 18:24:41 +08:00
suyl
408efdb631 删除一些东西 2021-06-24 16:54:09 +08:00
suyl
df481cd2b5 添加一些model 2021-06-24 16:50:06 +08:00
suyl
f2f7928068 user 修改 2021-06-24 16:26:30 +08:00
suyl
cb0f8c2001 删除一些model和dao文件 2021-06-24 16:18:07 +08:00
suyl
829b00d3c8 删除一些model和dao文件 2021-06-24 16:14:39 +08:00
suyl
5bbcda5b5f print controlller 添加打印机 2021-06-24 16:13:01 +08:00
suyl
1b213dc31f aa 2021-06-24 16:09:37 +08:00
suyl
bfe94e735a aa 2021-06-24 16:09:02 +08:00
suyl
8993e48ae9 aa 2021-06-24 15:37:47 +08:00
suyl
fda538ce92 aa 2021-06-24 15:36:51 +08:00
suyl
e09d175fa8 aa 2021-06-24 15:34:57 +08:00
suyl
e1e735ff46 aa 2021-06-24 15:34:17 +08:00
suyl
179f3f1146 aa 2021-06-24 15:33:35 +08:00
suyl
940af4b622 aa 2021-06-24 15:32:49 +08:00
suyl
dedef13719 aa 2021-06-24 15:32:20 +08:00
suyl
f2178a7548 删除一些不要的 2021-06-24 15:31:47 +08:00
suyl
537fa7b7ea 删除一些不要的 2021-06-24 15:27:39 +08:00
suyl
e4c5cfba61 aa 2021-06-24 15:18:29 +08:00
suyl
5b79b92566 aa 2021-06-24 15:13:20 +08:00
suyl
c2c9f99c68 aa 2021-06-24 14:34:14 +08:00
suyl
a062f6a173 aa 2021-06-24 11:00:32 +08:00
suyl
c07499770b aa 2021-06-24 10:43:34 +08:00
suyl
833209bfbf aa 2021-06-24 10:41:21 +08:00
suyl
ba519bd463 aa 2021-06-24 10:38:39 +08:00
suyl
4aa9b19c99 aa 2021-06-24 10:23:03 +08:00
suyl
e72e5ad83f aa 2021-06-24 10:15:14 +08:00
suyl
dc2ef79fc0 aaa 2021-06-24 10:13:18 +08:00
suyl
afea334ca0 aa 2021-06-24 09:41:01 +08:00
suyl
c246a94365 aa 2021-06-24 09:21:06 +08:00
suyl
7c87c541f2 aa 2021-06-16 10:31:09 +08:00
suyl
587c0aa864 aa 2021-06-16 10:29:15 +08:00
suyl
d8c596515e aa 2021-06-16 10:23:16 +08:00
suyl
55d1b84059 aa 2021-06-16 10:21:51 +08:00
suyl
6814b2ae6b aa 2021-06-16 10:19:57 +08:00
suyl
686aead9f2 aa 2021-06-16 10:15:39 +08:00
suyl
20098751ee aa 2021-06-16 10:06:58 +08:00
suyl
443fb80d6b aa 2021-06-16 09:18:07 +08:00
suyl
ef43ac99c5 aa 2021-06-16 09:13:30 +08:00
suyl
7ac449e71e aa 2021-06-15 19:01:01 +08:00
suyl
44d93ec198 aa 2021-06-15 18:52:26 +08:00
suyl
294a0df50f aa 2021-06-15 18:41:59 +08:00
suyl
621c9fbeb2 aa 2021-06-15 18:41:29 +08:00
suyl
288304c536 aa 2021-06-15 18:21:11 +08:00
suyl
dbdf8f862c aa 2021-06-15 18:18:53 +08:00
suyl
4b5df9f680 aa 2021-06-15 18:12:59 +08:00
suyl
b98ded125a aa 2021-06-15 18:10:02 +08:00
suyl
62933c7ef6 aa 2021-06-15 18:01:26 +08:00
suyl
b5363033d6 aa 2021-06-15 17:57:23 +08:00
suyl
d0e511ff98 aa 2021-06-15 17:49:34 +08:00
suyl
84016134f2 aa 2021-06-15 17:41:33 +08:00
suyl
b23f597060 aa 2021-06-15 17:28:35 +08:00
suyl
2c64ff131b aa 2021-06-15 17:23:55 +08:00
suyl
b9bed1d6d8 aa 2021-06-15 17:05:24 +08:00
suyl
e1b1795be2 aa 2021-06-15 16:57:13 +08:00
suyl
96c499f108 aa 2021-06-15 16:52:44 +08:00
suyl
dcff70b43b aa 2021-06-15 16:49:50 +08:00
suyl
7f9c0e8812 aa 2021-06-15 16:41:13 +08:00
suyl
4f41f766fe aa 2021-06-15 16:36:09 +08:00
suyl
29248dae3b aa 2021-06-15 16:13:53 +08:00
suyl
e3a135f337 aa 2021-06-15 16:11:41 +08:00
suyl
5cafeb9a50 aa 2021-06-15 15:57:07 +08:00
suyl
14ef7cb40a aa 2021-06-15 15:53:14 +08:00
suyl
446aed8515 aa 2021-06-15 15:51:01 +08:00
suyl
1a972a5b09 aa 2021-06-15 15:35:34 +08:00
suyl
e827c53ebc aa 2021-06-15 15:32:32 +08:00
suyl
ae84589963 aa 2021-06-15 15:15:03 +08:00
suyl
81c11062f2 aa 2021-06-15 15:12:22 +08:00
suyl
704fb336e6 aa 2021-06-15 15:00:00 +08:00
suyl
7267473617 aa 2021-06-15 14:47:51 +08:00
suyl
d11f13a0fd aa 2021-06-15 14:45:16 +08:00
suyl
2a2bd56df4 aa 2021-06-15 13:45:29 +08:00
suyl
78aa612a50 aa 2021-06-15 11:38:29 +08:00
suyl
c6275b162f aa 2021-06-15 11:13:30 +08:00
suyl
fe4073597e aa 2021-05-24 17:51:32 +08:00
suyl
d5f8ab6909 aa 2021-05-24 16:26:28 +08:00
suyl
29a15b55cd aa 2021-05-24 16:20:40 +08:00
suyl
9da435d0af aa 2021-05-17 16:41:23 +08:00
suyl
2e6aac79ff aa 2021-05-17 14:48:17 +08:00
suyl
d1d8bbaeb6 aa 2021-05-17 10:36:57 +08:00
suyl
f6c974f73e aa 2021-05-17 09:46:01 +08:00
suyl
9aeaedb2d6 aa 2021-05-17 09:41:59 +08:00
suyl
6b505c474e aa 2021-05-17 09:38:00 +08:00
suyl
4977dd6e72 aa 2021-05-17 09:24:47 +08:00
suyl
611b90e4c4 aa 2021-05-14 18:23:06 +08:00
suyl
f251aab7f2 aa 2021-05-14 11:33:19 +08:00
suyl
61a39bc973 aa 2021-05-14 11:15:34 +08:00
suyl
25c5cfc39f aa 2021-05-13 09:30:17 +08:00
suyl
e3be541ccd aa 2021-05-13 09:07:59 +08:00
suyl
e3c09bed8d aa 2021-05-12 18:28:34 +08:00
suyl
837e14ab0e aa 2021-05-12 15:08:17 +08:00
suyl
0fb3d05d3e aa 2021-05-12 15:05:07 +08:00
suyl
bf5fb8aea5 aa 2021-05-12 15:01:42 +08:00
suyl
83ee99c1d1 aa 2021-05-12 14:59:10 +08:00
suyl
2d8d668f4e aa 2021-05-11 15:03:03 +08:00
suyl
170456ef76 aa 2021-05-11 14:52:00 +08:00
suyl
1bf6ed058e aa 2021-05-11 14:11:41 +08:00
suyl
2bc920719c aa 2021-05-11 09:45:06 +08:00
suyl
3481d09177 aa 2021-05-11 08:41:21 +08:00
suyl
d1438e11bf aa 2021-05-10 16:36:13 +08:00
suyl
2981e57b9a aa 2021-05-10 15:06:47 +08:00
suyl
c321ae5886 aa 2021-05-10 09:06:04 +08:00
suyl
fb10cbb7d2 aa 2021-05-08 15:53:05 +08:00
suyl
8559ccc4f3 aa 2021-05-08 10:46:42 +08:00
suyl
2b81130e0a aa 2021-05-08 10:45:01 +08:00
suyl
ae8a75a975 aa 2021-05-07 16:52:59 +08:00
suyl
14d5bf3d78 aa 2021-05-07 15:46:33 +08:00
suyl
3f9ab86fae aa 2021-05-07 15:36:50 +08:00
suyl
d861e9b2ce aa 2021-05-07 14:51:51 +08:00
suyl
4024f62a6c aa 2021-05-07 14:50:20 +08:00
suyl
c844176703 aa 2021-05-07 14:35:40 +08:00
suyl
17ae45e74c aa 2021-05-07 11:40:23 +08:00
suyl
5e3c72b843 aa 2021-05-07 11:05:54 +08:00
suyl
4c5e825990 unionorder 2021-05-07 11:03:24 +08:00
suyl
c24f179edc aa 2021-05-06 18:31:31 +08:00
suyl
df4a4e333c aa 2021-05-06 18:21:46 +08:00
suyl
f505323837 unionorderstatus 2021-05-06 18:12:39 +08:00
suyl
b6f4138048 union order 2021-05-06 18:03:10 +08:00
suyl
c4dd7832f8 aa 2021-04-29 15:32:40 +08:00
suyl
5697f49bf1 aa 2021-04-28 16:56:23 +08:00
suyl
06b9d035b1 aa 2021-04-28 15:26:03 +08:00
suyl
dfb91baa09 aa 2021-04-28 14:25:32 +08:00
suyl
e216a3b5ae aa 2021-04-28 11:15:55 +08:00
suyl
0ad4efa6a6 aa 2021-04-28 11:12:32 +08:00
suyl
9a725ed9c2 aa 2021-04-28 11:09:38 +08:00
suyl
9dc7291c29 aa 2021-04-28 10:10:28 +08:00
suyl
270eef92ef pdd绑定 2021-04-27 18:14:51 +08:00
suyl
e58964633c aa 2021-04-27 17:12:31 +08:00
suyl
b65e808972 pdd物料推荐 2021-04-27 17:09:42 +08:00
suyl
13d2b1b883 aa 2021-04-27 16:14:40 +08:00
suyl
37c188ffa7 pdd 物料详情 2021-04-27 16:05:51 +08:00
suyl
db199feb00 aa 2021-04-27 15:08:51 +08:00
suyl
ced8c4996e pdd物料 2021-04-27 15:00:27 +08:00
suyl
e65f6c9209 aa 2021-04-27 10:56:20 +08:00
suyl
7279c48a10 平台物料分类 2021-04-27 10:54:33 +08:00
suyl
14f3c29c04 aa 2021-04-26 17:45:23 +08:00
suyl
f1eddbb839 aa 2021-04-26 14:55:22 +08:00
suyl
5b155d0d9c aa 2021-04-26 14:15:50 +08:00
suyl
1216c2d748 pdd活动查询 2021-04-26 14:13:20 +08:00
suyl
8600f85a8f pdd 2021-04-26 11:44:59 +08:00
suyl
29acc9232f aa 2021-04-26 10:59:56 +08:00
suyl
fbc4f96976 aa 2021-04-25 17:55:20 +08:00
suyl
7ebac81dba aa 2021-04-25 17:47:53 +08:00
suyl
6e3b989a13 淘宝饿了么活动 2021-04-25 17:43:11 +08:00
suyl
7c1c1b0045 aa 2021-04-25 16:37:11 +08:00
suyl
0343b77b1e aa 2021-04-25 16:33:04 +08:00
suyl
06a0332878 aa 2021-04-25 16:23:24 +08:00
suyl
18ebaa41c4 a 2021-04-22 16:51:09 +08:00
suyl
910e83ea4b aa 2021-04-22 16:41:21 +08:00
苏尹岚
b2c03d6956 aa 2021-04-21 18:10:45 +08:00
苏尹岚
433b980c52 aa 2021-04-21 17:30:28 +08:00
苏尹岚
a500b2631b aa 2021-04-21 17:08:33 +08:00
苏尹岚
56879c4d64 aa 2021-04-21 17:08:26 +08:00
苏尹岚
5c825f44df aa 2021-04-21 16:04:08 +08:00
苏尹岚
e80007e3ea aa 2021-04-21 15:37:10 +08:00
苏尹岚
309bbfdb62 aa 2021-04-21 14:42:21 +08:00
苏尹岚
20bc619947 aa 2021-04-21 14:34:45 +08:00
苏尹岚
9b3cad6488 aa 2021-04-21 14:10:11 +08:00
苏尹岚
853814df00 aa 2021-04-20 18:14:59 +08:00
苏尹岚
a0b0e31d5c aa 2021-04-20 17:45:08 +08:00
苏尹岚
360d8a5220 美团联盟二维码处理 2021-04-20 16:48:56 +08:00
苏尹岚
5772bdcd1e aa 2021-04-20 15:12:39 +08:00
苏尹岚
c43039abca aa 2021-04-20 13:51:57 +08:00
苏尹岚
1cd87fb87c aa 2021-04-20 11:27:08 +08:00
苏尹岚
a75ed0f33c aa 2021-04-20 09:33:30 +08:00
苏尹岚
14f7fc7828 aa 2021-04-19 15:50:50 +08:00
苏尹岚
89417e6f6d aa 2021-04-19 14:16:26 +08:00
苏尹岚
f442644bdd aa 2021-04-19 13:42:06 +08:00
苏尹岚
f8c86c25d4 aa 2021-04-16 08:40:04 +08:00
苏尹岚
32baa0a091 aa 2021-04-15 17:08:10 +08:00
苏尹岚
fb607a3c41 aa 2021-04-15 15:44:24 +08:00
苏尹岚
4057f8105e aa 2021-04-15 14:31:50 +08:00
苏尹岚
9b84048fe9 aa 2021-04-14 16:40:20 +08:00
苏尹岚
ed410ebb7f aa 2021-04-14 16:30:08 +08:00
苏尹岚
610b767814 aa 2021-04-14 15:51:11 +08:00
苏尹岚
c4d46326ad aa 2021-04-14 14:54:51 +08:00
苏尹岚
493e9ccc64 aa 2021-04-07 17:00:21 +08:00
苏尹岚
bac4c55835 aa 2021-04-07 16:48:23 +08:00
苏尹岚
bf35e6a26d aa 2021-04-07 16:37:53 +08:00
苏尹岚
c9d95b5edd aa 2021-04-07 16:15:08 +08:00
苏尹岚
bf68f22bac aa 2021-04-07 16:10:41 +08:00
苏尹岚
5de1be8b54 aa 2021-04-06 14:36:59 +08:00
苏尹岚
a33fa55f8c aa 2021-04-01 16:26:15 +08:00
苏尹岚
f9ff953e0a aa 2021-04-01 16:09:45 +08:00
苏尹岚
6235597ba6 aa 2021-03-30 16:27:27 +08:00
苏尹岚
5a7e7a0ab7 aa 2021-03-24 14:33:35 +08:00
苏尹岚
625b5a5cbd aa 2021-03-24 14:20:16 +08:00
苏尹岚
74c5171972 aa 2021-03-24 13:48:16 +08:00
苏尹岚
1ff8565566 aa 2021-03-16 09:51:41 +08:00
苏尹岚
807e2a69f1 aa 2021-03-15 08:59:06 +08:00
苏尹岚
95b34af3b7 aa 2021-02-22 17:57:20 +08:00
苏尹岚
37afeaaa04 aa 2021-02-22 17:54:14 +08:00
苏尹岚
60f61435bb aa 2021-02-22 17:45:00 +08:00
苏尹岚
2ed0f94f2f aa 2021-02-22 17:31:45 +08:00
苏尹岚
cc8c1a5a30 aa 2021-02-22 17:24:42 +08:00
苏尹岚
1f7a272aff aa 2021-02-22 16:52:14 +08:00
苏尹岚
a3a86a3d16 aa 2021-02-22 16:35:24 +08:00
苏尹岚
5a3ecfad93 aa 2021-02-02 18:35:53 +08:00
苏尹岚
bbc8763e76 aa 2021-01-21 16:10:42 +08:00
苏尹岚
2464e1d803 aa 2021-01-19 09:35:34 +08:00
苏尹岚
7ef72424bb aa 2021-01-19 09:25:22 +08:00
苏尹岚
4344e06558 aa 2021-01-18 14:18:49 +08:00
苏尹岚
f56ce72034 aa 2021-01-18 14:17:50 +08:00
苏尹岚
ae5dd3abde aa 2021-01-14 15:46:41 +08:00
苏尹岚
22a05e2cef aa 2021-01-14 11:16:40 +08:00
苏尹岚
deb0e60a06 aa 2021-01-12 11:02:21 +08:00
苏尹岚
03a32aa3d6 aa 2021-01-12 10:55:25 +08:00
苏尹岚
41acd31fec aa 2021-01-12 10:49:12 +08:00
苏尹岚
7e7f5ef5fa aa 2021-01-12 10:45:31 +08:00
苏尹岚
a06620e34b aa 2021-01-12 10:36:45 +08:00
苏尹岚
952f06f73d aa 2021-01-12 10:34:30 +08:00
苏尹岚
3838cf2ebf aa 2021-01-12 10:25:03 +08:00
苏尹岚
e3cc92bde9 aa 2021-01-11 15:45:55 +08:00
苏尹岚
0eafe25fa2 aa 2021-01-08 18:14:28 +08:00
苏尹岚
bbf2849a19 aa 2021-01-08 16:29:39 +08:00
苏尹岚
4ff352b5c1 aa 2021-01-08 16:26:14 +08:00
苏尹岚
fcc08de485 aa 2021-01-08 16:21:11 +08:00
苏尹岚
d9f6f165f9 aa 2021-01-08 16:18:50 +08:00
苏尹岚
a7d1ef9e70 aa 2021-01-08 16:16:18 +08:00
苏尹岚
d6021c6f28 aa 2021-01-08 16:10:12 +08:00
苏尹岚
cf9c58799c aa 2021-01-08 16:06:54 +08:00
苏尹岚
8ad648c194 aa 2021-01-08 16:01:08 +08:00
苏尹岚
1a6d1959c4 aa 2021-01-08 15:58:05 +08:00
苏尹岚
7a9b7c5a35 aa 2021-01-08 15:54:27 +08:00
苏尹岚
32a4b83fa9 aa 2021-01-08 15:49:16 +08:00
苏尹岚
79097e11df aa 2021-01-08 15:44:26 +08:00
苏尹岚
8b1ddf6b89 aa 2021-01-08 15:26:07 +08:00
苏尹岚
c4ac98380a aa 2021-01-08 15:15:44 +08:00
苏尹岚
e613558f25 aa 2021-01-08 15:09:58 +08:00
苏尹岚
ca15bf10bb aa 2021-01-08 09:01:08 +08:00
苏尹岚
4138eed6a2 aa 2021-01-07 18:09:45 +08:00
苏尹岚
03d53ddc49 aa 2021-01-07 18:09:33 +08:00
苏尹岚
bf5d742af0 aa 2021-01-07 18:03:58 +08:00
苏尹岚
3e0d1a4e31 aa 2021-01-07 17:57:51 +08:00
苏尹岚
a90b4af799 aa 2021-01-07 16:05:03 +08:00
苏尹岚
027d546151 aa 2021-01-07 10:00:46 +08:00
苏尹岚
1218e2077c aa 2021-01-07 09:36:13 +08:00
苏尹岚
8c981d71b0 aa 2021-01-06 17:30:30 +08:00
苏尹岚
5ce7436e1d aa 2021-01-06 17:25:04 +08:00
苏尹岚
f6a1edea5b aa 2021-01-06 17:13:17 +08:00
苏尹岚
126b8679fe aa 2021-01-06 16:42:00 +08:00
苏尹岚
007fdd7342 a 2021-01-04 18:16:30 +08:00
苏尹岚
78bb668fad aa 2021-01-04 15:50:34 +08:00
苏尹岚
ccdc532142 aa 2021-01-04 15:45:31 +08:00
苏尹岚
a3e80c306c aa 2021-01-04 15:41:37 +08:00
苏尹岚
ccc536b83f aa 2021-01-04 15:39:11 +08:00
苏尹岚
af19dddc5a aa 2021-01-04 15:32:14 +08:00
苏尹岚
c3f387e5b5 aa 2021-01-04 15:29:16 +08:00
苏尹岚
7f2a3c5133 aa 2021-01-04 15:27:09 +08:00
苏尹岚
59d8c30d91 aa 2021-01-04 15:23:39 +08:00
苏尹岚
45e167dd5b aa 2021-01-04 15:16:01 +08:00
苏尹岚
742ee01346 aa 2021-01-04 15:14:02 +08:00
苏尹岚
18b17e846b aa 2021-01-04 15:06:50 +08:00
苏尹岚
7d82d5ad34 aa 2021-01-04 14:57:27 +08:00
苏尹岚
b4be7c3ad7 aa 2021-01-04 14:52:37 +08:00
苏尹岚
4a41424c73 aa 2021-01-04 14:49:27 +08:00
苏尹岚
c659732c5d aa 2021-01-04 14:47:14 +08:00
苏尹岚
6ce886212f aa 2021-01-04 14:34:31 +08:00
苏尹岚
edb3e78650 aa 2021-01-04 14:31:56 +08:00
苏尹岚
3359662363 aa 2021-01-04 14:17:09 +08:00
苏尹岚
b586a93722 a 2021-01-04 11:55:27 +08:00
苏尹岚
31c746f639 aa 2021-01-04 11:31:36 +08:00
苏尹岚
f7d1abc91b aa 2021-01-04 11:30:52 +08:00
苏尹岚
18af6c92f3 aa 2021-01-04 11:12:01 +08:00
苏尹岚
2b9045b8f4 aa 2021-01-04 10:57:55 +08:00
苏尹岚
8a4bf159f8 aa 2021-01-04 10:55:07 +08:00
苏尹岚
b186b7f551 aa 2021-01-04 10:20:10 +08:00
苏尹岚
5a38f81a4a aa 2021-01-04 10:13:50 +08:00
苏尹岚
2c81655f97 aa 2021-01-04 10:09:47 +08:00
苏尹岚
615acd6363 aa 2021-01-04 10:06:34 +08:00
苏尹岚
539afbd153 支付分析 2021-01-04 09:28:00 +08:00
苏尹岚
e2b67fd1cb aa 2021-01-04 09:18:27 +08:00
苏尹岚
24b2247a1f aa 2020-12-31 18:22:48 +08:00
苏尹岚
a561368cf4 aa 2020-12-31 17:29:18 +08:00
苏尹岚
3de4615719 aa 2020-12-31 15:43:33 +08:00
苏尹岚
8434c19887 aa 2020-12-31 13:46:23 +08:00
苏尹岚
ef5a6161d3 aa 2020-12-31 13:43:52 +08:00
苏尹岚
aea7a0eb1e aa 2020-12-31 13:42:19 +08:00
苏尹岚
29cd7f3952 aa 2020-12-31 10:49:02 +08:00
苏尹岚
1a954ad675 aa 2020-12-31 10:25:17 +08:00
苏尹岚
6d66d1ec35 aa 2020-12-31 10:24:19 +08:00
苏尹岚
eda0d50636 aa 2020-12-31 10:15:59 +08:00
苏尹岚
37cf01e182 aa 2020-12-31 09:51:54 +08:00
苏尹岚
01797b9932 aa 2020-12-31 09:33:19 +08:00
苏尹岚
fd6fdd3960 aa 2020-12-30 18:56:27 +08:00
苏尹岚
4f2c857bbf aa 2020-12-30 18:10:51 +08:00
苏尹岚
786ac3f365 aa 2020-12-30 18:03:10 +08:00
苏尹岚
d3966a8e29 aa 2020-12-30 17:55:36 +08:00
苏尹岚
d70431691b aa 2020-12-30 17:50:40 +08:00
苏尹岚
0e9c2fffb5 aa 2020-12-30 16:55:57 +08:00
苏尹岚
2c9bfdac17 aa 2020-12-30 16:12:41 +08:00
苏尹岚
4c8a182300 a 2020-12-30 15:28:31 +08:00
苏尹岚
9a2fbeacb8 a 2020-12-30 15:26:14 +08:00
苏尹岚
608b0b0c41 a 2020-12-30 15:03:11 +08:00
苏尹岚
ef6bccc543 a 2020-12-30 14:51:40 +08:00
苏尹岚
f6bef97830 a 2020-12-30 14:30:44 +08:00
苏尹岚
5feafb676e a 2020-12-30 14:18:52 +08:00
苏尹岚
84de6377eb a 2020-12-30 14:17:21 +08:00
苏尹岚
a2396a4876 a 2020-12-30 14:10:26 +08:00
苏尹岚
cce7839324 a 2020-12-30 14:07:34 +08:00
苏尹岚
d1d592c633 a 2020-12-30 11:51:22 +08:00
苏尹岚
6a6a6e43d6 a 2020-12-30 11:42:30 +08:00
苏尹岚
5efd085da5 aa 2020-12-30 11:18:59 +08:00
苏尹岚
8c5f5cf858 aa 2020-12-29 17:01:17 +08:00
苏尹岚
e3747c81f5 aa 2020-12-29 16:57:00 +08:00
苏尹岚
269b7fa710 aa 2020-12-29 16:40:36 +08:00
苏尹岚
c4ce270e1a aa 2020-12-29 16:15:35 +08:00
苏尹岚
b6ffa0f01f aa 2020-12-29 15:55:21 +08:00
苏尹岚
8f6a6bf47d aa 2020-12-29 15:24:03 +08:00
苏尹岚
55189e1693 aa 2020-12-29 15:22:11 +08:00
苏尹岚
04acffa985 a 2020-12-29 15:09:20 +08:00
苏尹岚
e456ee1be9 a 2020-12-28 16:47:43 +08:00
苏尹岚
1d78471933 a 2020-12-28 14:29:40 +08:00
苏尹岚
85ab238067 aa 2020-12-28 14:22:22 +08:00
苏尹岚
c798070d12 aa 2020-12-28 11:19:13 +08:00
苏尹岚
e9de98e123 aa 2020-12-28 10:58:00 +08:00
苏尹岚
33ac4db9ba aa 2020-12-28 08:46:28 +08:00
苏尹岚
a3f06b2e7f aa 2020-12-25 17:12:12 +08:00
苏尹岚
83bcc38735 a 2020-12-25 16:43:30 +08:00
苏尹岚
da778f7b85 aa 2020-12-25 15:24:50 +08:00
苏尹岚
d26bd44af7 a 2020-12-25 15:18:53 +08:00
苏尹岚
55383ff5fc aa 2020-12-25 13:49:12 +08:00
苏尹岚
d9ad96249b aaa 2020-12-25 11:40:26 +08:00
苏尹岚
6a41d536fa aa 2020-12-25 11:38:33 +08:00
苏尹岚
598e78bba7 aa 2020-12-25 11:35:26 +08:00
苏尹岚
ff1dfebd86 aa 2020-12-25 11:01:47 +08:00
苏尹岚
e3c422c5a3 aa 2020-12-25 10:53:05 +08:00
苏尹岚
0210024dc4 aa 2020-12-25 10:25:07 +08:00
苏尹岚
68e9c5571c aa 2020-12-25 09:13:15 +08:00
苏尹岚
fa9215fe5b aa 2020-12-25 09:09:13 +08:00
苏尹岚
0332b25ea0 aa 2020-12-24 17:46:34 +08:00
苏尹岚
5f343c493b aa 2020-12-24 17:19:08 +08:00
苏尹岚
9b3beb0dc0 tx 2020-12-24 16:20:20 +08:00
苏尹岚
ccac6319a1 aa 2020-12-24 14:30:27 +08:00
苏尹岚
f71a758cc0 aa 2020-12-24 12:00:24 +08:00
苏尹岚
637f6ee7ac aa 2020-12-24 11:59:05 +08:00
苏尹岚
54aeccc534 aa 2020-12-24 10:07:38 +08:00
苏尹岚
7eea91324d aa 2020-12-23 17:55:13 +08:00
苏尹岚
a2313e4b19 aa 2020-12-23 16:49:48 +08:00
苏尹岚
d5b94fdbd2 aa 2020-12-23 16:42:45 +08:00
苏尹岚
d48952079b aa 2020-12-23 14:23:26 +08:00
苏尹岚
fd77a3703c aa 2020-12-23 11:43:51 +08:00
苏尹岚
5fee02bfcd aa 2020-12-23 11:40:12 +08:00
苏尹岚
25671ad532 aa 2020-12-23 11:35:36 +08:00
苏尹岚
35d3330f9d aa 2020-12-23 10:16:07 +08:00
苏尹岚
947750c5c9 aa 2020-12-23 09:28:48 +08:00
苏尹岚
1765620899 aa 2020-12-22 18:19:31 +08:00
苏尹岚
a48e9d13ab aa 2020-12-22 18:09:23 +08:00
苏尹岚
d2e6dd6bf3 aa 2020-12-22 18:05:54 +08:00
苏尹岚
382ef05884 aa 2020-12-22 18:02:32 +08:00
苏尹岚
4a7f691525 aa 2020-12-21 18:18:21 +08:00
苏尹岚
92f0cca62d a 2020-12-21 16:14:45 +08:00
苏尹岚
fd7057525e aa 2020-12-21 14:51:15 +08:00
苏尹岚
bd59cc18a7 aa 2020-12-21 14:44:13 +08:00
苏尹岚
49d0903a2d a 2020-12-18 17:56:18 +08:00
苏尹岚
829e1d76c2 a 2020-12-18 17:02:00 +08:00
苏尹岚
95a7766507 aa 2020-12-18 15:16:26 +08:00
苏尹岚
68626a8cfd a 2020-12-18 14:43:34 +08:00
苏尹岚
17dba6007b a 2020-12-17 17:39:19 +08:00
苏尹岚
1f3164832d a 2020-12-17 17:35:57 +08:00
苏尹岚
e5082bbfe7 reload 2020-12-17 17:23:40 +08:00
苏尹岚
2d1aa60e1c a 2020-12-17 17:05:28 +08:00
苏尹岚
2840dec1b7 a 2020-12-17 17:00:47 +08:00
苏尹岚
4f5c1a8f2b a 2020-12-17 16:48:19 +08:00
苏尹岚
3e41f86386 aa 2020-12-17 16:43:59 +08:00
苏尹岚
af30593ce4 a 2020-12-17 15:28:52 +08:00
苏尹岚
165da4d980 a 2020-12-17 15:25:17 +08:00
苏尹岚
5c678d1117 a 2020-12-17 14:15:39 +08:00
苏尹岚
4d313aea76 aa 2020-12-17 11:34:25 +08:00
苏尹岚
d9059263ee aa 2020-12-17 11:17:54 +08:00
苏尹岚
c7d87be485 a 2020-12-17 10:58:17 +08:00
苏尹岚
ed28a26a6b a 2020-12-17 10:08:51 +08:00
苏尹岚
d3a71dc6fb a 2020-12-17 10:07:39 +08:00
苏尹岚
6555557534 a 2020-12-17 09:51:36 +08:00
苏尹岚
f1dc696967 a 2020-12-17 09:39:51 +08:00
苏尹岚
5f96b68e5e resj 2020-12-17 09:31:41 +08:00
苏尹岚
e150bf5f59 resj 2020-12-17 09:12:56 +08:00
苏尹岚
ee27ffdeef a 2020-12-16 18:24:29 +08:00
苏尹岚
cf22855307 aa 2020-12-16 18:20:42 +08:00
苏尹岚
5ad8dc6ee0 a 2020-12-16 17:50:11 +08:00
苏尹岚
9f80450e0c a 2020-12-16 17:25:43 +08:00
苏尹岚
bccb99e580 duanxin 2020-12-16 11:08:56 +08:00
苏尹岚
5927b8b05d a 2020-12-16 09:22:34 +08:00
苏尹岚
1ad60d560f a 2020-12-16 09:20:21 +08:00
苏尹岚
fd336262f7 aa 2020-12-15 15:23:37 +08:00
苏尹岚
682e8d2947 aa 2020-12-15 15:01:49 +08:00
苏尹岚
ab078d7fd9 aa 2020-12-15 14:30:30 +08:00
苏尹岚
a216e42922 aa 2020-12-15 13:58:00 +08:00
苏尹岚
edff9daa62 aa 2020-12-15 11:00:49 +08:00
苏尹岚
a907462a0a a 2020-12-15 10:24:04 +08:00
苏尹岚
92e28b4176 aa 2020-12-14 15:16:07 +08:00
苏尹岚
f881f7c7b6 a 2020-12-14 15:07:01 +08:00
苏尹岚
05b9b6733d ss 2020-12-14 15:00:44 +08:00
苏尹岚
760269db13 a 2020-12-14 14:55:55 +08:00
苏尹岚
2eb6455122 upload audio 2020-12-14 14:43:02 +08:00
苏尹岚
e1cdb85d3f upload audio 2020-12-14 14:38:36 +08:00
苏尹岚
7b4649b430 upload audio 2020-12-14 14:10:36 +08:00
苏尹岚
309d47cb5b upload audio 2020-12-14 13:54:11 +08:00
苏尹岚
12ab1035ee aa 2020-12-14 13:47:40 +08:00
苏尹岚
f177221c7e a 2020-12-11 18:31:51 +08:00
苏尹岚
edbbbf770c a 2020-12-11 18:26:39 +08:00
苏尹岚
7c4e82b623 a 2020-12-11 17:50:09 +08:00
苏尹岚
cfadba7ad3 a 2020-12-11 17:05:44 +08:00
苏尹岚
0c72be5d8e a 2020-12-11 15:39:07 +08:00
苏尹岚
10dc638f1a aa 2020-12-11 15:23:27 +08:00
苏尹岚
14681aec1e aa 2020-12-11 15:20:34 +08:00
苏尹岚
f3d1635c6c aa 2020-12-11 15:09:26 +08:00
苏尹岚
d9a16fa54b aa 2020-12-11 14:59:30 +08:00
苏尹岚
5c7a5522d4 aa 2020-12-11 14:57:39 +08:00
苏尹岚
c2cf1ce0ef aa 2020-12-11 14:42:13 +08:00
苏尹岚
92f4a59e17 aa 2020-12-11 14:39:25 +08:00
苏尹岚
a96784dbfb a 2020-12-10 15:30:56 +08:00
苏尹岚
d69c31b773 bilifanxian 2020-12-10 14:02:46 +08:00
苏尹岚
caf63a3869 a 2020-12-10 10:26:09 +08:00
苏尹岚
9e07b0b957 aa 2020-12-10 10:04:05 +08:00
苏尹岚
0bb42973ba aa 2020-12-10 09:57:25 +08:00
苏尹岚
3f8bf89836 aa 2020-12-10 09:57:11 +08:00
苏尹岚
a4b7beb735 aa 2020-12-10 09:54:51 +08:00
苏尹岚
6d1eb9d47f aa 2020-12-10 09:52:30 +08:00
苏尹岚
5a668e63cc aa 2020-12-10 09:48:40 +08:00
苏尹岚
01812799c4 aa 2020-12-10 09:46:12 +08:00
苏尹岚
ef6ce5d5e2 aa 2020-12-10 09:43:51 +08:00
苏尹岚
59cbdd8d4d aa 2020-12-10 09:39:24 +08:00
苏尹岚
df8452f7de aa 2020-12-10 09:32:20 +08:00
苏尹岚
680a7df34d aa 2020-12-10 09:30:41 +08:00
苏尹岚
5dd82a44df a 2020-12-09 18:30:39 +08:00
苏尹岚
b4dfec99a2 aa 2020-12-09 17:59:04 +08:00
苏尹岚
4a4e4a69a9 aa 2020-12-09 17:53:08 +08:00
苏尹岚
a3258e9d1a a 2020-12-09 16:23:02 +08:00
苏尹岚
72c29abdd4 a 2020-12-09 16:06:48 +08:00
苏尹岚
6c171a107c dingdingtoken 2020-12-09 15:55:00 +08:00
苏尹岚
4f89bc32d1 dingdingtoken 2020-12-09 15:53:27 +08:00
苏尹岚
3de8b4ca4d jds kuaidi 2020-12-09 15:36:35 +08:00
苏尹岚
633aef8f10 a 2020-12-09 15:22:59 +08:00
苏尹岚
145deb5c70 a 2020-12-09 14:39:34 +08:00
苏尹岚
aad5603c68 aa 2020-12-08 16:43:16 +08:00
苏尹岚
7dd5223dea a 2020-12-08 11:53:59 +08:00
苏尹岚
e6e3afcca7 a 2020-12-08 11:22:35 +08:00
苏尹岚
e1aa2ec029 aa 2020-12-08 11:10:58 +08:00
苏尹岚
bc3463501f aa 2020-12-08 11:07:45 +08:00
苏尹岚
f0d887bc0c aa 2020-12-07 14:45:21 +08:00
苏尹岚
28978f0143 aa 2020-12-07 14:13:34 +08:00
苏尹岚
1afb76de67 shan 2020-12-07 13:52:39 +08:00
苏尹岚
78010354bc 同步油站 2020-12-07 11:01:04 +08:00
苏尹岚
360aed8743 aa 2020-12-07 09:17:19 +08:00
苏尹岚
b87260f34f aa 2020-12-07 09:10:15 +08:00
苏尹岚
ac19d53c8c aa 2020-12-07 09:04:37 +08:00
苏尹岚
edeca69ca9 aa 2020-12-07 09:04:14 +08:00
苏尹岚
a283490d08 a 2020-12-04 18:15:55 +08:00
苏尹岚
3f0dbdcfed a 2020-12-04 18:14:47 +08:00
苏尹岚
8836690b1a a 2020-12-04 17:23:18 +08:00
苏尹岚
09277b1842 aa 2020-12-04 17:09:06 +08:00
苏尹岚
26ece732ff a 2020-12-04 15:24:39 +08:00
苏尹岚
fb72d68235 a 2020-12-04 15:19:47 +08:00
苏尹岚
513e176bf6 a 2020-12-04 15:11:14 +08:00
苏尹岚
ffb12a0e6b a 2020-12-04 15:08:59 +08:00
苏尹岚
c086f337a4 a 2020-12-04 15:00:15 +08:00
苏尹岚
1483691937 a 2020-12-04 14:56:30 +08:00
苏尹岚
42bbc6767c a 2020-12-04 14:51:01 +08:00
苏尹岚
a5aa853f06 a 2020-12-04 14:48:35 +08:00
苏尹岚
a06d1b6d5e aa 2020-12-04 12:02:16 +08:00
苏尹岚
a35c28b20f aa 2020-12-04 11:41:10 +08:00
苏尹岚
d9ed65840f aa 2020-12-04 10:58:44 +08:00
苏尹岚
15cba26b7b a 2020-12-04 10:30:03 +08:00
苏尹岚
1097cbb60e aa 2020-12-03 18:25:02 +08:00
苏尹岚
72c4b6c06a a 2020-12-03 18:12:17 +08:00
苏尹岚
b4b8eaecb0 a 2020-12-03 17:55:20 +08:00
苏尹岚
83190dc848 a 2020-12-03 17:50:48 +08:00
苏尹岚
97b59580ab a 2020-12-03 17:36:00 +08:00
苏尹岚
609a74e559 a 2020-12-03 17:32:13 +08:00
苏尹岚
2f68e749c7 aa 2020-12-03 14:56:25 +08:00
苏尹岚
069c104d09 D:/git/ 2020-12-03 11:46:22 +08:00
苏尹岚
57812bf484 a 2020-12-03 11:43:37 +08:00
苏尹岚
d12e4edd08 aa 2020-12-03 11:33:52 +08:00
苏尹岚
088934adbd a 2020-12-03 11:15:35 +08:00
苏尹岚
3405090597 oilcode 2020-12-02 18:10:22 +08:00
苏尹岚
8fcd186ed3 a 2020-12-02 17:42:44 +08:00
苏尹岚
0f561dc394 aa 2020-12-02 17:08:35 +08:00
苏尹岚
c8c7dbf38e initstation 2020-12-02 15:58:57 +08:00
苏尹岚
b06343c8bf initstation 2020-12-02 15:49:04 +08:00
苏尹岚
2d0f12a9ff aa 2020-12-02 14:51:18 +08:00
苏尹岚
70db40b68d ejy 2020-12-02 14:12:55 +08:00
苏尹岚
4aa8787fd8 a 2020-12-02 11:31:19 +08:00
苏尹岚
8e71f3de18 a 2020-12-02 11:28:55 +08:00
苏尹岚
b03f5ae055 a 2020-12-02 11:26:24 +08:00
苏尹岚
871eb1f74f a 2020-12-02 11:23:57 +08:00
苏尹岚
2502b821d4 a 2020-12-02 11:00:50 +08:00
苏尹岚
eab8fa7311 a 2020-12-02 10:43:03 +08:00
苏尹岚
65340be4da aa 2020-12-02 10:20:09 +08:00
苏尹岚
e4b5efd4eb aa 2020-12-02 09:32:25 +08:00
苏尹岚
ad02997ff7 aa 2020-12-02 09:22:27 +08:00
苏尹岚
66abf4c711 a 2020-12-01 15:33:26 +08:00
苏尹岚
fd11b0cd83 aa 2020-12-01 09:54:53 +08:00
苏尹岚
0788bd8e79 aa 2020-11-30 18:29:28 +08:00
苏尹岚
e247aa69ba aa 2020-11-30 18:26:15 +08:00
苏尹岚
afeb65d616 aa 2020-11-30 15:13:46 +08:00
苏尹岚
bf210c0cdd aa 2020-11-30 15:10:01 +08:00
苏尹岚
5783cef8aa qq 2020-11-30 14:53:59 +08:00
苏尹岚
c092e2cd85 weiduxiaoxi 2020-11-30 14:41:17 +08:00
苏尹岚
b9c15efec4 aa 2020-11-30 11:01:37 +08:00
苏尹岚
8eb3ef3488 aa 2020-11-27 18:00:41 +08:00
苏尹岚
b424457fff test 2020-11-27 17:15:11 +08:00
苏尹岚
19b681ea97 a 2020-11-27 17:04:50 +08:00
苏尹岚
2e2cd0686c post 2020-11-27 16:58:04 +08:00
苏尹岚
28b097cfca a 2020-11-27 11:32:35 +08:00
苏尹岚
ff125d53aa aa 2020-11-24 17:09:46 +08:00
苏尹岚
b04870c607 a 2020-11-24 16:37:23 +08:00
苏尹岚
f2192d4825 a 2020-11-24 16:02:54 +08:00
苏尹岚
22c70edcc4 ad 2020-11-24 16:00:47 +08:00
苏尹岚
97f4e1bc19 aa 2020-11-24 15:42:15 +08:00
苏尹岚
d4ffefce8a aa 2020-11-24 15:36:52 +08:00
苏尹岚
34ea3761f3 aa 2020-11-24 15:25:34 +08:00
苏尹岚
842b5e59bb poped 2020-11-24 14:29:42 +08:00
苏尹岚
126af8f857 weixinmpo 2020-11-24 13:34:45 +08:00
苏尹岚
ec97835313 邀请4人得会员 2020-11-24 08:42:25 +08:00
苏尹岚
6d54e23321 mtmber 2020-11-23 17:08:32 +08:00
苏尹岚
b25c14cb88 mtmber 2020-11-23 17:04:28 +08:00
苏尹岚
04d3483b06 mtmmer 2020-11-23 16:45:07 +08:00
苏尹岚
4dd1ee8ecb subappid 2020-11-23 16:03:10 +08:00
苏尹岚
a5c6193e29 subappid 2020-11-23 10:53:26 +08:00
苏尹岚
7db1975e96 submchid 2020-11-23 10:39:45 +08:00
苏尹岚
c3b062cfbf heihei 2020-11-23 10:31:48 +08:00
苏尹岚
abf763e454 aa 2020-11-23 10:14:25 +08:00
苏尹岚
5088d49c0c wxpay 2020-11-23 10:12:52 +08:00
苏尹岚
a3849bb5b7 aa 2020-11-23 09:42:17 +08:00
苏尹岚
9793d1b274 sys messaged 2020-11-23 09:37:11 +08:00
苏尹岚
f265cd4053 验证微信 2020-11-20 17:06:33 +08:00
苏尹岚
f917c96aa3 验证微信 2020-11-20 16:59:33 +08:00
苏尹岚
487c34e6a9 test 2020-11-20 15:57:33 +08:00
苏尹岚
9e65eded68 test 2020-11-20 15:52:35 +08:00
苏尹岚
cbff4eb618 test 2020-11-20 15:50:44 +08:00
苏尹岚
9da28c7363 test 2020-11-20 15:47:50 +08:00
苏尹岚
158adc8499 test 2020-11-20 15:37:16 +08:00
苏尹岚
52db66616e test 2020-11-20 15:30:19 +08:00
苏尹岚
ecc068f976 test 2020-11-20 15:25:02 +08:00
苏尹岚
8bdf988a14 post 2020-11-20 13:45:30 +08:00
苏尹岚
ace910eb62 post 2020-11-20 13:44:35 +08:00
苏尹岚
047c24c151 test 2020-11-20 13:42:30 +08:00
苏尹岚
c2740e87d9 test 2020-11-20 13:38:09 +08:00
苏尹岚
750ad8fb9a test 2020-11-20 12:04:24 +08:00
苏尹岚
e501c1beaf test 2020-11-20 11:58:08 +08:00
苏尹岚
8d814257b2 test 2020-11-20 11:52:30 +08:00
苏尹岚
118f93fb5a auth 2020-11-20 11:35:01 +08:00
苏尹岚
b2ac231af3 auth 2020-11-20 11:30:40 +08:00
苏尹岚
969f597557 token 2020-11-20 11:24:21 +08:00
苏尹岚
f63794c9e1 getuserinfo 2020-11-20 10:56:24 +08:00
苏尹岚
bccf4b8d4f weixin 2020-11-20 09:54:28 +08:00
苏尹岚
7808360d1c weixin 2020-11-20 09:53:04 +08:00
苏尹岚
d296acfb94 re 2020-11-19 18:01:22 +08:00
苏尹岚
d8f1e361d7 daoxu 2020-11-18 16:51:33 +08:00
苏尹岚
3a7d19e8a3 kuangao 2020-11-18 11:33:30 +08:00
苏尹岚
6d9a96d0ec cao 2020-11-17 17:57:51 +08:00
苏尹岚
f218f16781 heihei 2020-11-17 17:24:37 +08:00
苏尹岚
833bc63cad heihei 2020-11-17 17:22:29 +08:00
苏尹岚
5a0842eba7 查不到单聊才对 2020-11-17 16:07:46 +08:00
苏尹岚
908693fde5 完成提现订单 2020-11-17 15:57:29 +08:00
苏尹岚
9b86d634c5 完成提现订单 2020-11-17 15:56:49 +08:00
苏尹岚
a5a30c5148 getorders 2020-11-17 15:29:56 +08:00
苏尹岚
26751d21f4 getorders 2020-11-17 15:27:09 +08:00
苏尹岚
f0b9ea7385 getorders 2020-11-17 15:26:38 +08:00
苏尹岚
aafa040327 getorders 2020-11-17 15:17:03 +08:00
苏尹岚
869b4f2c35 get orders 2020-11-17 14:07:43 +08:00
苏尹岚
fe57e8a76e cash 2020-11-17 13:54:48 +08:00
苏尹岚
2001383f0f popcode 2020-11-17 11:59:02 +08:00
苏尹岚
a4d0874eda zhengshu 2020-11-17 11:17:18 +08:00
苏尹岚
e68239c6ea aa 2020-11-17 11:12:25 +08:00
苏尹岚
d89375a7ce aa 2020-11-17 10:35:56 +08:00
苏尹岚
32988d0cee aa 2020-11-17 10:32:18 +08:00
苏尹岚
01c475ea95 wx zhengshu 2020-11-17 10:28:09 +08:00
苏尹岚
b62b23562e wx zhengshu 2020-11-17 10:26:51 +08:00
苏尹岚
5fd1522f17 ceshi 2020-11-17 09:46:19 +08:00
苏尹岚
9b7613f436 ceshi 2020-11-17 09:31:53 +08:00
苏尹岚
84a3e4b384 ceshi 2020-11-17 09:25:34 +08:00
苏尹岚
8113852ecc ceshi 2020-11-17 09:21:57 +08:00
苏尹岚
cbf15f6c49 ceshi 2020-11-17 09:18:52 +08:00
苏尹岚
cd48c4b81c 错误 2020-11-17 09:16:02 +08:00
苏尹岚
6488daac1e maxcount 2020-11-17 09:02:10 +08:00
苏尹岚
5cd44c6526 msg 2020-11-16 18:29:13 +08:00
苏尹岚
4eb0730605 sort 2020-11-16 18:23:36 +08:00
苏尹岚
b4cb45389b sort 2020-11-16 18:23:11 +08:00
苏尹岚
0f2789b728 ca 2020-11-16 17:50:13 +08:00
苏尹岚
98ddab4f7b ca 2020-11-16 17:35:16 +08:00
苏尹岚
5199cfe947 heihei 2020-11-16 17:31:42 +08:00
苏尹岚
3c97be837d aa 2020-11-16 17:18:58 +08:00
苏尹岚
70f07549f6 by 2020-11-16 17:10:44 +08:00
苏尹岚
641e05cfd7 待提现 2020-11-16 16:31:28 +08:00
苏尹岚
5d62f14378 查询聊天组 2020-11-16 16:03:42 +08:00
苏尹岚
f920a30389 任务分成 2020-11-16 14:57:08 +08:00
苏尹岚
c7e52925c1 fencheng 2020-11-16 14:14:21 +08:00
苏尹岚
0c140fa4c1 tuiguangm 2020-11-16 11:45:06 +08:00
苏尹岚
eaaa634e5a tuiguangm 2020-11-16 11:39:36 +08:00
苏尹岚
68478588b5 chengdu 2020-11-13 16:47:01 +08:00
苏尹岚
d3c943925c seq 2020-11-13 11:42:47 +08:00
苏尹岚
3cb9790d43 websotckty 2020-11-13 11:12:06 +08:00
苏尹岚
5bdfa981cd websotckty 2020-11-13 10:59:29 +08:00
苏尹岚
dc8f708cc2 websotckty 2020-11-13 10:09:11 +08:00
苏尹岚
8805d78dee websotckty 2020-11-13 09:55:00 +08:00
苏尹岚
aab7167e35 websotckty 2020-11-13 09:53:21 +08:00
苏尹岚
80392c74d5 websotckty 2020-11-13 09:36:13 +08:00
苏尹岚
b12c1b12c6 websotckty 2020-11-13 09:35:09 +08:00
苏尹岚
8180769021 websotckty 2020-11-13 09:33:16 +08:00
苏尹岚
2c0776d388 websotckty 2020-11-13 09:31:26 +08:00
苏尹岚
7fd07db556 websotckty 2020-11-13 09:26:38 +08:00
苏尹岚
01d9af671d qq 2020-11-12 17:12:33 +08:00
苏尹岚
bdb7c8a3f3 嘿嘿 2020-11-12 16:59:06 +08:00
苏尹岚
d37e8e8b4f post 2020-11-12 16:32:41 +08:00
苏尹岚
7ff1c39297 update 2020-11-12 16:30:10 +08:00
苏尹岚
9401aed189 post 2020-11-12 16:25:22 +08:00
苏尹岚
a3f55fc57c aa 2020-11-12 16:21:11 +08:00
苏尹岚
c7d1488296 updatebind 2020-11-12 16:17:23 +08:00
苏尹岚
d5efb69678 heihei 2020-11-11 17:07:44 +08:00
苏尹岚
4ba80a99a5 heihei 2020-11-11 16:53:24 +08:00
苏尹岚
02822598c2 heihei 2020-11-11 16:49:01 +08:00
苏尹岚
3fa1ed6222 heihei 2020-11-11 16:34:25 +08:00
苏尹岚
1256ff79cd heihei 2020-11-11 15:49:25 +08:00
苏尹岚
5d9108c646 heihei 2020-11-11 15:42:10 +08:00
苏尹岚
396e46636a table 2020-11-11 15:19:52 +08:00
苏尹岚
8573e20206 imrecord userid 2020-11-11 14:47:29 +08:00
苏尹岚
9b220dbc68 imrecord userid 2020-11-11 14:45:12 +08:00
苏尹岚
28fbbe1a45 imrecord userid 2020-11-11 14:30:05 +08:00
苏尹岚
cbc81f3c74 imrecord userid 2020-11-11 14:27:46 +08:00
苏尹岚
2887294071 websotckt 2020-11-11 14:20:23 +08:00
苏尹岚
ff16d1db79 websotckt 2020-11-11 14:19:19 +08:00
苏尹岚
d0938be8ab websotckt 2020-11-11 14:16:49 +08:00
苏尹岚
f101b715cf websotckt 2020-11-11 14:13:34 +08:00
苏尹岚
bbff9d2e4f websotckt 2020-11-11 14:03:39 +08:00
苏尹岚
f82b71332e websotckt 2020-11-11 14:00:44 +08:00
苏尹岚
4cda519218 websotckt 2020-11-11 14:00:13 +08:00
苏尹岚
24b826e688 mm 2020-11-11 12:01:39 +08:00
苏尹岚
9290236ae8 getplace 2020-11-11 11:01:18 +08:00
苏尹岚
a2b6c89935 usermanager 2020-11-11 10:57:58 +08:00
苏尹岚
c2dae8e2bb usermanager 2020-11-11 10:43:30 +08:00
苏尹岚
cb6fa7fa74 城市比例 2020-11-11 10:27:12 +08:00
苏尹岚
cd156feba9 提现城市分成比例 2020-11-11 10:17:22 +08:00
苏尹岚
97f9e44e8a fenchengbili 2020-11-11 10:03:25 +08:00
苏尹岚
f6f8141ccf initdata 2020-11-11 09:57:28 +08:00
苏尹岚
6ab1165cff initdata 2020-11-11 09:53:25 +08:00
苏尹岚
433d79254d initdata 2020-11-11 09:50:53 +08:00
苏尹岚
829af27f30 content 2020-11-10 16:51:21 +08:00
苏尹岚
925ef2ffc4 joborderid 2020-11-10 16:37:04 +08:00
苏尹岚
5f0cf841ed deilifveinfo 2020-11-10 14:33:54 +08:00
苏尹岚
85da153440 getjddelivery 2020-11-10 14:06:33 +08:00
苏尹岚
e114e56ab2 chonghuiyuan 2020-11-10 14:00:22 +08:00
苏尹岚
e7627e5904 updateuser 2020-11-10 13:54:00 +08:00
苏尹岚
1be5319436 waykgpric 2020-11-10 11:41:50 +08:00
苏尹岚
b8de5a8a49 getuser 2020-11-10 10:59:08 +08:00
苏尹岚
2de901a9c9 getuser 2020-11-10 10:56:43 +08:00
苏尹岚
801850f1f7 getuser 2020-11-10 10:51:34 +08:00
苏尹岚
1ddd2d7362 getusers 2020-11-10 10:41:57 +08:00
苏尹岚
1aaeab99cc getusers 2020-11-10 10:38:25 +08:00
苏尹岚
32cecd0e98 getusers 2020-11-10 10:22:57 +08:00
苏尹岚
4d3d0fac2a getusers 2020-11-10 09:55:45 +08:00
苏尹岚
c74bf0da82 getusers 2020-11-10 09:51:34 +08:00
苏尹岚
bb2e4a6721 getusers 2020-11-10 09:49:33 +08:00
苏尹岚
e1875b17da getusers 2020-11-10 09:43:55 +08:00
苏尹岚
93a7689a94 getusers 2020-11-10 09:39:30 +08:00
苏尹岚
380554ac2b kuaidi xianzhi 2020-11-10 09:14:35 +08:00
苏尹岚
90b6fcf597 yunfei 2020-11-10 08:46:41 +08:00
苏尹岚
f836b738f0 importmtmember 2020-11-09 14:15:37 +08:00
苏尹岚
3156af3448 updatesuer 2020-11-09 11:00:35 +08:00
苏尹岚
3681e9f7fa updateuser 2020-11-09 10:41:29 +08:00
苏尹岚
8abb7ffd13 导入会员 2020-11-09 10:09:37 +08:00
苏尹岚
bfc99196a8 updateuser 2020-11-09 09:40:07 +08:00
苏尹岚
6b9eb80be9 pay result 2020-11-06 16:33:59 +08:00
苏尹岚
35bd646600 pay result 2020-11-06 16:29:19 +08:00
苏尹岚
f4d4c04659 pay result 2020-11-06 16:26:09 +08:00
苏尹岚
2322394a84 pay result 2020-11-06 16:22:19 +08:00
苏尹岚
235ccab488 pay result 2020-11-06 16:16:59 +08:00
苏尹岚
3933523142 pay result 2020-11-06 16:16:20 +08:00
苏尹岚
d0d2d6c2df pay result 2020-11-06 15:23:01 +08:00
苏尹岚
03dc9b724c cancel accept 2020-11-06 10:18:28 +08:00
苏尹岚
da24bd128d token 2020-11-06 09:00:04 +08:00
苏尹岚
652bbf42c8 pay 2020-11-05 18:29:22 +08:00
苏尹岚
f171cfc468 pay 2020-11-05 18:21:56 +08:00
苏尹岚
fd36e21197 pay 2020-11-05 18:18:05 +08:00
苏尹岚
f037b4434c pay 2020-11-05 18:09:50 +08:00
苏尹岚
c9a3febe47 pay 2020-11-05 18:06:47 +08:00
苏尹岚
c3b653a90a pay 2020-11-05 18:01:00 +08:00
苏尹岚
d954f37d4d pay 2020-11-05 16:56:53 +08:00
苏尹岚
c3e899d65a pay 2020-11-05 16:46:35 +08:00
苏尹岚
cf72ac3c8b address 2020-11-05 16:44:57 +08:00
苏尹岚
49ac45a94a address 2020-11-05 16:20:12 +08:00
苏尹岚
40fd3e6d2c address 2020-11-05 16:00:27 +08:00
苏尹岚
0bc79ac9ba address 2020-11-05 15:49:52 +08:00
苏尹岚
fdd6b879fb auditmilit at 2020-11-05 15:18:30 +08:00
苏尹岚
2b7720be38 auditmilit at 2020-11-05 15:17:13 +08:00
苏尹岚
bb373ef391 auditmilit at 2020-11-05 15:04:43 +08:00
苏尹岚
7b69b96a8a auditmilit at 2020-11-05 14:56:42 +08:00
苏尹岚
0e0a5db339 auditmilit at 2020-11-05 14:53:28 +08:00
苏尹岚
aa3dc4e6f1 send 2020-11-05 14:41:03 +08:00
苏尹岚
dcf0cddf48 heihei 2020-11-05 14:18:37 +08:00
苏尹岚
1e2fc44cf0 return 2020-11-05 11:44:35 +08:00
苏尹岚
85b4b9a1a9 rollback 2020-11-05 11:07:16 +08:00
苏尹岚
e1cd990c76 rollback 2020-11-05 11:02:17 +08:00
苏尹岚
4a986546eb rollback 2020-11-05 10:57:29 +08:00
苏尹岚
57da75ee0d rollback 2020-11-05 10:51:54 +08:00
苏尹岚
bad35a0e0c panic 2020-11-05 10:43:39 +08:00
苏尹岚
34e21b209d test 2020-11-05 09:06:22 +08:00
苏尹岚
233a0a9364 test 2020-11-05 08:59:09 +08:00
苏尹岚
ebc4f888a8 imgs 2020-11-04 16:59:31 +08:00
苏尹岚
916736b0fb billtypenames 2020-11-04 16:43:37 +08:00
苏尹岚
be3ade4a69 getjoborders 2020-11-04 16:38:21 +08:00
苏尹岚
d1f4cf9e75 getjoborders 2020-11-04 16:29:10 +08:00
苏尹岚
54958becc1 getjoborders statusss 2020-11-04 15:37:45 +08:00
苏尹岚
5979dfb148 getjoborders 2020-11-04 10:04:46 +08:00
苏尹岚
662b306ad7 getjoborders 2020-11-04 09:38:54 +08:00
苏尹岚
1637a4215a getjoborders 2020-11-04 09:18:17 +08:00
苏尹岚
d61decc182 getjoborders 2020-11-04 09:17:23 +08:00
苏尹岚
b0576d0d55 wxpay 2020-11-03 18:31:00 +08:00
苏尹岚
8808a71f7c wxpay 2020-11-03 18:26:51 +08:00
苏尹岚
62b7ee89d7 wxpay 2020-11-03 18:05:58 +08:00
苏尹岚
9762d78148 job 2020-11-03 17:49:13 +08:00
苏尹岚
3206ae2f92 spe 2020-11-03 17:33:54 +08:00
苏尹岚
744b8074e1 spe 2020-11-03 16:12:39 +08:00
苏尹岚
76ca18d261 test 2020-11-03 15:59:58 +08:00
苏尹岚
cf37c22103 test 2020-11-03 15:38:05 +08:00
苏尹岚
2984ac1ef0 test 2020-11-03 15:33:53 +08:00
苏尹岚
4186800548 getjobs 2020-11-03 15:13:40 +08:00
苏尹岚
9e7de82c9c getjobs 2020-11-03 15:08:01 +08:00
苏尹岚
e1852e32c4 query delivery 2020-11-03 15:01:26 +08:00
苏尹岚
686416521a sort 2020-11-03 14:23:05 +08:00
苏尹岚
dc1829de5a job 2020-11-03 11:57:06 +08:00
苏尹岚
2b018c4132 lastop 2020-11-03 10:51:44 +08:00
苏尹岚
0315b531c8 place 2020-11-03 09:54:45 +08:00
苏尹岚
c4b70f47d2 place 2020-11-03 09:49:51 +08:00
苏尹岚
8ab2af4f1c distance 2020-11-02 18:25:25 +08:00
苏尹岚
ca819b108c paixu 2020-11-02 17:45:53 +08:00
苏尹岚
3a1edc1237 paixu 2020-11-02 17:44:45 +08:00
苏尹岚
bba63d28a5 deliver fee 2020-11-02 16:10:06 +08:00
苏尹岚
0d679e9871 delivery 2020-11-02 16:07:44 +08:00
苏尹岚
7584a2e689 job 2020-11-02 16:04:24 +08:00
苏尹岚
f08be13855 job 2020-11-02 15:59:03 +08:00
苏尹岚
673ba2f11b weight 2020-11-02 14:07:38 +08:00
苏尹岚
9ddfe8e284 heihei 2020-10-30 18:05:54 +08:00
苏尹岚
cc1071a22a end 2020-10-30 17:44:09 +08:00
苏尹岚
7c2d897f66 renwu 2020-10-30 17:39:02 +08:00
苏尹岚
bcb1e07ff5 job img 2020-10-30 17:26:43 +08:00
苏尹岚
7f11756c97 wx shan 2020-10-30 09:28:29 +08:00
苏尹岚
72c61ec556 wx shan 2020-10-30 09:26:15 +08:00
苏尹岚
2cf7a0157e wx shan 2020-10-30 09:22:37 +08:00
苏尹岚
dd18d0e64d wx shan 2020-10-30 09:10:41 +08:00
苏尹岚
fbad28f76d aapp 2020-10-29 17:52:45 +08:00
苏尹岚
1f080493be wxrz 2020-10-29 15:01:36 +08:00
苏尹岚
b23e804e29 misc 2020-10-29 14:27:34 +08:00
苏尹岚
46a31d79a5 job 2020-10-29 14:26:01 +08:00
苏尹岚
658b005f61 余额不足 2020-10-29 14:05:41 +08:00
苏尹岚
b485bb7bec 余额不足 2020-10-29 14:04:31 +08:00
苏尹岚
baed9d8c4b ss 2020-10-29 13:45:24 +08:00
苏尹岚
9d177646c7 job 2020-10-29 11:45:44 +08:00
苏尹岚
d515dcc656 job 2020-10-29 11:37:25 +08:00
苏尹岚
d583243da8 job 2020-10-29 11:33:29 +08:00
苏尹岚
cb5eb09bba job 2020-10-29 09:50:30 +08:00
苏尹岚
48035f22b6 shan 2020-10-28 18:01:38 +08:00
苏尹岚
5088f29456 京东物流超重验证 2020-10-28 17:18:54 +08:00
苏尹岚
53fcb9f57f 京东物流超重验证 2020-10-28 17:02:08 +08:00
苏尹岚
3e44f00a25 运单验重 2020-10-28 15:56:03 +08:00
苏尹岚
278574a897 mofidt 2020-10-28 14:39:18 +08:00
苏尹岚
4fa27150dc 美团会员和京东物流自动充值 2020-10-28 13:56:05 +08:00
苏尹岚
bbefa6eeea test del 2020-10-28 09:45:03 +08:00
苏尹岚
123d90503d test 2020-10-28 09:43:00 +08:00
苏尹岚
73ce8a77c3 limit type 2020-10-28 09:04:24 +08:00
苏尹岚
c7199a3bc7 limittype 2020-10-28 09:01:28 +08:00
苏尹岚
965293fc14 service 2020-10-27 18:28:30 +08:00
苏尹岚
cba8a36aae yue不足 2020-10-27 16:44:03 +08:00
苏尹岚
b7e25130ce service 2020-10-27 16:40:54 +08:00
苏尹岚
f1db21b302 service 2020-10-27 16:12:59 +08:00
苏尹岚
5ef69f5f5d service 2020-10-27 16:09:05 +08:00
苏尹岚
38312fc43b getservice 2020-10-27 15:11:43 +08:00
苏尹岚
75fae9aa2d qiniu roken 2020-10-27 14:41:44 +08:00
苏尹岚
5199ed7df4 任务定时 2020-10-27 14:34:38 +08:00
苏尹岚
55dddcbb75 jobtime 2020-10-27 11:53:46 +08:00
苏尹岚
a7032ae943 job order userid 2020-10-27 08:59:29 +08:00
苏尹岚
4692e711aa cms 2020-10-26 17:59:41 +08:00
苏尹岚
64c0bc05ed cms 2020-10-26 17:58:51 +08:00
苏尹岚
bbcb8ec37c de bal 2020-10-26 17:37:37 +08:00
苏尹岚
396f81cd58 ope 2020-10-26 16:46:43 +08:00
苏尹岚
ec81fb7947 操作记录 2020-10-26 14:40:26 +08:00
苏尹岚
fad889355b get eneity 2020-10-26 14:38:19 +08:00
苏尹岚
1601813062 query err 2020-10-26 14:13:43 +08:00
苏尹岚
8ad7ed8aaf query err 2020-10-26 11:51:53 +08:00
苏尹岚
55275eb390 query err 2020-10-26 11:43:05 +08:00
苏尹岚
b8e3c39c54 query 2020-10-26 11:21:11 +08:00
苏尹岚
602afa385f query 2020-10-26 11:19:50 +08:00
苏尹岚
100c2ca978 get im rec 2020-10-26 11:11:23 +08:00
苏尹岚
55a43504b6 getjd dele dta 2020-10-23 16:54:40 +08:00
苏尹岚
b4eafb711f 查询用户的京东快递 2020-10-23 16:45:52 +08:00
苏尹岚
4bb5e12d2d cancel jd deli 2020-10-23 16:27:55 +08:00
苏尹岚
d16d67dfc6 send jd deli 2020-10-23 16:01:48 +08:00
苏尹岚
8e23dd4b1e send 2020-10-23 15:48:51 +08:00
苏尹岚
506a9a8764 delivey order 2020-10-23 15:38:16 +08:00
苏尹岚
e211997a61 deliveyr order 2020-10-23 15:35:21 +08:00
苏尹岚
2ae5f3a793 shan 2020-10-23 15:21:58 +08:00
苏尹岚
0460b48bbf user delivery type 2020-10-23 15:08:06 +08:00
苏尹岚
2b0bf4f7fe user delivert 2020-10-23 14:10:05 +08:00
苏尹岚
b8cb5ddff9 user delivery 2020-10-23 14:08:17 +08:00
苏尹岚
6b57bb3078 shan 2020-10-23 14:01:00 +08:00
苏尹岚
410377a578 shan 2020-10-23 13:51:00 +08:00
苏尹岚
520e91ff9d post 2020-10-22 17:28:52 +08:00
苏尹岚
8631c0acc4 post 2020-10-22 17:26:59 +08:00
苏尹岚
0e03ea65c5 post 2020-10-22 17:23:40 +08:00
苏尹岚
8cf944ce80 shangchuantup 2020-10-22 17:21:57 +08:00
苏尹岚
2ea9a04503 shangchuantup 2020-10-22 17:20:39 +08:00
苏尹岚
f24f927a68 shangchuantup 2020-10-22 16:52:02 +08:00
苏尹岚
244e8c8473 shangchuantup 2020-10-22 16:45:12 +08:00
苏尹岚
382f59f545 聊天? 2020-10-22 15:46:58 +08:00
苏尹岚
51a9c62beb modify file name 2020-10-22 15:16:06 +08:00
苏尹岚
b9c49f75a5 billdrtail 2020-10-22 15:10:06 +08:00
苏尹岚
777bdc6d93 退出用户组 2020-10-22 14:23:26 +08:00
苏尹岚
4fc2e9c5df updatemessage 2020-10-22 13:44:29 +08:00
苏尹岚
c160d89f17 updatemessage group 2020-10-22 11:48:21 +08:00
苏尹岚
e96431dbe0 add message 2020-10-22 11:46:13 +08:00
苏尹岚
b8f18712a9 创建聊天组 2020-10-22 10:23:04 +08:00
苏尹岚
bd1ae5558c create messagegroup 2020-10-22 09:41:18 +08:00
苏尹岚
bbf527d419 createmessagegruop 2020-10-22 08:40:20 +08:00
苏尹岚
7e32707c8b createmessagegruop 2020-10-22 08:34:47 +08:00
苏尹岚
dd8d91d021 创建聊天组 2020-10-21 11:51:32 +08:00
苏尹岚
2c57b36537 创建聊天组 2020-10-21 11:50:06 +08:00
苏尹岚
9861f7a774 创建聊天组 2020-10-21 11:43:15 +08:00
苏尹岚
9b8fc7e1dc 创建聊天组 2020-10-21 11:12:47 +08:00
苏尹岚
16458454bd 创建聊天组 2020-10-21 11:07:41 +08:00
苏尹岚
fe53668185 创建聊天组 2020-10-21 11:02:31 +08:00
苏尹岚
9c3be6bcc7 jobimg 2020-10-20 17:42:26 +08:00
苏尹岚
c30588b9ea job img 2020-10-20 17:34:56 +08:00
苏尹岚
b6837feb2c mtmember 2020-10-20 17:30:39 +08:00
苏尹岚
379d826b44 spjob 2020-10-20 16:37:52 +08:00
苏尹岚
a6034b3535 swagger 2020-10-20 16:22:23 +08:00
苏尹岚
871e88d1e5 特殊任务购买 2020-10-20 15:20:38 +08:00
苏尹岚
66ba2b5e82 导入美团绘图那 2020-10-20 15:10:45 +08:00
苏尹岚
3426100635 mt member 2020-10-20 15:01:34 +08:00
苏尹岚
d20d77c8ec cash limit 2020-10-20 14:19:18 +08:00
苏尹岚
150ec0701c cash finish 2020-10-20 13:51:30 +08:00
苏尹岚
29946b79d9 wx cash 2020-10-20 11:51:42 +08:00
苏尹岚
a765af69ee finacl wxpay 2020-10-20 11:11:45 +08:00
苏尹岚
768d187ba6 wxpay 2020-10-20 11:10:43 +08:00
苏尹岚
5a76c726c4 wxpay 2020-10-20 11:02:54 +08:00
苏尹岚
5dd72f7b2d wxpay 2020-10-20 11:01:15 +08:00
苏尹岚
64f8ebd43f wxpay 2020-10-20 10:47:10 +08:00
苏尹岚
ac20216437 accountbalacne 2020-10-20 10:34:35 +08:00
苏尹岚
adf90f21e0 cash 2020-10-20 09:26:26 +08:00
苏尹岚
5f59b7bdd9 prod 2020-10-19 16:01:59 +08:00
苏尹岚
a9e9d30308 member 2020-10-19 15:25:31 +08:00
苏尹岚
a41052cd9c member 2020-10-19 15:15:52 +08:00
苏尹岚
10d66dda21 wxapp 2020-10-19 15:14:20 +08:00
苏尹岚
7580a79422 member 2020-10-19 13:38:24 +08:00
苏尹岚
d9f8d2f4bb member 2020-10-19 11:04:13 +08:00
苏尹岚
00553e32e8 member 2020-10-19 11:01:04 +08:00
苏尹岚
5a95250bcd 一个余额 2020-10-19 10:38:39 +08:00
苏尹岚
793669a976 getselfinfo 2020-10-19 09:21:43 +08:00
苏尹岚
dab6ba84d2 getselfinfo 2020-10-19 09:08:31 +08:00
苏尹岚
a3d169d2f0 yzm 2020-10-16 17:57:14 +08:00
苏尹岚
d25ee35268 yzm 2020-10-16 17:55:25 +08:00
苏尹岚
c887a0a14a yzm 2020-10-16 17:52:50 +08:00
苏尹岚
1132be64dc del 2020-10-16 17:49:11 +08:00
苏尹岚
67f4bddc4c yanzm 2020-10-16 17:43:02 +08:00
苏尹岚
50759aec9f del 2020-10-16 17:21:24 +08:00
苏尹岚
e05f313c1a ces 2020-10-16 17:14:02 +08:00
苏尹岚
74e4ca6479 index 2020-10-16 16:59:51 +08:00
苏尹岚
d2c6d02b82 event 2020-10-16 16:21:22 +08:00
苏尹岚
3c05d41246 addmessagegroup 2020-10-16 15:56:38 +08:00
苏尹岚
8c7806bf3d refresh job 2020-10-16 15:16:26 +08:00
苏尹岚
cc9ac79e45 audit job 2020-10-16 15:07:29 +08:00
苏尹岚
4737c354e4 audit job 2020-10-16 15:03:16 +08:00
苏尹岚
1c1784943e job submit 2020-10-16 11:51:52 +08:00
苏尹岚
47c2cd12fe acceptjob 2020-10-16 10:38:01 +08:00
苏尹岚
25461b7f8f job statsu 2020-10-16 10:11:05 +08:00
苏尹岚
2dbd9d542b joborders 2020-10-16 09:59:25 +08:00
苏尹岚
61252f4527 message 2020-10-15 17:56:28 +08:00
苏尹岚
4c05c1a7b2 聊天组 2020-10-15 15:58:12 +08:00
苏尹岚
f78f323db2 job limit 2020-10-15 14:16:48 +08:00
苏尹岚
3f9d251990 rsm appcinfig 2020-10-15 09:06:19 +08:00
苏尹岚
f5f93381ab beta 2020-10-15 09:01:52 +08:00
苏尹岚
1d56ce77f7 adduserbill 2020-10-15 08:58:36 +08:00
苏尹岚
1482ff8cee 发布job 2020-10-14 18:30:50 +08:00
苏尹岚
54438022ff bill job 2020-10-14 18:29:36 +08:00
苏尹岚
0ff054afed pay 2020-10-14 16:01:58 +08:00
苏尹岚
cbe94c7916 pay 2020-10-14 15:25:26 +08:00
苏尹岚
3fa46c9afd order 2020-10-14 14:58:46 +08:00
苏尹岚
fac92a6c7a order 2020-10-14 14:44:53 +08:00
苏尹岚
bd361fa881 shan 2020-10-14 13:48:23 +08:00
苏尹岚
eb950f11bf shan 2020-10-14 13:47:11 +08:00
苏尹岚
accb629e14 shan 2020-10-14 11:57:12 +08:00
苏尹岚
5f791290ca getjobs 2020-10-14 10:29:23 +08:00
苏尹岚
fb9992e616 getjobs 2020-10-14 10:29:09 +08:00
苏尹岚
6f848954d1 beta 2020-10-14 09:36:28 +08:00
苏尹岚
0b36b4b81f beta 2020-10-14 09:36:03 +08:00
苏尹岚
49ad561d54 xianzhi 2020-10-14 09:31:29 +08:00
苏尹岚
1133684e3b job 2020-10-14 09:18:59 +08:00
苏尹岚
8f746dcfea fabu renwu 2020-10-13 18:09:28 +08:00
苏尹岚
602f088dba job 2020-10-13 16:55:45 +08:00
苏尹岚
208104c751 congih 2020-10-13 15:52:53 +08:00
苏尹岚
d84c7679b7 cotr 2020-10-13 15:51:06 +08:00
苏尹岚
1932dbf8a8 c 2020-10-13 14:38:11 +08:00
苏尹岚
2ab79d949a appconfg crm 2020-10-13 14:18:55 +08:00
苏尹岚
cc96feb587 appconfg crm 2020-10-13 14:18:06 +08:00
苏尹岚
60baba6bde event 2020-10-13 14:16:39 +08:00
苏尹岚
078327e8d5 event 2020-10-13 12:02:07 +08:00
苏尹岚
f2f7e511a3 job model 2020-10-13 11:58:11 +08:00
苏尹岚
2d86b6a928 job 2020-10-13 11:56:52 +08:00
苏尹岚
82a4e58c08 job 2020-10-13 11:38:34 +08:00
苏尹岚
be58e21519 job 2020-10-13 11:21:48 +08:00
苏尹岚
c9263befb3 order 2020-10-13 09:36:51 +08:00
苏尹岚
1affa3afbb order 2020-10-13 09:06:56 +08:00
苏尹岚
32506c47d4 order 2020-10-12 18:29:34 +08:00
苏尹岚
6aa221391a bill 2020-10-12 17:35:21 +08:00
苏尹岚
81d8f3e421 shan 2020-10-12 17:22:09 +08:00
苏尹岚
49c149c531 c 2020-10-12 17:19:40 +08:00
苏尹岚
9b62c93016 c 2020-10-12 17:18:17 +08:00
苏尹岚
20936ca4c8 shanyici 2020-10-12 17:14:32 +08:00
苏尹岚
845c83bb09 user model 2020-10-12 17:10:57 +08:00
苏尹岚
52b0778d59 删除修改 2020-10-12 17:01:08 +08:00
苏尹岚
20fcc857d5 mysql conn 2020-10-10 18:34:24 +08:00
苏尹岚
d807f7f51c jxteam 2020-10-10 15:31:37 +08:00
苏尹岚
045d54844f shan 2020-10-10 11:45:23 +08:00
苏尹岚
99532b7aec shan 2020-10-10 11:36:02 +08:00
392 changed files with 4175 additions and 99272 deletions

View File

@@ -4,13 +4,14 @@ import (
"bytes"
"encoding/base64"
"errors"
"fmt"
"regexp"
"strings"
"time"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/dao"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/globals/api"
"github.com/dchest/captcha"
@@ -212,9 +213,6 @@ func SendVerifyCode(authToken, captchaID, captchaValue, authID string) (verfifyC
if handler := authers[authType]; handler == nil {
err = ErrIllegalAuthType
} else {
//if user, _ := dao.GetUserByID(dao.GetDB(), "mobile", authID); user != nil {
// return "", authInfo, fmt.Errorf("该用户已存在,请勿重复注册!")
//}
verfifyCode, err = handler.SendVerifyCode(authID)
}
}
@@ -246,7 +244,6 @@ func LoginInternal(ctx *Context, authType, authID, authIDType, authSecret string
realAuthID = user.GetID()
}
if authBindEx, err = handler.VerifySecret(realAuthID, authSecret); err == nil {
globals.SugarLogger.Debugf("Login authBindEx", utils.Format4Output(authBindEx, false))
if authBindEx == nil { // mobile, email会返回nil表示不会新建AuthBind实体
user = userProvider.GetUser(authID, authIDType)
authBindEx = &AuthBindEx{
@@ -269,10 +266,6 @@ func LoginInternal(ctx *Context, authType, authID, authIDType, authSecret string
// if user != nil {
// authBindEx.UserID = user.GetID()
// }
if user2 := userProvider.GetUser(authBindEx.UserHint.Email, UserIDMobile); user2 != nil {
user = user2
}
} else if authBindEx.UserID != "" {
user = userProvider.GetUser(authBindEx.UserID, UserIDID)
}
@@ -284,9 +277,9 @@ func LoginInternal(ctx *Context, authType, authID, authIDType, authSecret string
//如果是小程序
if authType == "weixinmini" || authType == "weixinapp" {
appID := strings.Split(authSecret, ",")[0]
if appID == "wx08a5c2a8581414ff" || appID == "wx2d6949f724b2541d" || appID == "wx18111a41fd17f24f" || appID == "wx4b5930c13f8b1170" { //菜市或者果园
if authInfo.AuthBindInfo.UserID != "" {
binds, err := dao.GetUserBindAuthInfo(dao.GetDB(), authInfo.AuthBindInfo.UserID, 0, nil, "", "", []string{"wx2bb99eb5d2c9b82c", "wx4b5930c13f8b1170"})
if appID == "wxa4a76d7b4c88604e" || appID == "wx2d6949f724b2541d" || appID == "wx18111a41fd17f24f" { //菜市或者果园
if user != nil {
binds, err := dao.GetUserBindAuthInfo(dao.GetDB(), user.GetID(), 0, nil, "", "", "wx2bb99eb5d2c9b82c")
if err != nil {
return authInfo, err
}
@@ -347,18 +340,6 @@ func AddAuthBind(user IUser, newAuthInfo *AuthInfo) (err error) {
return err
}
func AddAuthBindWithMobile(authInfo *AuthInfo, mobile string) (err error) {
if handler := authers[authInfo.AuthBindInfo.Type]; handler != nil {
user, _ := dao.GetUserByID(dao.GetDB(), "mobile", mobile)
authInfo.AuthBindInfo.UserID = user.UserID
//handler.UnbindAuth(user.GetID(), newAuthInfo.GetAuthType(), newAuthInfo.GetAuthTypeID(), user.GetName())
err = handler.AddAuthBind(authInfo.AuthBindInfo, user.GetName())
} else {
err = ErrIllegalAuthType
}
return err
}
func UnbindAuth(userID, authType, authTypeID, userName string) (err error) {
globals.SugarLogger.Debugf("UnbindAuth userID:%s, authType:%s, authTypeID:%s, userName:%s", userID, authType, authTypeID, userName)
if handler := authers[authType]; handler != nil {
@@ -482,7 +463,7 @@ func DisableUser(userID, operatorUserName string) (err error) {
}
func GetUserBindAuthInfo(userID string) (authList []*model.AuthBind, err error) {
return dao.GetUserBindAuthInfo(dao.GetDB(), userID, model.AuthBindTypeAuth, nil, "", "", nil)
return dao.GetUserBindAuthInfo(dao.GetDB(), userID, model.AuthBindTypeAuth, nil, "", "", "")
}
func DeletedTokenInfoWithoutParam(authInfo *AuthInfo) (err error) {
@@ -495,3 +476,16 @@ func DeletedTokenInfoWithoutParam(authInfo *AuthInfo) (err error) {
}
return err
}
func CheckWeixinminiAuthBind(userID string) (err error) {
var (
db = dao.GetDB()
)
authBinds, err := dao.GetUserBindAuthInfo(db, userID, model.AuthBindTypeAuth, []string{"weixinmini", "weixinapp"}, "", "", "")
if len(authBinds) == 0 {
return fmt.Errorf("请绑定微信认证方式!")
} else {
return nil
}
return err
}

View File

@@ -1,42 +0,0 @@
package alipay
import (
"git.rosy.net.cn/baseapi/platformapi/alipayapi"
"git.rosy.net.cn/jx-callback/business/auth2"
"git.rosy.net.cn/jx-callback/business/auth2/authprovider"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/globals/api"
)
const (
AuthType = "alipaycode"
AuthKey = "GHp3ojlVYRRu2XID4FX2ew=="
)
type Auther struct {
authprovider.DefAuther
}
var (
AutherObj *Auther
)
func init() {
AutherObj = new(Auther)
auth2.RegisterAuther(AuthType, AutherObj)
}
func (a *Auther) VerifySecret(dummy, code string) (authBindEx *auth2.AuthBindEx, err error) {
globals.SugarLogger.Debugf("VerifySecret dummy:%s, code:%s", dummy, code)
tokenInfo, err := api.AliPayAPI.SystemAuthToken(alipayapi.GrantTypeCode, code, "")
if err == nil {
//userInfo, err2 := api.AliPayAPI.UserInfoShare(tokenInfo.AccessToken)
//if err = err2; err == nil {
if authBindEx, err = a.UnionFindAuthBind(AuthType, api.AliPayAPI.GetAppID(), nil, tokenInfo.UserID, tokenInfo.AlipayUserID, tokenInfo); err == nil {
authBindEx.AuthSecret = tokenInfo.AccessToken
authBindEx.AuthSecret2 = tokenInfo.RefreshToken
}
}
return authBindEx, err
}

View File

@@ -9,8 +9,8 @@ import (
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/auth2"
"git.rosy.net.cn/jx-callback/business/dao"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/globals/api"
)
@@ -82,7 +82,7 @@ func (a *DefAuther) UnionFindAuthBind(curAuthType, curAuthTypeID string, unionAu
} else if dao.IsNoRowsError(err) { // 直接找不到尝试unionID
if unionID != "" { // 且有unionID
var authBindList []*model.AuthBind
if authBindList, err = dao.GetUserBindAuthInfo(db, "", model.AuthBindTypeAuth, unionAuthTypeList, "", unionID, nil); err == nil && len(authBindList) > 0 { // 通过unionID找到至少一个认证方式
if authBindList, err = dao.GetUserBindAuthInfo(db, "", model.AuthBindTypeAuth, unionAuthTypeList, "", unionID, ""); err == nil && len(authBindList) > 0 { // 通过unionID找到至少一个认证方式
authBind = authBindList[0]
authBind.Type = curAuthType
authBind.TypeID = curAuthTypeID

View File

@@ -1,6 +0,0 @@
package dingding
const (
AuthTypeStaff = "ddstaff" // 钉钉企业登录
AuthTypeQRCode = "ddqrcode"
)

View File

@@ -1,37 +0,0 @@
package dingding
import (
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/auth2"
"git.rosy.net.cn/jx-callback/business/auth2/authprovider"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/globals/api"
)
type QRCodeAuther struct {
authprovider.DefAuther
}
var (
AutherObjQRCode *QRCodeAuther
)
func init() {
AutherObjQRCode = new(QRCodeAuther)
auth2.RegisterAuther(AuthTypeQRCode, AutherObjQRCode)
}
func (a *QRCodeAuther) VerifySecret(dummy, code string) (authBindEx *auth2.AuthBindEx, err error) {
globals.SugarLogger.Debugf("dingding qrcode VerifySecret code:%s", code)
userQRInfo, err := api.DingDingQRCodeAPI.GetUserInfoByCode(code)
if err == nil {
globals.SugarLogger.Debugf("dingding qrcode VerifySecret code:%s, userQRInfo:%s", code, utils.Format4Output(userQRInfo, false))
if authBindEx, err = a.UnionFindAuthBind(AuthTypeQRCode, api.DingDingQRCodeAPI.GetAppID(), []string{AuthTypeStaff, AuthTypeQRCode}, userQRInfo.OpenID, userQRInfo.UnionID, userQRInfo); err == nil {
authBindEx.UserHint = &auth2.UserBasic{
Name: userQRInfo.Nickname,
}
}
}
return authBindEx, err
}

View File

@@ -1,47 +0,0 @@
package dingding
import (
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/auth2"
"git.rosy.net.cn/jx-callback/business/auth2/authprovider"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/globals/api"
)
type StaffAuther struct {
authprovider.DefAuther
}
var (
AutherObjStaff *StaffAuther
)
func init() {
AutherObjStaff = new(StaffAuther)
auth2.RegisterAuther(AuthTypeStaff, AutherObjStaff)
}
func (a *StaffAuther) VerifySecret(dummy, code string) (authBindEx *auth2.AuthBindEx, err error) {
globals.SugarLogger.Debugf("dingding staff VerifySecret code:%s", code)
userID, err := api.DingDingAPI.GetUserID(code)
if err == nil {
userDetail, err2 := api.DingDingAPI.GetUserDetail(userID.UserID)
if err = err2; err == nil {
if authBindEx, err = a.UnionFindAuthBind(AuthTypeStaff, api.DingDingQRCodeAPI.GetAppID(), []string{AuthTypeStaff, AuthTypeQRCode}, userID.UserID, utils.Interface2String(userDetail["unionid"]), userDetail); err == nil {
authBindEx.UserHint = &auth2.UserBasic{
UserID2: userID.UserID,
Mobile: utils.Interface2String(userDetail["mobile"]),
Email: utils.Interface2String(userDetail["email"]),
Name: utils.Interface2String(userDetail["name"]),
}
}
}
}
return authBindEx, err
}
func (a *StaffAuther) GetUserType() (userType int8) {
return model.UserTypeOperator
}

View File

@@ -1,90 +0,0 @@
package mobile
import (
"errors"
"fmt"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/auth2"
"git.rosy.net.cn/jx-callback/business/auth2/authprovider"
"git.rosy.net.cn/jx-callback/globals"
aliyunsmsclient "github.com/KenmyZhang/aliyun-communicate"
)
const (
AuthType = auth2.AuthTypeMobile
TestVerifyCode = "123456"
)
var (
warningMap = map[string]int{
"isv.AMOUNT_NOT_ENOUGH": 1,
"isv.ACCOUNT_ABNORMAL": 1,
"isv.OUT_OF_SERVICE": 1,
"isv.DAY_LIMIT_CONTROL": 1,
}
)
var (
ErrVerifyCodeIsWrong = errors.New("验证码错")
)
type Auther struct {
authprovider.DefAuther
}
var (
AutherObj *Auther
)
func init() {
AutherObj = new(Auther)
auth2.RegisterAuther(AuthType, AutherObj)
}
// 特殊接口
func (a *Auther) SendVerifyCode(mobileNumber string) (verifyCode string, err error) {
verifyCode = a.GenerateVerifyCode(mobileNumber)
smsClient := aliyunsmsclient.New("http://dysmsapi.aliyuncs.com/")
response, err := smsClient.Execute(globals.AliKey, globals.AliSecret, mobileNumber, globals.SMSSignName, globals.SMSMobileVerifyTemplate, string(utils.MustMarshal(map[string]interface{}{
"code": verifyCode,
})))
a.SaveVerifyCode(mobileNumber, verifyCode)
if err == nil && response.Code == aliyunsmsclient.ResponseCodeOk {
// a.SaveVerifyCode(mobileNumber, verifyCode)
} else {
if err == nil {
if warningMap[response.Code] == 1 {
globals.SugarLogger.Warnf("SendVerifyCode mobileNumber:%s failed with response:%s", mobileNumber, utils.Format4Output(response, false))
} else {
globals.SugarLogger.Infof("SendVerifyCode mobileNumber:%s failed with response:%s", mobileNumber, utils.Format4Output(response, false))
}
err = fmt.Errorf("发送短信出错:%s", response.Message)
} else {
globals.SugarLogger.Warnf("SendVerifyCode mobileNumber:%s failed with error:%v", mobileNumber, err)
}
}
return verifyCode, err
}
func (a *Auther) VerifySecret(mobileNumber, code string) (authBindEx *auth2.AuthBindEx, err error) {
globals.SugarLogger.Debugf("VerifySecret mobileNumber:%s, code:%s", mobileNumber, code)
err = ErrVerifyCodeIsWrong
if (code == auth2.InternalAuthSecret ||
auth2.TestMobileMap[mobileNumber] == 1 && code == TestVerifyCode) ||
a.VerifyCode(mobileNumber, code) {
err = nil
}
return nil, err
}
// 此函数为空
func (a *Auther) AddAuthBind(authBindEx *auth2.AuthBindEx, userName string) (err error) {
return err
}
// 此函数为空
func (a *Auther) UnbindAuth(userID, authType, authTypeID, userName string) (err error) {
return err
}

View File

@@ -1,88 +0,0 @@
package password
import (
"crypto/sha1"
"errors"
"fmt"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/auth2"
"git.rosy.net.cn/jx-callback/business/auth2/authprovider"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/globals"
)
const (
AuthType = auth2.AuthTypePassword
)
type Auther struct {
authprovider.DefAuther
}
var (
AutherObj *Auther
)
var (
ErrUserAndPassNotMatch = errors.New("用户名密码不匹配")
)
func init() {
AutherObj = new(Auther)
auth2.RegisterAuther(AuthType, AutherObj)
}
func (a *Auther) VerifySecret(userID, passMD5 string) (authBindEx *auth2.AuthBindEx, err error) {
globals.SugarLogger.Debugf("localpass VerifySecret userID:%s", userID)
var authBind *model.AuthBind
if authBind, err = dao.GetAuthBind(dao.GetDB(), model.AuthBindTypeAuth, AuthType, userID); err == nil {
if err = a.checkPassword(authBind, passMD5); err == nil {
authBindEx = &auth2.AuthBindEx{
AuthBind: *authBind,
}
}
} else if dao.IsNoRowsError(err) {
err = auth2.ErrUserAuthTypeNotExist
}
return authBindEx, err
}
// 特殊接口
func (a *Auther) ChangePassword(userID, userName, oldPassMD5, newPassMD5 string) (err error) {
var authBind *model.AuthBind
db := dao.GetDB()
salt := utils.GetUUID()
encryptPwd := a.encryptPassword(newPassMD5, salt)
if authBind, err = dao.GetAuthBind(db, model.AuthBindTypeAuth, AuthType, userID); err == nil {
if err = a.checkPassword(authBind, oldPassMD5); err == nil || authBind.AuthSecret == "" { // 如果原密码为空,不判断原密码,代表重置密码
_, err = dao.UpdateEntityLogically(db, authBind, map[string]interface{}{
"AuthSecret": encryptPwd,
"AuthSecret2": salt,
}, userName, nil)
}
} else if dao.IsNoRowsError(err) {
err = a.AddAuthBind(&auth2.AuthBindEx{
AuthBind: model.AuthBind{
UserID: userID,
Type: AuthType,
AuthID: userID,
AuthSecret: encryptPwd,
AuthSecret2: salt,
},
}, userName)
}
return err
}
func (a *Auther) encryptPassword(password, salt string) string {
return fmt.Sprintf("%x", sha1.Sum([]byte(password+salt)))
}
func (a *Auther) checkPassword(authBind *model.AuthBind, passMD5 string) (err error) {
if authBind.AuthSecret != a.encryptPassword(passMD5, authBind.AuthSecret2) {
return ErrUserAndPassNotMatch
}
return nil
}

View File

@@ -1,105 +0,0 @@
package weixin
import (
"errors"
"git.rosy.net.cn/baseapi/platformapi/weixinapi"
"git.rosy.net.cn/jx-callback/business/auth2"
"git.rosy.net.cn/jx-callback/business/auth2/authprovider"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/globals/api"
)
const (
AuthTypeWeixin = "wxqrcode" // 微信扫码
AuthTypeMP = "weixinsns" // 公众号
AuthTypeWXNative = "wxnative" // 微信APP
AuthTypeWxApp = "weixinapp" //app微信登录
)
type Auther struct {
authprovider.DefAuther
authType string
}
var (
AutherObjWX *Auther
AutherObjMP *Auther
AutherObjNative *Auther
AutherObjApp *Auther
)
var (
ErrStateIsWrong = errors.New("登录state非法")
)
func init() {
AutherObjWX = &Auther{
authType: AuthTypeWeixin,
}
auth2.RegisterAuther(AuthTypeWeixin, AutherObjWX)
AutherObjMP = &Auther{
authType: AuthTypeMP,
}
auth2.RegisterAuther(AuthTypeMP, AutherObjMP)
AutherObjNative = &Auther{
authType: AuthTypeWXNative,
}
auth2.RegisterAuther(AuthTypeWXNative, AutherObjNative)
AutherObjApp = &Auther{
authType: AuthTypeWxApp,
}
auth2.RegisterAuther(AuthTypeWxApp, AutherObjApp)
}
func (a *Auther) VerifySecret(id, secret string) (authBindEx *auth2.AuthBindEx, err error) {
globals.SugarLogger.Debugf("weixin VerifySecret id:%s secret:%s", id, secret)
var openID, accessToken string
_, jsCode := SplitJsCode(secret)
if a.authType != AuthTypeWXNative {
state := id
code := jsCode
if state == "" {
token, err2 := a.getAPI().SNSRetrieveToken(code)
if err = err2; err == nil {
openID = token.OpenID
accessToken = token.AccessToken
}
} else {
err = ErrStateIsWrong
}
} else {
openID = id
accessToken = secret
}
if err == nil {
wxUserinfo, err2 := a.getAPI().SNSGetUserInfo(accessToken, openID)
if err = err2; err == nil {
if authBindEx, err = a.UnionFindAuthBind(a.authType, a.getAPI().GetAppID(), []string{AuthTypeWeixin, AuthTypeMP, AuthTypeMini, AuthTypeWXNative, AuthTypeWxApp}, wxUserinfo.OpenID, wxUserinfo.UnionID, wxUserinfo); err == nil {
authBindEx.UserHint = &auth2.UserBasic{
Name: wxUserinfo.NickName,
Avatar: wxUserinfo.HeadImgURL,
}
}
}
}
return authBindEx, err
}
func (a *Auther) getAPI() *weixinapi.API {
if a.authType == AuthTypeWeixin {
return api.WeixinPageAPI
}
if a.authType == AuthTypeWxApp {
return api.WeixinApp
}
return api.WeixinAPI
}
func (a *Auther) GetUserType() (userType int8) {
return model.UserTypeStoreBoss
}

View File

@@ -1,139 +0,0 @@
package weixin
import (
"errors"
"strings"
"git.rosy.net.cn/baseapi/platformapi/weixinapi"
"git.rosy.net.cn/jx-callback/business/auth2"
"git.rosy.net.cn/jx-callback/business/auth2/authprovider"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/globals/api"
)
const (
AuthTypeMini = "weixinmini" // 小程序
)
type MiniAuther struct {
authprovider.DefAuther
}
var (
ErrAuthTypeShouldBeMini = errors.New("当前操作要求是小程序登录方式")
)
var (
AutherObjMini *MiniAuther
)
func init() {
AutherObjMini = new(MiniAuther)
auth2.RegisterAuther(AuthTypeMini, AutherObjMini)
}
func (a *MiniAuther) VerifySecret(dummy, jsCode string) (authBindEx *auth2.AuthBindEx, err error) {
globals.SugarLogger.Debugf("weixin mini VerifySecret jsCode:%s", jsCode)
appID, jsCode := SplitJsCode(jsCode)
sessionInfo, err := getWxApp(appID).SNSCode2Session(jsCode)
if err == nil {
sessionKey := sessionInfo.SessionKey
sessionInfo.SessionKey = ""
if authBindEx, err = a.UnionFindAuthBind(AuthTypeMini, getWxApp(appID).GetAppID(), []string{AuthTypeWeixin, AuthTypeMP, AuthTypeMini, AuthTypeWXNative}, sessionInfo.OpenID, sessionInfo.UnionID, sessionInfo); err == nil {
authBindEx.UserData = sessionKey
}
}
return authBindEx, err
}
// 特殊接口
func (a *MiniAuther) DecryptData(authInfo *auth2.AuthInfo, jsCode, encryptedData, iv string) (decryptedDataBase64 string, err error) {
globals.SugarLogger.Debugf("weixin mini DecryptData jsCode:%s, encryptedData:%s, iv:%s", jsCode, encryptedData, iv)
var sessionKey string
appID, jsCode := SplitJsCode(jsCode)
if jsCode != "" {
sessionInfo, err := getWxApp(appID).SNSCode2Session(jsCode)
if err == nil {
// if authBindEx, err := a.UnionFindAuthBind(AuthTypeMini, getWxApp(appID).GetAppID(), []string{AuthTypeMini}, sessionInfo.OpenID, "", nil); err == nil {
// if authBindEx.UserID != authInfo.GetID() {
// return "", fmt.Errorf("jsCode与token不匹配")
// }
// } else {
// return "", err
// }
sessionKey = sessionInfo.SessionKey
} else {
return "", err
}
} else {
if authInfo.AuthBindInfo.Type != AuthTypeMini {
// return "", ErrAuthTypeShouldBeMini
}
sessionKey = authInfo.AuthBindInfo.UserData.(string)
}
// decryptedData, err := ProxySNSDecodeMiniProgramData(encryptedData, sessionKey, iv)
decryptedData, err := weixinapi.SNSDecodeMiniProgramData(encryptedData, sessionKey, iv)
if err != nil {
return "", err
}
// authInfo.AuthBindInfo.UserData = sessionKey
return string(decryptedData), nil
}
func (a *MiniAuther) GetUserType() (userType int8) {
return model.UserTypeStoreBoss
}
func getWxApp(appID string) (miniApi *weixinapi.API) {
miniApi = api.WeixinMiniAPI
if len(appID) > 0 && appID == api.WeixinMiniAppID2 {
miniApi = api.WeixinMiniAPI2
}
if len(appID) > 0 && appID == api.WeixinMiniAppIDsc {
miniApi = api.WeixinMiniAPIsc
}
return miniApi
}
func SplitJsCode(jsCode string) (appID, realJsCode string) {
list := strings.Split(jsCode, ",")
if len(list) == 2 {
appID = list[0]
realJsCode = list[1]
} else if len(list) == 1 {
realJsCode = jsCode
} else {
globals.SugarLogger.Warnf("SplitJsCode abnormal jsCode:%s", jsCode)
}
return appID, realJsCode
}
func ComposeJsCode(appID, jsCode string) (composedCode string) {
composedCode = strings.Join([]string{
appID,
jsCode,
}, ",")
return composedCode
}
// func ProxySNSCode2Session(jsCode string) (sessionInfo *weixinapi.SessionInfo, err error) {
// miniApi := api.WeixinMiniAPI
// list := strings.Split(jsCode, ",")
// if len(list) >= 2 && len(list[0]) == len("wx4b5930c13f8b1170") {
// if list[0] == api.WeixinMiniAppID2 {
// miniApi = api.WeixinMiniAPI2
// }
// miniApi = getWxApp(list[0])
// jsCode = strings.Join(list[1:], ",")
// }
// sessionInfo, err = miniApi.SNSCode2Session(jsCode)
// return sessionInfo, err
// }
// func ProxySNSDecodeMiniProgramData(encryptedData, sessionKey, iv string) (decryptedData []byte, err error) {
// globals.SugarLogger.Debugf("ProxySNSDecodeMiniProgramData, encryptedData:%s, sessionKey:%s, iv:%s", encryptedData, sessionKey, iv)
// decryptedData, err = api.WeixinMiniAPI.SNSDecodeMiniProgramData(encryptedData, sessionKey, iv)
// return decryptedData, err
// }

View File

@@ -6,8 +6,8 @@ import (
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/authz"
"git.rosy.net.cn/jx-callback/business/dao"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
)
func GetRoleDescription(name string, storeID int) (description string) {

View File

@@ -1,171 +0,0 @@
package casbinauth
import (
jxmodel "git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/globals"
"github.com/astaxie/beego/client/orm"
"github.com/casbin/casbin/model"
"github.com/casbin/casbin/persist"
)
type Adapter struct {
}
// finalizer is the destructor for Adapter.
func finalizer(a *Adapter) {
}
func NewAdapter() *Adapter {
return &Adapter{}
}
func loadPolicyLine(line jxmodel.CasbinRule, model model.Model) {
lineText := line.PType
if line.V0 != "" {
lineText += ", " + line.V0
}
if line.V1 != "" {
lineText += ", " + line.V1
}
if line.V2 != "" {
lineText += ", " + line.V2
}
if line.V3 != "" {
lineText += ", " + line.V3
}
if line.V4 != "" {
lineText += ", " + line.V4
}
if line.V5 != "" {
lineText += ", " + line.V5
}
persist.LoadPolicyLine(lineText, model)
}
func (a *Adapter) LoadPolicy(model model.Model) error {
var lines []jxmodel.CasbinRule
o := orm.NewOrm()
_, err := o.QueryTable("casbin_rule").Limit(-1).All(&lines)
if err != nil {
return err
}
for _, line := range lines {
loadPolicyLine(line, model)
}
return nil
}
func savePolicyLine(ptype string, rule []string) jxmodel.CasbinRule {
line := jxmodel.CasbinRule{}
line.PType = ptype
if len(rule) > 0 {
line.V0 = rule[0]
}
if len(rule) > 1 {
line.V1 = rule[1]
}
if len(rule) > 2 {
line.V2 = rule[2]
}
if len(rule) > 3 {
line.V3 = rule[3]
}
if len(rule) > 4 {
line.V4 = rule[4]
}
if len(rule) > 5 {
line.V5 = rule[5]
}
return line
}
func (a *Adapter) clearAll(o orm.Ormer) (err error) {
_, err = o.Raw(`
DELETE t1
FROM casbin_rule t1
`).Exec()
return err
}
// SavePolicy saves policy to database.
func (a *Adapter) SavePolicy(model model.Model) error {
globals.SugarLogger.Debugf("SavePolicy")
o := orm.NewOrm()
a.clearAll(o)
var lines []jxmodel.CasbinRule
for ptype, ast := range model["p"] {
for _, rule := range ast.Policy {
line := savePolicyLine(ptype, rule)
lines = append(lines, line)
}
}
for ptype, ast := range model["g"] {
for _, rule := range ast.Policy {
line := savePolicyLine(ptype, rule)
lines = append(lines, line)
}
}
_, err := o.InsertMulti(len(lines), lines)
return err
}
// AddPolicy adds a policy rule to the storage.
func (a *Adapter) AddPolicy(sec string, ptype string, rule []string) error {
o := orm.NewOrm()
line := savePolicyLine(ptype, rule)
_, err := o.Insert(&line)
return err
}
// RemovePolicy removes a policy rule from the storage.
func (a *Adapter) RemovePolicy(sec string, ptype string, rule []string) error {
o := orm.NewOrm()
line := savePolicyLine(ptype, rule)
_, err := o.Delete(&line, "p_type", "v0", "v1", "v2", "v3", "v4", "v5")
return err
}
// RemoveFilteredPolicy removes policy rules that match the filter from the storage.
func (a *Adapter) RemoveFilteredPolicy(sec string, ptype string, fieldIndex int, fieldValues ...string) error {
line := jxmodel.CasbinRule{}
line.PType = ptype
filter := []string{}
filter = append(filter, "p_type")
if fieldIndex <= 0 && 0 < fieldIndex+len(fieldValues) {
line.V0 = fieldValues[0-fieldIndex]
filter = append(filter, "v0")
}
if fieldIndex <= 1 && 1 < fieldIndex+len(fieldValues) {
line.V1 = fieldValues[1-fieldIndex]
filter = append(filter, "v1")
}
if fieldIndex <= 2 && 2 < fieldIndex+len(fieldValues) {
line.V2 = fieldValues[2-fieldIndex]
filter = append(filter, "v2")
}
if fieldIndex <= 3 && 3 < fieldIndex+len(fieldValues) {
line.V3 = fieldValues[3-fieldIndex]
filter = append(filter, "v3")
}
if fieldIndex <= 4 && 4 < fieldIndex+len(fieldValues) {
line.V4 = fieldValues[4-fieldIndex]
filter = append(filter, "v4")
}
if fieldIndex <= 5 && 5 < fieldIndex+len(fieldValues) {
line.V5 = fieldValues[5-fieldIndex]
filter = append(filter, "v5")
}
o := orm.NewOrm()
_, err := o.Delete(&line, filter...)
return err
}

View File

@@ -1,49 +0,0 @@
package casbinauth
import (
"git.rosy.net.cn/jx-callback/business/authz"
"git.rosy.net.cn/jx-callback/business/authz/autils"
"github.com/casbin/casbin"
"github.com/casbin/casbin/errors"
)
type CasbinAuthz struct {
enforcer *casbin.SyncedEnforcer
}
func New(modelFile string) (authObj authz.IAuthz, err error) {
obj := &CasbinAuthz{}
obj.enforcer, err = casbin.NewSyncedEnforcer(modelFile, NewAdapter())
return obj, err
}
func (c *CasbinAuthz) AddRole4User(userID string, r *authz.RoleInfo) (err error) {
_, err = c.enforcer.AddRoleForUser(userID, r.GetFullName())
return err
}
func (c *CasbinAuthz) DeleteRole4User(userID string, r *authz.RoleInfo) (err error) {
_, err = c.enforcer.DeleteRoleForUser(userID, r.GetFullName())
return err
}
func (c *CasbinAuthz) GetUserRoleList(userID string) (roleList []*authz.RoleInfo, err error) {
roleNameList, err := c.enforcer.GetRolesForUser(userID)
if err == nil && len(roleNameList) > 0 {
roleList = autils.FullRoleName2RoleList(roleNameList)
}
return roleList, err
}
func (c *CasbinAuthz) GetRoleUserList(r *authz.RoleInfo) (userIDList []string, err error) {
// globals.SugarLogger.Debug(roleFullName)
userIDList, err = c.enforcer.GetUsersForRole(r.GetFullName())
if err == errors.ERR_NAME_NOT_FOUND {
err = nil
}
return userIDList, err
}
// func (c *CasbinAuthz) GetAllRoleList() (roleList []*authz.RoleInfo) {
// return authz.FullRoleName2RoleList(c.enforcer.GetAllRoles())
// }

View File

@@ -1,128 +0,0 @@
package cs
import (
"git.rosy.net.cn/baseapi/platformapi/weimobapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/authz/autils"
"git.rosy.net.cn/jx-callback/business/jxstore/cms"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/globals/api"
)
const (
minCSOrderPayment = 0 // 供货订单的最小金额(单位为元)
maxUnitPrice = 3000 // 为防止误填单价,限制单价最高(单位为分)
)
func OnCallbackMsg(msg *weimobapi.CallbackMsg) (response *weimobapi.CallbackResponse) {
orderID := utils.Int64ToStr(msg.OrderNo)
jxutils.CallMsgHandler(func() {
response = onOrderMsg(msg)
}, jxutils.ComposeUniversalOrderID(orderID, model.VendorIDWSC))
return response
}
func onOrderMsg(msg *weimobapi.CallbackMsg) (response *weimobapi.CallbackResponse) {
globals.SugarLogger.Debugf("onOrderMsg:%s", utils.Format4Output(msg, true))
if msg.Event == weimobapi.MsgEventOrderStatusChange {
if utils.ForceInterface2Int64(msg.MsgBody["orderStatus"]) == weimobapi.MsgOrderStatusFinished {
if orderDetail, err := api.WeimobAPI.QueryOrderDetail2(msg.OrderNo, false); err == nil {
if orderDetail.OrderStatus == weimobapi.OrderStatusFinished && orderDetail.PaymentAmount >= minCSOrderPayment {
changeStoreSkusByOrder(orderDetail)
}
} else {
globals.SugarLogger.Debugf("onOrderMsg order:%s failed with err:%v", msg.OrderNo, err)
response = weimobapi.Err2CallbackResponse(err, "")
}
}
}
return response
}
func changeStoreSkusByOrder(order *weimobapi.OrderDetail) {
globals.SugarLogger.Debugf("changeStoreSkusByOrder order:%s", utils.Format4Output(order, true))
receiverMobile := order.DeliveryDetail.LogisticsDeliveryDetail.ReceiverMobile
ctx := jxcontext.NewWithUserName(nil, utils.LimitStringLen(utils.Int64ToStr(order.OrderNo), 32), nil, nil)
if storeList, err := GetStoreList4Mobile(dao.GetDB(), []string{receiverMobile}); err == nil {
if len(storeList) >= 1 {
var skuBindInfos []*cms.StoreSkuBindInfo
storeID := storeList[0].ID
globals.SugarLogger.Debugf("changeStoreSkusByOrder storeID:%d", storeID)
for _, v := range order.ItemList {
nameID := int(utils.Str2Int64WithDefault(v.SkuCode, 0))
unitPrice := v.CostPrice
if nameID > 0 && (unitPrice > 0 && unitPrice < maxUnitPrice) {
skuBindInfos = append(skuBindInfos, &cms.StoreSkuBindInfo{
StoreID: storeID,
NameID: nameID,
UnitPrice: int(jxutils.StandardPrice2Int(unitPrice)),
IsFocus: 1,
IsSale: 1,
})
} else {
globals.SugarLogger.Infof("[运营],微商城订单:%d商品:%s没有设置正确的SkuName编码或单价当前商家编码:%s市场价:%s", order.OrderNo, v.SkuNum, v.SkuCode, jxutils.IntPrice2StandardString(jxutils.StandardPrice2Int(unitPrice)))
}
}
if len(skuBindInfos) > 0 {
var nameIDs []int
for _, v := range skuBindInfos {
nameIDs = append(nameIDs, v.NameID)
}
if skuNamesInfo, err := cms.GetSkuNames(ctx, "", false, false, map[string]interface{}{
"nameIDs": string(utils.MustMarshal(nameIDs)),
}, 0, 0); err == nil {
for _, skuName := range skuNamesInfo.SkuNames {
if skuName.Status != model.SkuStatusNormal {
cms.UpdateSkuName(ctx, skuName.ID, map[string]interface{}{
"status": model.SkuStatusNormal,
}, false)
}
for _, sku := range skuName.Skus {
if sku.Status != model.SkuStatusNormal {
cms.UpdateSku(ctx, sku.ID, map[string]interface{}{
"status": model.SkuStatusNormal,
})
}
}
}
}
cms.UpdateStoreSkus(ctx, 0, storeID, skuBindInfos, true, true)
} else {
globals.SugarLogger.Debugf("changeStoreSkusByOrder orderID:%d, storeID:%d is empty", order.OrderNo, storeID)
}
} else {
globals.SugarLogger.Infof("[运营],微商城订单:%d手机:%s找不到唯一一个本地门店%d", order.OrderNo, receiverMobile, len(storeList))
}
} else {
globals.SugarLogger.Warnf("changeStoreSkusByOrder orderNo:%d, receiverMobile:%s failed with err:%v", order.OrderNo, receiverMobile, err)
}
}
func GetStoreList4Mobile(db *dao.DaoDB, mobileList []string) (storeList []*model.Store, err error) {
sql := `
SELECT t1.*
FROM store t1
WHERE t1.deleted_at = ? /*AND t1.change_price_type = ?*/`
sqlParams := []interface{}{
utils.DefaultTimeValue,
// model.StoreChangePriceTypeBossDisabled,
}
if len(mobileList) > 0 {
questionMarks := dao.GenQuestionMarks(len(mobileList))
sql += " AND (t1.tel1 IN (" + questionMarks + ") OR t1.tel2 IN (" + questionMarks + `)
OR (SELECT
COUNT(*)
FROM casbin_rule t2
JOIN user t3 ON t3.user_id = t2.v0 AND t3.mobile IN (` + questionMarks + `)
WHERE t2.v1 = CONCAT(?, t1.id)
) > 0)
`
sqlParams = append(sqlParams, mobileList, mobileList, mobileList, autils.NewStoreBossRole(-1).GetFullName())
}
err = dao.GetRows(db, &storeList, sql, sqlParams...)
return storeList, err
}

View File

@@ -1,24 +0,0 @@
package cs
import (
"testing"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/globals/api2"
"git.rosy.net.cn/jx-callback/globals/testinit"
)
func init() {
testinit.Init()
api2.Init()
}
func TestGetStoreList4Mobile(t *testing.T) {
storeList, err := GetStoreList4Mobile(dao.GetDB(), []string{"18180948107"})
if err != nil {
t.Fatal(err)
}
t.Log(utils.Format4Output(storeList, false))
t.Log(len(storeList))
}

32
business/dao/common.go Normal file
View File

@@ -0,0 +1,32 @@
package dao
import (
"git.rosy.net.cn/jx-callback/business/model"
)
func GetDataResource(db *DaoDB, hashCode, fullURL string) (dataRes *model.DataResource, err error) {
sql := `
SELECT t1.*
FROM data_resource t1
WHERE 0 = 1`
sqlParams := []interface{}{}
if hashCode != "" {
sql += " OR t1.hash_code = ?"
sqlParams = append(sqlParams, hashCode)
}
if fullURL != "" {
sql += " OR t1.main_url = ? OR t1.qiniu_url = ? OR t1.ebai_url = ? OR t1.mtwm_url = ?"
sqlParams = append(sqlParams, fullURL, fullURL, fullURL, fullURL)
}
err = GetRow(db, &dataRes, sql, sqlParams...)
return dataRes, err
}
func GetNeedUploadDataResource(db *DaoDB) (dataResList []*model.DataResource, err error) {
sql := `
SELECT t1.*
FROM data_resource t1
WHERE t1.use_type <> 0 AND (t1.ebai_url = '' OR t1.mtwm_url = '')`
err = GetRows(db, &dataResList, sql)
return dataResList, err
}

View File

@@ -97,7 +97,7 @@ func Commit(db *DaoDB, txDB orm.TxOrmer) (err error) {
if db.transactionLevel == 1 {
db.stopWatchTransaction()
err = txDB.Commit()
// err = db.Db.Commit()
//err = db.Db.Commit()
db.transactionLevel = 0
} else if db.transactionLevel > 1 {
db.transactionLevel--
@@ -109,7 +109,7 @@ func Rollback(db *DaoDB, txDB orm.TxOrmer) (err error) {
if db.transactionLevel > 0 {
db.stopWatchTransaction()
err = txDB.Rollback()
// err = db.Db.Rollback()
//err = db.Db.Rollback()
}
db.transactionLevel = 0
return err
@@ -143,17 +143,22 @@ func GetRowTx(txDB orm.TxOrmer, inPtr interface{}, sql string, values ...interfa
if txDB == nil {
return
}
typeInfo := reflect.TypeOf(inPtr)
if typeInfo.Kind() != reflect.Ptr {
return errors.New("inPtr must be ptr")
}
slice := reflect.New(reflect.SliceOf(typeInfo.Elem()))
if err = GetRowsTx(txDB, slice.Interface(), sql, values...); err == nil {
slice = slice.Elem()
if slice.Len() > 0 {
reflect.ValueOf(inPtr).Elem().Set(slice.Index(0))
} else {
return orm.ErrNoRows
if !useGetRowsWhenGetRow { // beego QueryRow有bug嵌入的struct不能正常绑定
err = txDB.Raw(sql, values).QueryRow(inPtr)
//err = db.Db.Raw(sql, values).QueryRow(inPtr)
} else {
typeInfo := reflect.TypeOf(inPtr)
if typeInfo.Kind() != reflect.Ptr {
return errors.New("inPtr must be ptr")
}
slice := reflect.New(reflect.SliceOf(typeInfo.Elem()))
if err = GetRowsTx(txDB, slice.Interface(), sql, values...); err == nil {
slice = slice.Elem()
if slice.Len() > 0 {
reflect.ValueOf(inPtr).Elem().Set(slice.Index(0))
} else {
return orm.ErrNoRows
}
}
}
return err
@@ -172,7 +177,7 @@ func GetRowsTx(txDB orm.TxOrmer, inPtr interface{}, sql string, values ...interf
return
}
_, err = txDB.Raw(sql, values).QueryRows(inPtr)
// _, err = db.Db.Raw(sql, values).QueryRows(inPtr)
//_, err = db.Db.Raw(sql, values).QueryRows(inPtr)
return err
}
@@ -197,6 +202,16 @@ func UpdateEntity(db *DaoDB, item interface{}, cols ...string) (num int64, err e
return num, err
}
func CreateEntity(db *DaoDB, item interface{}) (err error) {
if db == nil {
db = GetDB()
}
if _, err = db.Db.Insert(item); err != nil && !IsDuplicateError(err) {
globals.SugarLogger.Errorf("CreateEntity %s failed with error:%v", reflect.TypeOf(item).Name(), err)
}
return err
}
func UpdateEntityTx(txDB orm.TxOrmer, item interface{}, cols ...string) (num int64, err error) {
if txDB == nil {
return
@@ -208,16 +223,6 @@ func UpdateEntityTx(txDB orm.TxOrmer, item interface{}, cols ...string) (num int
return num, err
}
func CreateEntity(db *DaoDB, item interface{}) (err error) {
if db == nil {
db = GetDB()
}
if _, err = db.Db.Insert(item); err != nil && !IsDuplicateError(err) {
globals.SugarLogger.Errorf("CreateEntity %s failed with error:%v", reflect.TypeOf(item).Name(), err)
}
return err
}
func CreateEntityTx(txDB orm.TxOrmer, item interface{}) (err error) {
if txDB == nil {
return
@@ -258,6 +263,18 @@ func DeleteEntity(db *DaoDB, item interface{}, cols ...string) (num int64, err e
return num, err
}
func DeleteEntityTx(txDB orm.TxOrmer, item interface{}, cols ...string) (num int64, err error) {
if txDB == nil {
return
}
err = utils.CallFuncLogError(func() error {
num, err = txDB.Delete(item, cols...)
//num, err = db.Db.Delete(item, cols...)
return err
}, reflect.TypeOf(item).Name())
return num, err
}
func ExecuteSQL(db *DaoDB, sql string, params ...interface{}) (num int64, err error) {
if db == nil {
db = GetDB()
@@ -275,16 +292,13 @@ func ExecuteSQL(db *DaoDB, sql string, params ...interface{}) (num int64, err er
// 此函数要求db在事务中否则可能导致取得到的是另一个连接的数据
func GetLastTotalRowCount(db *DaoDB) int {
countInfo := &struct{ Ct int }{}
// if err := txDB.Raw("SELECT FOUND_ROWS() ct", nil).QueryRow(countInfo); err == nil {
// return countInfo.Ct
// }
if err := GetRow(db, countInfo, "SELECT FOUND_ROWS() ct"); err == nil {
return countInfo.Ct
}
return 0
}
func GetLastTotalRowCount2(db *DaoDB, txDB orm.TxOrmer) int {
func GetLastTotalRowCountTx(txDB orm.TxOrmer) int {
countInfo := &struct{ Ct int }{}
if err := GetRowTx(txDB, countInfo, "SELECT FOUND_ROWS() ct"); err == nil {
return countInfo.Ct

View File

@@ -27,7 +27,7 @@ func GetAuthBind(db *DaoDB, bindType int, authType, authID string) (authBind *mo
return authBind, err
}
func GetUserBindAuthInfo(db *DaoDB, userID string, bindType int, typeList []string, authID, authID2 string, typeIDs []string) (authList []*model.AuthBind, err error) {
func GetUserBindAuthInfo(db *DaoDB, userID string, bindType int, typeList []string, authID, authID2, typeID string) (authList []*model.AuthBind, err error) {
sql := `
SELECT *
FROM auth_bind t1
@@ -56,9 +56,9 @@ func GetUserBindAuthInfo(db *DaoDB, userID string, bindType int, typeList []stri
sql += " AND t1.auth_id2 = ?"
sqlParams = append(sqlParams, authID2)
}
if len(typeIDs) > 0 {
sql += " AND t1.type_id IN (" + GenQuestionMarks(len(typeIDs)) + ")"
sqlParams = append(sqlParams, typeIDs)
if typeID != "" {
sql += " AND t1.type_id = ?"
sqlParams = append(sqlParams, typeID)
}
sql += " ORDER BY t1.type"
err = GetRows(db, &authList, sql, sqlParams...)

91
business/dao/dao_print.go Normal file
View File

@@ -0,0 +1,91 @@
package dao
import (
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/globals"
)
// QueryUserPrinter 查询用户打印机
func QueryUserPrinter(userId, printNo string) (*model.Printer, error) {
sql := `
SELECT *
FROM printer
WHERE 1 = 1 AND deleted_at = ?
`
sqlParams := []interface{}{
utils.DefaultTimeValue,
}
if printNo != "" {
sql += " AND print_no = ?"
sqlParams = append(sqlParams, printNo)
}
if userId != "" {
sql += " AND user_id = ?"
sqlParams = append(sqlParams, userId)
}
var printer = &model.Printer{}
err := GetRow(GetDB(), &printer, sql, sqlParams)
return printer, err
}
func GetPrinters(db *DaoDB, appID int, printNo string, status, statusNeq int) (printers []*model.Printer, err error) {
sql := `
SELECT *
FROM printer
WHERE 1 = 1 AND deleted_at = ?
`
sqlParams := []interface{}{
utils.DefaultTimeValue,
}
if appID != 0 {
sql += " AND app_id = ?"
sqlParams = append(sqlParams, appID)
}
if printNo != "" {
sql += " AND print_no = ?"
sqlParams = append(sqlParams, printNo)
}
if status != 0 {
sql += " AND status = ?"
sqlParams = append(sqlParams, status)
}
if statusNeq != 0 {
sql += " AND status <> ?"
sqlParams = append(sqlParams, statusNeq)
}
err = GetRows(db, &printers, sql, sqlParams)
globals.SugarLogger.Debugf("======printers==== %s", utils.Format4Output(printers, false))
return printers, err
}
func GetPrintMsgs(db *DaoDB, printNo, msgID string, status, statusNeq int) (printMsgs []*model.PrintMsg, err error) {
sql := `
SELECT *
FROM print_msg
WHERE 1 = 1 AND deleted_at = ?
`
sqlParams := []interface{}{
utils.DefaultTimeValue,
}
if status != model.PrintMsgAll {
sql += " AND status = ?"
sqlParams = append(sqlParams, status)
}
if statusNeq != model.PrintMsgAll {
sql += " AND status <> ?"
sqlParams = append(sqlParams, statusNeq)
}
if printNo != "" {
sql += " AND print_no = ?"
sqlParams = append(sqlParams, printNo)
}
if msgID != "" {
sql += " AND msg_id = ?"
sqlParams = append(sqlParams, msgID)
}
err = GetRows(db, &printMsgs, sql, sqlParams)
return printMsgs, err
}

View File

@@ -0,0 +1,25 @@
package dao
import (
"errors"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/model"
)
func GetPrintSetting(printNo string) (*model.PrintSettingObj, error) {
sql := ` SELECT * FROM print_setting WHERE print_no = ? and deleted_at = ? `
sqlParams := []interface{}{
printNo,
utils.DefaultTimeValue,
}
var printSetting *model.PrintSetting
if err := GetRow(GetDB(), &printSetting, sql, sqlParams...); err != nil {
return nil, err
}
if printSetting == nil {
return nil, errors.New("数据查询异常")
}
return model.UnMarshalString2Json(printSetting)
}

View File

@@ -0,0 +1,36 @@
package dao
import (
"errors"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/globals"
)
// SelectUserDefaultTemp 查询用户默认模板
func SelectUserDefaultTemp(userId string, tempType string) (*model.SystemTemp, bool, error) {
var result *model.SystemTemp
if err := GetRow(GetDB(), &result, `SELECT * FROM system_temp WHERE user_id = ? AND temp_type = ? AND is_use = ? AND deleted_at = ? ORDER BY created_at desc `, []interface{}{userId, tempType, 1, utils.DefaultTimeValue}...); err != nil {
return nil, false, err
}
return result, true, nil
}
// QuerySystemTemp 查询系统模板
func QuerySystemTemp() (*model.SystemTemp, error) {
var result []*model.SystemTemp
if err := GetRows(GetDB(), &result, `SELECT * FROM system_temp WHERE user_id = ? AND temp_type = ? AND is_use = ? AND deleted_at = ? ORDER BY created_at desc `, []interface{}{"system_user", "user_store", 1, utils.DefaultTimeValue}...); err != nil {
return nil, err
}
if len(result) > 0 {
return result[0], nil
}
globals.SugarLogger.Debugf("========模板获取异常")
return nil, errors.New("模板获取异常")
}
// AddTemp 添加模板数据
func AddTemp(param *model.SystemTemp) error {
return CreateEntity(GetDB(), param)
}

View File

@@ -0,0 +1,19 @@
package dao
import (
"encoding/json"
"git.rosy.net.cn/baseapi/utils"
"testing"
)
func TestGetUsers(t *testing.T) {
aa := "{\"title\":\"<center><b>京西菜市</b></center><br><center>手机买菜上京西</center><br><center>极速到家送惊喜</center><br>--------------------------------<br>\",\"divider\":\"--------------------------------<br>\",\"payOrderTime\":\"<left>下单时间:%s</left>\",\"trySendTime\":\"<left>预计送达时间:%s</left>\",\"consigneeName\":\"<left>客户名称:%s</left>\",\"consigneeMobile\":\"<left>客户电话:%s</left>\",\"consigneeAddress\":\"<left>客户地址:%s</left>\",\"buyerComment\":\"<left>客户备注:%s</left>\",\"qrcOrder\":\"<qrl>%s</qrl>\",\"goodsListDetail\":\"商品列表:<br>品名 数量 单价 小计<br>--------------------------------<br>\",\"skuName\":\"<b>%s</b><br>\",\"skuNumber\":\"<b>x%s</b>\",\"skuPrice\":\"<b>¥%s</b>\",\"skuAllPrice\":\"<b>¥%s</b>\",\"skuUpc\":\"upc码 %s<br>\",\"allSkuTypeCount\":\"<br><br><b>共 %s 种\",\"allSkuCount\":\" %s 件商品</b><br>\",\"storeName\":\"<center><b>商品质量问题请联系:</b></center><br><center><b>%s:\",\"storeTel\":\"%s</b></center><br><br>更多信息请关注官方微信:\",\"officialName\":\"<b>%s</b><br><br><br>--------------------------------<br>--------------------------------<br><br>\"}"
conte := make(map[string]string, 0)
if err := json.Unmarshal([]byte(aa), &conte); err != nil {
t.Fatal(err)
}
t.Log(utils.Format4Output(conte, false))
}

View File

@@ -111,7 +111,7 @@ func GetOperateEvents(db *DaoDB, name string, apiFunctions []string, operateType
txDB, _ := Begin(db)
defer Commit(db, txDB)
if err = GetRowsTx(txDB, &operateEventExt, sql, sqlParams...); err == nil {
totalCount = GetLastTotalRowCount2(db, txDB)
totalCount = GetLastTotalRowCountTx(txDB)
}
var (
accessUUidList []string
@@ -142,31 +142,131 @@ func GetOperateEvents(db *DaoDB, name string, apiFunctions []string, operateType
return operateEventExt, totalCount, err
}
func GetImMessageRecord(db *DaoDB, vendorOrderID, userID string, storeID, vendorID int) (msg []*model.ImMessageRecord, err error) {
type GetMessageGroupsResult struct {
model.MessageGroup
Avatar string `json:"avatar"`
LastMessageType int `json:"lastMessageType"`
LastContent string `json:"lastContent"`
LastTime time.Time `json:"lastTime"`
LastUserName string `json:"lastUserName"`
UserName string `json:"userName"`
UnReadMessageCount int `json:"unReadMessageCount"`
MessageGroupMembers []*GetMessageGroupsMemberResult `json:"messageGroupMembers"`
}
type GetMessageGroupsMemberResult struct {
model.User
model.MessageGroupMember
}
func GetMessageGroups(db *DaoDB, userID string, groupID, groupType int, isMember bool, userID2 string) (messageGroupsResult []*GetMessageGroupsResult, err error) {
sql := `
SELECT *
FROM im_message_record
WHERE deleted_at = ?
SELECT a.*, b.name user_name, b.avatar
FROM message_group a
LEFT JOIN user b ON b.user_id = a.user_id
WHERE a.deleted_at = ?
`
sqlParams := []interface{}{
utils.DefaultTimeValue,
}
if vendorOrderID != "" {
sql += " AND vendor_order_id = ?"
sqlParams = append(sqlParams, vendorOrderID)
}
sqlParams := []interface{}{utils.DefaultTimeValue}
if userID != "" {
sql += " AND user_id = ?"
sql += " AND a.user_id = ?"
sqlParams = append(sqlParams, userID)
}
if storeID != 0 {
sql += " AND store_id = ?"
sqlParams = append(sqlParams, storeID)
if groupType != 0 {
sql += " AND a.type = ?"
sqlParams = append(sqlParams, groupType)
}
if vendorID >= 0 {
sql += " AND vendor_id = ?"
sqlParams = append(sqlParams, vendorID)
if groupID != 0 {
sql += " AND a.group_id LIKE ?"
sqlParams = append(sqlParams, utils.Int2Str(groupID)+"%")
}
err = GetRows(db, &msg, sql, sqlParams)
return msg, err
if err = GetRows(db, &messageGroupsResult, sql, sqlParams); err == nil {
if isMember {
for _, v := range messageGroupsResult {
var messageGroupMembers []*GetMessageGroupsMemberResult
sql2 := `
SELECT a.*, b.*
FROM message_group_member a
LEFT JOIN user b ON b.user_id = a.member_user_id
WHERE a.group_id = ?
AND a.deleted_at = ?
`
sqlParams2 := []interface{}{v.GroupID, utils.DefaultTimeValue}
if userID2 != "" {
sql2 += ` AND member_user_id = ?`
sqlParams2 = append(sqlParams2, userID2)
}
if err = GetRows(db, &messageGroupMembers, sql2, sqlParams2); err == nil {
v.MessageGroupMembers = messageGroupMembers
}
}
}
}
return messageGroupsResult, err
}
func GetMessageGroupMembers(db *DaoDB, groupID, groupType int, memberUserID string) (messageGroupMembers []*model.MessageGroupMember, err error) {
sqlParams := []interface{}{}
sql := `
SELECT a.*
FROM message_group_member a
`
if groupType != 0 {
sql += ` JOIN message_group b ON b.group_id = a.group_id AND b.type = ? AND b.deleted_at = ?`
sqlParams = append(sqlParams, groupType, utils.DefaultTimeValue)
}
sql += `
WHERE a.deleted_at = ?
`
sqlParams = append(sqlParams, utils.DefaultTimeValue)
if groupID != 0 {
sql += " AND a.group_id = ?"
sqlParams = append(sqlParams, groupID)
}
if memberUserID != "" {
sql += " AND a.member_user_id = ?"
sqlParams = append(sqlParams, memberUserID)
}
err = GetRows(db, &messageGroupMembers, sql, sqlParams)
return messageGroupMembers, err
}
//得到某个用户所在所有群组
func GetUserMessageGroups(db *DaoDB, userID string) (messageGroup []*model.MessageGroup, err error) {
sql := `
SELECT group_id
FROM message_group
WHERE deleted_at = ? AND user_id = ?
UNION
SELECT group_id
FROM message_group_member
WHERE deleted_at = ? AND member_user_id = ?
`
sqlParams := []interface{}{
utils.DefaultTimeValue, userID,
utils.DefaultTimeValue, userID,
}
err = GetRows(db, &messageGroup, sql, sqlParams)
messageGroup = append(messageGroup, &model.MessageGroup{
GroupID: model.SysGroupID,
})
return messageGroup, err
}
func GetMessageGroupRead(db *DaoDB, userID string, groupID int) (messageGroupReads []*model.MessageGroupRead, err error) {
sql := `
SELECT *
FROM message_group_read a
WHERE 1 = 1
`
sqlParams := []interface{}{}
if userID != "" {
sql += ` AND a.user_id = ?`
sqlParams = append(sqlParams, userID)
}
if groupID != 0 {
sql += ` AND a.group_id = ?`
sqlParams = append(sqlParams, groupID)
}
err = GetRows(db, &messageGroupReads, sql, sqlParams...)
return messageGroupReads, err
}

View File

@@ -63,40 +63,3 @@ func GetPlaceByName(db *DaoDB, name string, level int, parentCode int) (place *m
}
return place, err
}
func GetPlaceByJdCode(db *DaoDB, jdCode int) (place *model.Place, err error) {
if db == nil {
db = GetDB()
}
place = &model.Place{
JdCode: jdCode,
}
err = db.Db.Read(place, "JdCode")
return place, err
}
func GetPlaceByJdsCode(db *DaoDB, jdsCode int) (place *model.Place, err error) {
if db == nil {
db = GetDB()
}
place = &model.Place{
JdsCode: jdsCode,
}
err = db.Db.Read(place, "JdsCode")
return place, err
}
func GetPlaces(db *DaoDB, cityCodes []int) (places []*model.Place, err error) {
sql := `
SELECT *
FROM place
WHERE 1 = 1
`
sqlParams := []interface{}{}
if len(cityCodes) > 0 {
sql += " AND code IN (" + GenQuestionMarks(len(cityCodes)) + ")"
sqlParams = append(sqlParams, cityCodes)
}
err = GetRows(db, &places, sql, sqlParams)
return places, err
}

View File

@@ -0,0 +1,19 @@
package dao
import (
"git.rosy.net.cn/jx-callback/business/model"
)
func CheckHeard(printNo string) (bool, error) {
var data *model.PrintActivation
err := GetRow(GetDB(), &data, `SELECT * FROM print_activation WHERE print_no = ?`, []interface{}{printNo}...)
if err != nil {
return false, err
}
if data == nil {
return false, nil
}
return true, nil
}

View File

@@ -0,0 +1,42 @@
package dao
import (
"git.rosy.net.cn/jx-callback/business/model"
"time"
)
// QueryPrintBindStore 查询绑定门店
func QueryPrintBindStore(printNo string) ([]*model.PrintBindStore, error) {
var data []*model.PrintBindStore
if err := GetRows(GetDB(), &data, `SELECT * FROM print_bind_store WHERE print_no = ?`, []interface{}{printNo}...); err != nil {
return nil, err
}
return data, nil
}
// BindStoreList 绑定门店信息
func BindStoreList(req *model.AddPrinterParam, userId string) error {
param := &model.PrintBindStore{
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
StoreID: req.StoreId,
StoreName: req.Name,
StoreVendor: 9, // 绑定平台,全平台
PrintNo: req.PrintNo,
StoreStatus: 1, // 门店开启
BindStatus: 1, // 绑定状态
}
if userId != "" {
param.UserId = userId
} else {
param.UserId = "system"
}
return CreateEntity(GetDB(), param)
}
// DeleteStoreList 删除绑定门店
func DeleteStoreList(printNo string, storeId string) error {
sql := ` DELETE FROM print_bind_store WHERE print_no = ? AND store_id = ? `
_, err := ExecuteSQL(GetDB(), sql, []interface{}{printNo, storeId}...)
return err
}

View File

@@ -0,0 +1,533 @@
package dao
import (
"encoding/json"
"fmt"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-print/globals"
"strings"
"time"
)
var SystemTempObj map[string]*model.SystemTemp
func Init() {
SystemTempObj = make(map[string]*model.SystemTemp, 0)
sysTempList, err := QuerySystemTemp()
if err != nil {
globals.SugarLogger.Debug("query system temp err :", err)
return
}
SystemTempObj[sysTempList.TempSize] = sysTempList
//now := time.Now()
//param := &model.SystemTemp{
// CreatedAt: &now,
// UpdatedAt: &now,
// LastOperator: "system",
// DeletedAt: &utils.DefaultTimeValue,
// TempName: "",
// TempRank: model.SystemTempKey,
// Temp: "",
// UserId: "system_user",
// TempType: model.TempTypeMerchant,
// TempSize: model.SystemTempSizeBig,
// PrintSn: "system",
// IsUse: 1,
//}
// 初始化大字体模板
//if _, v := temp[model.SystemTempSizeBig]; !v {
// param.TempName = "system" + model.SystemTempSizeBig
// param.Temp = model.SystemTempValue
// if err := AddTemp(param); err != nil {
// globals.SugarLogger.Debug("init system temp err :", err)
// }
// SystemTempObj[model.SystemTempSizeBig] = param
//}
// 初始化中字体模板
//if _, v := temp[model.SystemTempSizeMedium]; !v {
// param.TempName = "system" + model.SystemTempSizeMedium
// medium := strings.Replace(model.SystemTempValue, "<b>", "<hb>", -1)
// medium2 := strings.Replace(medium, "</b>", "</hb>", -1)
// param.Temp = medium2
// param.TempSize = model.SystemTempSizeMedium
// param.IsUse = 2
// if err := AddTemp(param); err != nil {
// globals.SugarLogger.Debug("init system temp err :", err)
// }
// SystemTempObj[model.SystemTempSizeMedium] = param
//}
// 初始化小字体模板
//if _, v := temp[model.SystemTempSizeSmall]; !v {
// param.TempName = "system" + model.SystemTempSizeSmall
// medium := strings.Replace(model.SystemTempValue, "<b>", " ", -1)
// medium2 := strings.Replace(medium, "</b>", " ", -1)
// param.Temp = medium2
// param.TempSize = model.SystemTempSizeSmall
// param.IsUse = 2
// if err := AddTemp(param); err != nil {
// globals.SugarLogger.Debug("init system temp err :", err)
// }
// SystemTempObj[model.SystemTempSizeSmall] = param
//}
}
// MakePrintMsgOnTemp 将打印数据渲染到模板当中
func MakePrintMsgOnTemp(param map[string]string, userId string) (string, error) {
// 查询用户默认模板,不存在则使用系统默认模板
userTemp := &model.SystemTemp{}
userTemp, isHave, err := SelectUserDefaultTemp(userId, model.TempTypeMerchantUser)
if err != nil || !isHave {
userTemp, err = QuerySystemTemp()
}
if userTemp == nil || !isHave {
if userTemp.TempType != "" {
userTemp = SystemTempObj[userTemp.TempSize]
} else {
userTemp = SystemTempObj[model.SystemTempSizeBig]
}
}
// 需要打印数据
printMsg := ""
printValue := make([]interface{}, 0, 0)
userTempMap := make(map[string]string, 0)
if err := json.Unmarshal([]byte(userTemp.Temp), &userTempMap); err != nil {
return "", err
}
for _, v := range strings.Split(userTemp.TempRank, ",") {
switch v {
case "skuName", "skuNumber", "skuPrice", "skuAllPrice", "allSkuTypeCount", "allSkuCount", "skuUpc", "userPayMoney":
continue
case "goodsListDetail":
printMsg += userTempMap[v]
skuList := make([]*model.SkuListPrintOrder, 0, 0)
if err := json.Unmarshal([]byte(param["skuList"]), &skuList); err != nil {
return "", err
}
for i := 0; i < len(skuList); i++ {
printMsg += userTempMap["skuName"]
printMsg += userTempMap["skuNumber"]
printMsg += userTempMap["skuPrice"]
printMsg += userTempMap["skuAllPrice"]
printValue = append(printValue, skuList[i].SkuName, skuList[i].SkuCount, skuList[i].SalePrice, skuList[i].TotalCountPrice)
if skuList[i].Upc != "" {
printMsg += userTempMap["skuUpc"]
printValue = append(printValue, skuList[i].Upc)
}
}
printMsg += userTempMap["allSkuTypeCount"]
printValue = append(printValue, param["allSkuTypeCount"])
printMsg += userTempMap["allSkuCount"]
printValue = append(printValue, param["allSkuCount"])
printMsg += userTempMap["userPayMoney"]
printValue = append(printValue, param["userPayMoney"])
case "businessType":
if param[v] == "2" { // 是预订单
printMsg += userTempMap[v]
printValue = append(printValue, param[v])
}
case "divider":
printMsg += userTempMap[v]
case "title":
printMsg += userTempMap[v]
case "qrcOrder": // 老版打印机展示不要
//printMsg += userTempMap[v]
//printValue = append(printValue, param[v])
printMsg += `<b>%s #%s</b>`
printValue = append(printValue, param["vendorName"], param["vendorOrderNo"])
default:
printMsg += userTempMap[v]
printValue = append(printValue, param[v])
}
}
return strings.Replace(fmt.Sprintf(strings.Replace(printMsg, "\n", "", -1), printValue...), "\\n", "\r\n", -1), nil
//}
}
// MakePrintMsgOnTempVoice 制作平台语音
func MakePrintMsgOnTempVoice(param map[string]string, setting *model.PrintSettingObj, userId string) (string, error) {
// 打订单
if param[model.OrderStatusPrint] != "" {
// 订单提示设置
printMsg, err := PrinterOrderVoice(param, setting, userId)
if err != nil {
globals.SugarLogger.Debug("err Unmarshal userTemp.printMsg", err)
return "", err
}
return printMsg, nil
}
// 打运单
if param[model.WayBillStatusPrint] != "" {
switch param[model.WayBillStatusPrint] {
case utils.Int2Str(model.WaybillStatusCourierAssigned): // 分配骑手
return PrintWayBillOrderStatus(param, setting), nil
case utils.Int2Str(model.WaybillStatusDeliverReminder): // 催单
printVoiceMsg := ``
printVoiceValue := make([]interface{}, 0, 0)
//printVoiceMsg, printVoiceValue = SyntheticSpeech(printVoiceMsg, printVoiceValue, param)
printVoiceMsg += `<sound>%d</sound>`
printVoiceValue = append(printVoiceValue, model.ReminderOrderVoice)
return strings.Replace(fmt.Sprintf(strings.Replace(printVoiceMsg, "\n", "", -1), printVoiceValue...), "\\n", "\r\n", -1), nil
case utils.Int2Str(model.WaybillStatusDelivered): // 送达
printVoiceMsg := ``
printVoiceValue := make([]interface{}, 0, 0)
//printVoiceMsg, printVoiceValue = SyntheticSpeech(printVoiceMsg, printVoiceValue, param)
printVoiceMsg += `<sound>%d</sound>`
printVoiceValue = append(printVoiceValue, model.FinialsOrderVoice)
return strings.Replace(fmt.Sprintf(strings.Replace(printVoiceMsg, "\n", "", -1), printVoiceValue...), "\\n", "\r\n", -1), nil
}
}
// 门店状态
if param[model.StoreStatusPrint] != "" {
return PrintStoreStatus(param, setting), nil
}
// 进店咨询
if param[model.EnterTheStorePrint] != "" && setting.VoiceSetting.ConsultingPrint == model.SettingOpen {
return `<sound>19</sound>`, nil
}
return "", nil
}
// PrinterOrderVoice 打印机订单提示设置
func PrinterOrderVoice(param map[string]string, setting *model.PrintSettingObj, userId string) (string, error) {
var (
printVoiceMsg string //语音信息
printVoiceValue = make([]interface{}, 0, 0)
textMsg string // 文本信息
err error
)
// 订单状态
switch param[model.OrderStatusPrint] {
// 新订单(待接单)
case utils.Int2Str(model.OrderStatusNew):
// 称谓设置/平台语音设置
if setting.CallNameSetting == 64 || setting.CallNameSetting == 65 || setting.CallNameSetting == 66 {
// 老板
printVoiceMsg += `<sound>%d</sound>`
printVoiceValue = append(printVoiceValue, setting.CallNameSetting)
}
// 订单设置
if setting.PrintSetting.WaitOrderPrint == model.SettingOpen { // 打印订单
textMsg, err = MakePrintMsgOnTemp(param, userId)
if err != nil {
return "", err
}
}
if setting.VoiceSetting.WaitOrderVoice == model.SettingOpen { // 订单通知
printVoiceMsg += `<sound>%d</sound>` // 你来新订单了
printVoiceValue = append(printVoiceValue, model.NewOrderVoice)
}
// 申请取消
case utils.Int2Str(model.ApplyOrderCancel):
// 称谓设置/平台语音设置
if setting.CallNameSetting == 64 || setting.CallNameSetting == 65 || setting.CallNameSetting == 66 {
// 老板
printVoiceMsg += `<sound>%d</sound>`
printVoiceValue = append(printVoiceValue, setting.CallNameSetting)
}
// 订单设置
if setting.PrintSetting.ApplyUserCancelOrder == model.SettingOpen { // 申请取消打印
rejection := ``
rejectionValue := make([]interface{}, 0, 0)
rejection += `<center><b>客户申请取消订单:</b></center><br>`
rejection += `<center><b>订单号: %s</b></center><br>`
rejection += `<center><b>订单来源: %s # %s</b></center><br>`
rejection += `<center><b>取消时间: %s</b></center><br>`
rejectionValue = append(rejectionValue, param[model.OrderNoPrint], param[model.VendorNamePrint], param[model.VendorOrderNoPrint], utils.Time2DateStr(time.Now()))
textMsg = strings.Replace(fmt.Sprintf(strings.Replace(rejection, "\n", "", -1), rejectionValue...), "\\n", "\r\n", -1)
}
if setting.VoiceSetting.ApplyUserOrderCancelVoice == model.SettingOpen { // 申请取消语音
printVoiceMsg += `<sound>%d</sound>`
printVoiceValue = append(printVoiceValue, model.ApplyCancelVoice)
//printVoiceMsg, printVoiceValue = SyntheticSpeech(printVoiceMsg, printVoiceValue, param)
}
// 申请退货
case utils.Int2Str(model.ApplyOrderRefundGoods):
// 称谓设置/平台语音设置
if setting.CallNameSetting == 64 || setting.CallNameSetting == 65 || setting.CallNameSetting == 66 {
// 老板
printVoiceMsg += `<sound>%d</sound>`
printVoiceValue = append(printVoiceValue, setting.CallNameSetting)
}
rejection := ``
rejectionValue := make([]interface{}, 0, 0)
rejection += `<center><b>客户申请退货:</b></center><br>`
rejection += `<center><b>订单号: %s</b></center><br>`
rejection += `<center><b>订单来源: %s # %s</b></center><br>`
rejection += `<center><b>原因: %s</b></center><br>`
rejectionValue = append(rejectionValue, param[model.OrderNoPrint], param[model.VendorNamePrint], param[model.VendorOrderNoPrint], param[model.RejectionReasonPrint])
textMsg = strings.Replace(fmt.Sprintf(strings.Replace(rejection, "\n", "", -1), rejectionValue...), "\\n", "\r\n", -1)
if setting.VoiceSetting.ApplyRefundGoodsVoice == model.SettingOpen { // 申请退货语音
printVoiceMsg += `<sound>%d</sound>`
printVoiceValue = append(printVoiceValue, model.ApplyReturnGoodsVoice)
// printVoiceMsg, printVoiceValue = SyntheticSpeech(printVoiceMsg, printVoiceValue, param)
}
// 申请退款
case utils.Int2Str(model.ApplyOrderRefund):
// 称谓设置/平台语音设置
if setting.CallNameSetting == 64 || setting.CallNameSetting == 65 || setting.CallNameSetting == 66 {
// 老板
printVoiceMsg += `<sound>%d</sound>`
printVoiceValue = append(printVoiceValue, setting.CallNameSetting)
}
// 订单设置
if setting.PrintSetting.ApplyUserRefund == model.SettingOpen { // 取消退款订单
textMsg, err = MakePrintMsgOnTemp(param, userId)
if err != nil {
return "", err
}
}
if setting.VoiceSetting.ApplyRefundOrderVoice == model.SettingOpen {
//printVoiceMsg, printVoiceValue = SyntheticSpeech(printVoiceMsg, printVoiceValue, param)
printVoiceMsg += `<sound>%d</sound>`
printVoiceValue = append(printVoiceValue, model.ApplyRefundVoice)
}
// 取消打印
case utils.Int2Str(model.OrderStatusRejection): // 拒收
// 称谓设置/平台语音设置
if setting.CallNameSetting == 64 || setting.CallNameSetting == 65 || setting.CallNameSetting == 66 {
// 老板
printVoiceMsg += `<sound>%d</sound>`
printVoiceValue = append(printVoiceValue, setting.CallNameSetting)
}
//if setting.VoiceSetting.CustomerRejectionVoice == model.SettingOpen && setting.SystemVoice == model.SettingOpen {
// // 暂无语音打印
//}
// 拒收暂无语音设置,使用文本提示
if setting.PrintSetting.CustomerRejectionPrint == model.SettingOpen { // 客户拒收打印
rejection := ``
rejectionValue := make([]interface{}, 0, 0)
rejection += `<center><b>客户拒收信息:</b></center><br>`
rejection += `<center><b>订单号: %s</b></center><br>`
rejection += `<center><b>订单来源: %s # %s</b></center><br>`
rejection += `<center><b>拒收原因: %s</b></center><br>`
rejectionValue = append(rejectionValue, param[model.OrderNoPrint], param[model.VendorNamePrint], param[model.VendorOrderNoPrint], param[model.RejectionReasonPrint])
textMsg = strings.Replace(fmt.Sprintf(strings.Replace(rejection, "\n", "", -1), rejectionValue...), "\\n", "\r\n", -1)
}
case utils.Int2Str(model.OrderStatusCustomerService): // 客服退款
// 称谓设置/平台语音设置
if setting.CallNameSetting == 64 || setting.CallNameSetting == 65 || setting.CallNameSetting == 66 {
// 老板
printVoiceMsg += `<sound>%d</sound>`
printVoiceValue = append(printVoiceValue, setting.CallNameSetting)
}
if setting.VoiceSetting.CusterRefundVoice == model.SettingOpen {
printVoiceMsg += `<sound>%d</sound>`
printVoiceValue = append(printVoiceValue, model.BusinessResponsibilityVoice)
}
if setting.PrintSetting.CusterRefundPrint == model.SettingOpen {
rejection := ``
rejectionValue := make([]interface{}, 0, 0)
rejection += `<center><b>客服退款详情:</b></center><br>`
rejection += `<center><b>订单号: %s</b></center><br>`
rejection += `<center><b>订单来源: %s # %s</b></center><br>`
rejection += `<center><b>退款原因: %s</b></center><br>`
rejection += `<center><b>退款时间: %s</b></center><br>`
rejectionValue = append(rejectionValue, param[model.OrderNoPrint], param[model.VendorNamePrint], param[model.VendorOrderNoPrint], param[model.CustcareRefundReasonPrint], utils.Time2DateStr(time.Now()))
textMsg = strings.Replace(fmt.Sprintf(strings.Replace(rejection, "\n", "", -1), rejectionValue...), "\\n", "\r\n", -1)
}
case utils.Int2Str(model.OrderStatusCanceled), utils.Int2Str(model.CancelOrderSuccess): // 取消订单成功
// 称谓设置/平台语音设置
if setting.CallNameSetting == 64 || setting.CallNameSetting == 65 || setting.CallNameSetting == 66 {
// 老板
printVoiceMsg += `<sound>%d</sound>`
printVoiceValue = append(printVoiceValue, setting.CallNameSetting)
if setting.VoiceSetting.RefundGoodsVoice == model.SettingOpen {
printVoiceMsg += `<sound>%d</sound>`
printVoiceValue = append(printVoiceValue, model.CancelOrderVoice)
}
}
if setting.PrintSetting.CusterRefundPrint == model.SettingOpen {
rejection := ``
rejectionValue := make([]interface{}, 0, 0)
rejection += `<center><b>订单取消成功:</b></center><br>`
rejection += `<center><b>订单号: %s</b></center><br>`
rejection += `<center><b>订单来源: %s # %s</b></center><br>`
rejection += `<center><b>取消原因: %s</b></center><br>`
rejection += `<center><b>取消成功时间: %s</b></center><br>`
rejectionValue = append(rejectionValue, param[model.OrderNoPrint], param[model.VendorNamePrint], param[model.VendorOrderNoPrint], param[model.CustcareRefundReasonPrint], utils.Time2DateStr(time.Now()))
textMsg = strings.Replace(fmt.Sprintf(strings.Replace(rejection, "\n", "", -1), rejectionValue...), "\\n", "\r\n", -1)
}
case utils.Int2Str(model.BusinessCancelOrder): // 商家取消打印
// 称谓设置/平台语音设置
if setting.CallNameSetting == 64 || setting.CallNameSetting == 65 || setting.CallNameSetting == 66 {
// 老板
printVoiceMsg += `<sound>%d</sound>`
printVoiceValue = append(printVoiceValue, setting.CallNameSetting)
}
if setting.PrintSetting.BusinessOrderCancel == model.SettingOpen {
rejection := ``
rejectionValue := make([]interface{}, 0, 0)
rejection += `<center><b>商家侧取消订单:</b></center><br>`
rejection += `<center><b>订单号: %s</b></center><br>`
rejection += `<center><b>订单来源: %s # %s</b></center><br>`
rejection += `<center><b>取消原因: %s</b></center><br>`
rejection += `<center><b>取消成功时间: %s</b></center><br>`
rejectionValue = append(rejectionValue, param[model.OrderNoPrint], param[model.VendorNamePrint], param[model.VendorOrderNoPrint], param[model.CustcareRefundReasonPrint], utils.Time2DateStr(time.Now()))
textMsg = strings.Replace(fmt.Sprintf(strings.Replace(rejection, "\n", "", -1), rejectionValue...), "\\n", "\r\n", -1)
}
case utils.Int2Str(model.OrderRefundMoneySuccess): // 订单退款成功打印
// 称谓设置/平台语音设置
if setting.CallNameSetting == 64 || setting.CallNameSetting == 65 || setting.CallNameSetting == 66 {
// 老板
printVoiceMsg += `<sound>%d</sound>`
printVoiceValue = append(printVoiceValue, setting.CallNameSetting)
}
if setting.PrintSetting.OrderCancelSuccess == model.SettingOpen {
rejection := ``
rejectionValue := make([]interface{}, 0, 0)
rejection += `<center><b>退款成功:</b></center><br>`
rejection += `<center><b>订单号: %s</b></center><br>`
rejection += `<center><b>订单来源: %s # %s</b></center><br>`
rejectionValue = append(rejectionValue, param[model.OrderNoPrint], param[model.VendorNamePrint], param[model.VendorOrderNoPrint])
textMsg = strings.Replace(fmt.Sprintf(strings.Replace(rejection, "\n", "", -1), rejectionValue...), "\\n", "\r\n", -1)
}
}
voice := strings.Replace(fmt.Sprintf(strings.Replace(printVoiceMsg, "\n", "", -1), printVoiceValue...), "\\n", "\r\n", -1)
return voice + textMsg, nil
}
// PrintWayBillOrderStatus 打印运单类通知消息
func PrintWayBillOrderStatus(param map[string]string, setting *model.PrintSettingObj) string {
var (
printVoiceMsg string //语音信息
printVoiceValue = make([]interface{}, 0, 0)
textMsg string // 文本信息
textMsgValue = make([]interface{}, 0, 0) // 文本信息
)
switch param[model.WayBillStatusPrint] {
case utils.Int2Str(model.WaybillStatusAccepted), utils.Int2Str(model.WaybillStatusCourierAssigned): // 分配骑手
if setting.PrintSetting.RiderTakeOrder == model.SettingOpen { // 打印订单
textMsg += `<center><b>接单骑手信息:</b></center><br>`
textMsg += `<center><b>骑手姓名: %s</b></center><br>`
textMsg += `<center><b>骑手电话: %s</b></center><br>`
textMsg += `<center><b>接单时间: %s</b></center><br>`
textMsg += `<center><b>订单来源: %s</b></center><br>`
textMsg += `<center><b>单号: #%s</b></center><br>`
textMsgValue = append(textMsgValue, param[model.RiderNamePrint], param[model.RiderPhonePrint], utils.Time2DateStr(time.Now()), param[model.VendorNamePrint], param[model.VendorOrderNoPrint])
}
}
if setting.VoiceSetting.RiderTakeOrderVoice == model.SettingOpen { // 骑手接单语音通知
printVoiceMsg += `<sound>%d</sound><sound>%d</sound>` // 骑手已经接单了
printVoiceValue = append(printVoiceValue, model.RiderGetOrderVoice)
}
msg := strings.Replace(fmt.Sprintf(strings.Replace(textMsg, "\n", "", -1), textMsgValue...), "\\n", "\r\n", -1)
voice := strings.Replace(fmt.Sprintf(strings.Replace(printVoiceMsg, "\n", "", -1), printVoiceValue...), "\\n", "\r\n", -1)
return voice + msg
}
// PrintStoreStatus 打印门店状态
func PrintStoreStatus(param map[string]string, setting *model.PrintSettingObj) string {
var (
printVoiceMsg string //语音信息
printVoiceValue = make([]interface{}, 0, 0)
textMsg string // 文本信息
textMsgValue = make([]interface{}, 0, 0)
)
switch utils.Str2Int(param[model.StoreStatusPrint]) {
case -9: // 丢失授权
var voice string
if setting.VoiceSetting.LoseAuthorization == model.SettingOpen {
printVoiceMsg += `<sound>%d</sound>`
printVoiceValue = append(printVoiceValue, model.LoseTokenVoice)
voice = strings.Replace(fmt.Sprintf(strings.Replace(printVoiceMsg, "\n", "", -1), printVoiceValue...), "\\n", "\r\n", -1)
}
textMsg += `<left><b>门店丢失授权通知</b></left><br>`
textMsg += `<left><b>门店:%s</b></left><br>`
textMsg += `<left><b>平台:%s</b></left><br>`
textMsg += `<left><b>下线时间:%s</b></left><br>`
textMsg += `<left><b>授权丢失,将无法继续打压订单!!!!</b></left><br>`
textMsgValue = append(textMsgValue, param[model.StoreNamePrint], param[model.VendorNamePrint], utils.Time2DateStr(time.Now()))
msg := strings.Replace(fmt.Sprintf(strings.Replace(textMsg, "\n", "", -1), textMsgValue...), "\\n", "\r\n", -1)
return voice + msg
default:
// 离线打印文本开启
textMsg += `<center><b>门店下线通知</b></center><br>`
textMsg += `<center><b>门店:%s</b></center><br>`
textMsg += `<center><b>平台:%s</b></center><br>`
textMsg += `<center><b>下线时间:%s</b></center><br>`
textMsgValue = append(textMsgValue, param[model.StoreNamePrint], param[model.VendorNamePrint], utils.Time2DateStr(time.Now()))
// 离线打印语音开启
printVoiceMsg += `<sound>%d</sound>`
printVoiceValue = append(printVoiceValue, model.StoreOfflineVoice)
voice := strings.Replace(fmt.Sprintf(strings.Replace(printVoiceMsg, "\n", "", -1), printVoiceValue...), "\\n", "\r\n", -1)
msg := strings.Replace(fmt.Sprintf(strings.Replace(textMsg, "\n", "", -1), textMsgValue...), "\\n", "\r\n", -1)
return voice + msg
}
}
// SyntheticSpeech 合成语音 (美团xxx号订单)
func SyntheticSpeech(printVoiceMsg string, printVoiceValue []interface{}, param map[string]string) (string, []interface{}) {
printVoiceMsg += `<sound>%d</sound>` // 美团
switch param[model.VendorIDPrint] {
case utils.Int2Str(model.VendorIDJD): // 京东
printVoiceValue = append(printVoiceValue, model.JdVoice)
case utils.Int2Str(model.VendorIDMTWM): // 美团
printVoiceValue = append(printVoiceValue, model.MtVoice)
case utils.Int2Str(model.VendorIDELM): // 饿了么
printVoiceValue = append(printVoiceValue, model.ElmVoice)
case utils.Int2Str(model.VendorIDEBAI): // 饿百
printVoiceValue = append(printVoiceValue, model.ElmVoice)
case utils.Int2Str(model.VendorIDJDShop): // 京东商城
printVoiceValue = append(printVoiceValue, model.JdToHose)
case utils.Int2Str(model.VendorIDTT): // 抖音
// 暂无
}
if param[model.VendorOrderNoPrint] != "" {
switch len(param[model.VendorOrderNoPrint]) {
case 1:
printVoiceMsg += `<sound>%d</sound>`
printVoiceValue = append(printVoiceValue, model.NumberVoiceMap[param[model.VendorOrderNoPrint]])
case 2:
printVoiceMsg += `<sound>%d</sound>`
printVoiceValue = append(printVoiceValue, model.NumberVoiceMap[param[model.VendorOrderNoPrint][:1]+"0"])
if param[model.VendorOrderNoPrint][1:] != "0" {
printVoiceMsg += `<sound>%d</sound>`
printVoiceValue = append(printVoiceValue, model.NumberVoiceMap[param[model.VendorOrderNoPrint][1:]])
}
case 3:
printVoiceMsg += `<sound>%d</sound>`
printVoiceValue = append(printVoiceValue, model.NumberVoiceMap[param[model.VendorOrderNoPrint][0:1]+"00"])
if param[model.VendorOrderNoPrint][1:2] == "0" && param[model.VendorOrderNoPrint][2:] == "0" {
} else if param[model.VendorOrderNoPrint][1:2] == "0" && param[model.VendorOrderNoPrint][2:] != "0" {
printVoiceMsg += `<sound>%d</sound>`
printVoiceValue = append(printVoiceValue, model.NumberVoiceMap[param[model.VendorOrderNoPrint][1:2]])
printVoiceMsg += `<sound>%d</sound>`
printVoiceValue = append(printVoiceValue, model.NumberVoiceMap[param[model.VendorOrderNoPrint][2:]])
} else if param[model.VendorOrderNoPrint][1:2] != "0" && param[model.VendorOrderNoPrint][2:] == "0" {
printVoiceMsg += `<sound>%d</sound>`
printVoiceValue = append(printVoiceValue, model.NumberVoiceMap[param[model.VendorOrderNoPrint][1:2]+"0"])
} else if param[model.VendorOrderNoPrint][1:2] != "0" && param[model.VendorOrderNoPrint][2:] != "0" {
printVoiceMsg += `<sound>%d</sound>`
printVoiceValue = append(printVoiceValue, model.NumberVoiceMap[param[model.VendorOrderNoPrint][1:2]+"0"])
printVoiceMsg += `<sound>%d</sound>`
printVoiceValue = append(printVoiceValue, model.NumberVoiceMap[param[model.VendorOrderNoPrint][2:]])
}
}
}
printVoiceMsg += `<sound>%d</sound>`
printVoiceValue = append(printVoiceValue, model.OrderNoVoice)
return printVoiceMsg, printVoiceValue
}

View File

@@ -1,74 +0,0 @@
package orderman
import (
"fmt"
"strings"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/jxutils/netprinter"
"git.rosy.net.cn/jx-callback/business/jxutils/weixinmsg"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/business/partner/purchase/jd"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/globals/api"
)
func (c *OrderManager) OnNewFakeJdOrder(vendorOrderID string) (err error) {
utils.CallFuncAsync(func() {
orderInfo, err := api.FakeJdAPI.FakeQuerySingleOrderRaw(vendorOrderID)
if err == nil {
order := jd.Map2Order(orderInfo)
jxutils.RefreshOrderSkuRelated(order)
err = c.notifyNewFakeJdOrder(order)
}
if err != nil {
globals.SugarLogger.Warnf("OnNewFakeJdOrder failed with err:%v", err)
}
})
return err
}
func (c *OrderManager) notifyNewFakeJdOrder(order *model.GoodsOrder) (err error) {
db := dao.GetDB()
storeDetail, err := dao.GetStoreDetailByVendorStoreID(db, order.VendorStoreID, model.VendorIDJD, "")
if err != nil {
return err
}
realStoreID := storeDetail.ID
if storeDetail.LinkStoreID != 0 {
realStoreID = storeDetail.LinkStoreID
}
notifyWxNewFakeJdOrder(order, realStoreID)
netprinter.PrintOrderByOrder4Store(jxcontext.AdminCtx, order, realStoreID)
return err
}
func notifyWxNewFakeJdOrder(order *model.GoodsOrder, storeID int) (err error) {
globals.SugarLogger.Debugf("notifyWxNewFakeJdOrder orderID:%s", order.VendorOrderID)
sb := new(strings.Builder)
sb.WriteString("老板,你有新订单了\n")
sb.WriteString(fmt.Sprintf("订单号:%s\n", order.VendorOrderID))
sb.WriteString("送达时间:")
if order.BusinessType == model.BusinessTypeDingshida {
sb.WriteString(utils.Time2Str(order.ExpectedDeliveredTime))
} else {
sb.WriteString("立即达")
}
sb.WriteString("\n")
sb.WriteString(fmt.Sprintf("买家:%s\n", order.ConsigneeName))
sb.WriteString(fmt.Sprintf("电话:%s\n", order.ConsigneeMobile))
sb.WriteString(fmt.Sprintf("收货地址:%s\n", order.ConsigneeAddress))
sb.WriteString("商品详情:\n")
for _, sku := range order.Skus {
sb.WriteString(fmt.Sprintf("\t%s*%d\n", sku.SkuName, sku.Count))
}
title := fmt.Sprintf("你有到家菜市新订单%d", order.OrderSeq)
content := sb.String()
// globals.SugarLogger.Debugf("notifyWxNewFakeJdOrder, orderID:%s, content:%s", order.VendorOrderID, content)
_, err = weixinmsg.SendStoreMessage(jxcontext.AdminCtx, title, content, []int{storeID}, nil, "", model.MessageTypeStore, true, true)
return err
}

View File

@@ -1,14 +0,0 @@
package orderman
import (
"testing"
"time"
)
func TestOnNewFakeJdOrder(t *testing.T) {
err := FixedOrderManager.OnNewFakeJdOrder("2002984074001021")
if err != nil {
t.Fatal(err)
}
time.Sleep(3 * time.Second)
}

View File

@@ -1,262 +0,0 @@
package orderman
import (
"math"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/globals"
)
const (
TotalRate = 200 // 总费率千分之200= 第三方平台费+京西品牌费+京西服务费现阶段都是合计200‰
MaxFreightMoneyFromJxByShop = 7 // 商家自送实际转美团/达达后由商家承担的运费金额上限
)
// 处理正向订单结账信息
func (c *OrderManager) SaveOrderFinancialInfo(order *model.OrderFinancial, operation string) (err error) {
db := dao.GetDB()
txDB , _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil || err != nil {
dao.Rollback(db, txDB)
if r != nil {
panic(r)
}
}
}()
if operation == partner.UpdatedPeration {
// db := orm.NewOrm()
err = utils.CallFuncLogError(func() error {
_, err = dao.ExecuteSQL(db, "DELETE FROM order_financial WHERE vendor_order_id = ? AND vendor_id = ?", order.VendorOrderID, order.VendorID)
return err
}, "SaveOrderFinancialInfo delete order_financial, orderID:%s", order.VendorOrderID)
if err != nil {
return err
}
err = utils.CallFuncLogError(func() error {
_, err = dao.ExecuteSQL(db, "DELETE FROM order_sku_financial WHERE vendor_order_id = ? AND vendor_id = ? AND is_afs_order = 0", order.VendorOrderID, order.VendorID)
return err
}, "SaveOrderFinancialInfo delete order_sku_financial, orderID:%s", order.VendorOrderID)
if err != nil {
return err
}
err = utils.CallFuncLogError(func() error {
_, err = dao.ExecuteSQL(db, "DELETE FROM order_discount_financial WHERE vendor_order_id = ? AND vendor_id = ?", order.VendorOrderID, order.VendorID)
return err
}, "SaveOrderFinancialInfo delete order_discount_financial, orderID:%s", order.VendorOrderID)
if err != nil {
return err
}
}
for _, activity := range order.Discounts {
if err = dao.CreateEntity(db, activity); err != nil {
if !dao.IsDuplicateError(err) {
globals.SugarLogger.Warnf("On SaveOrderDiscountFinancialInfo order.VendorOrderID:%s err: order is err", order.VendorOrderID)
return err
}
dao.Rollback(db, txDB)
return nil
}
}
order.ShopMoneyByCal = order.SalePriceMoney - order.TotalDiscountMoney - order.PointsDeductionMoney + order.PmFreightDiscountMoney - order.DistanceFreightMoney - order.FreightTipsMoney - order.DonationMoney + order.SelfDeliveryDiscountMoney + order.PmSubsidyMoney + order.SkuBoxMoney + order.BoxMoney - order.PmMoney
order.JxPmMoney = utils.Float64TwoInt64(float64(order.ShopMoney+order.PmMoney)*TotalRate/1000) - order.PmMoney // 京西平台费 = 总金额*20%-第三方平台费
if order.JxPmMoney < 0 { // 如果算出京西平台费为负数则置0
order.JxPmMoney = 0
}
order.JxShopMoney = order.ShopMoney - order.JxPmMoney + order.JxSubsidyMoney - order.JxFreightMoneyByShop
// 订单结算金额拆分计算拆分到单条sku
// 先获取订单主体优惠金额
platOrderGoodsDiscountMoney := order.PmSubsidyMoney - order.PmSkuSubsidyMoney + order.SelfDeliveryDiscountMoney
// 结算平台扣除项汇总---平台佣金,商家设置运费减免,远距离费,小费,公益捐款、、、、
deductionsByPm := order.FreightDiscountMoney + order.DistanceFreightMoney + order.FreightTipsMoney + order.DonationMoney + order.PmMoney
// 结算京西扣除项汇总---京西佣金,京西配送运费
deductionsByJx := order.JxPmMoney + order.JxFreightMoneyByShop
for _, sku := range order.Skus[1:] {
// 用户支付菜品金额用户为这一条sku支付的菜品金额
sku.UserMoney = utils.Float64TwoInt64(float64(order.SalePriceMoney-order.DiscountMoney-order.PointsDeductionMoney+order.BoxMoney+order.SkuBoxMoney) * float64(sku.SalePrice*int64(sku.Count)+sku.SkuBoxMoney) / float64(order.SalePriceMoney+order.SkuBoxMoney)) // 林峰确认比如49-2满减算餐盒费满49元不算餐盒费不足49元是可以参加满减活动的那么餐盒费也应该和商品金额一起进行折算
order.Skus[0].UserMoney += sku.UserMoney
// 计算平台订单主体补贴拆分到单条sku的金额 + sku.PmSubsidyMoneyForSku
sku.PmSubsidyMoney = sku.PmSkuSubsidyMoney + utils.Float64TwoInt64(float64(platOrderGoodsDiscountMoney*sku.SalePrice*int64(sku.Count)+sku.SkuBoxMoney)/float64(order.SalePriceMoney+order.SkuBoxMoney))
order.Skus[0].PmSubsidyMoney += sku.PmSubsidyMoney
// 计算京西满减补贴拆分到单条sku的金额 + sku.JxSubsidyMoneyForSku
sku.JxSubsidyMoney = sku.JxSkuSubsidyMoney + utils.Float64TwoInt64(float64(order.JxSubsidyMoney-order.PmSkuSubsidyMoney)*float64(sku.SalePrice*int64(sku.Count)+sku.SkuBoxMoney)/float64(order.SalePriceMoney+order.SkuBoxMoney))
order.Skus[0].JxSubsidyMoney += sku.JxSubsidyMoney
// 计算单条sku需要承担的平台扣费金额
sku.PmDeductionsMoney = utils.Float64TwoInt64(float64(deductionsByPm) * (float64(sku.UserMoney + sku.PmSubsidyMoney)) / (float64(order.SalePriceMoney + order.BoxMoney + order.SkuBoxMoney - order.DiscountMoney - order.PointsDeductionMoney + order.PmSubsidyMoney)))
order.Skus[0].PmDeductionsMoney += sku.PmDeductionsMoney
// 计算单条sku平台应该结算给京西的金额
sku.ShopMoneyByCal = sku.UserMoney + sku.PmSubsidyMoney - sku.PmDeductionsMoney
order.Skus[0].ShopMoneyByCal += sku.ShopMoneyByCal
// j计算单条sku需要承担的京西扣费金额
sku.JxDeductionsMoney = utils.Float64TwoInt64(float64(deductionsByJx*sku.ShopMoneyByCal) / float64(order.ShopMoney))
order.Skus[0].JxDeductionsMoney += sku.JxDeductionsMoney
// 计算单条sku京西应该结算给商家的金额
sku.JxShopMoney = sku.ShopMoneyByCal + sku.JxSubsidyMoney - sku.JxDeductionsMoney
order.Skus[0].JxShopMoney += sku.JxShopMoney
if sku.SkuID >= math.MaxInt32 {
sku.SkuID = sku.JxSkuID
}
if err = dao.CreateEntity(db, sku); err != nil {
if !dao.IsDuplicateError(err) {
globals.SugarLogger.Warnf("On SaveOrderSkuFinancialInfo order.VendorOrderID:%s err:%v", order.VendorOrderID, err)
return err
}
dao.Rollback(db, txDB)
return nil
}
}
if len(order.Skus) > 0 {
sku := order.Skus[0]
if sku.SkuID > math.MaxInt32 {
sku.SkuID = sku.JxSkuID
}
sku.UserMoney = order.SalePriceMoney - order.DiscountMoney - sku.UserMoney
sku.PmSubsidyMoney = platOrderGoodsDiscountMoney + order.SelfDeliveryDiscountMoney - sku.PmSubsidyMoney
sku.JxSubsidyMoney = order.JxSubsidyMoney - sku.JxSubsidyMoney
sku.PmDeductionsMoney = deductionsByPm - sku.PmDeductionsMoney
sku.ShopMoneyByCal = order.ShopMoney - sku.ShopMoneyByCal
sku.JxDeductionsMoney = deductionsByJx - sku.JxDeductionsMoney
sku.JxShopMoney = order.JxShopMoney - sku.JxShopMoney
if err = dao.CreateEntity(db, sku); err != nil {
if !dao.IsDuplicateError(err) {
globals.SugarLogger.Warnf("On SaveOrderSkuFinancialInfo order.VendorOrderID:%s err:%v", order.VendorOrderID, err)
return err
}
dao.Rollback(db, txDB)
return nil
}
} else {
globals.SugarLogger.Warnf("On SaveOrderSkuFinancialInfo order.VendorOrderID:%s err: order have no sku", order.VendorOrderID)
}
// 加上京西对单条sku的补贴再存数据库
order.JxSubsidyMoney += order.JxSkuSubsidyMoney
if err = dao.CreateEntity(db, order); err != nil {
if !dao.IsDuplicateError(err) {
globals.SugarLogger.Warnf("On SaveOrderFinancialInfo order.VendorOrderID:%s err: order is err", order.VendorOrderID)
return err
}
dao.Rollback(db, txDB)
return nil
}
dao.Commit(db, txDB)
return err
}
// 处理售后订单结账信息
func (c *OrderManager) SaveAfsOrderFinancialInfo(afsOrder *model.AfsOrder) (err error) {
globals.SugarLogger.Debug(afsOrder.AfsOrderID)
db := dao.GetDB()
txDB , _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil || err != nil {
dao.Rollback(db, txDB)
if r != nil {
panic(r)
}
}
}()
// 平台结算扣除汇总--平台补贴,售后产生运费,平台收包装费,同城运费、、、
deductionsByPm := afsOrder.PmSubsidyMoney + afsOrder.AfsFreightMoney + afsOrder.BoxMoney + afsOrder.TongchengFreightMoney
afsOrder.RefundMoneyByCal = afsOrder.SkuUserMoney + afsOrder.FreightUserMoney + deductionsByPm - afsOrder.PmRefundMoney
// order.TotalMoney += order.SkuJxMoney // 退款单京西补贴部分先不作计算
if err = dao.CreateEntity(db, afsOrder); err != nil {
if !dao.IsDuplicateError(err) {
globals.SugarLogger.Warnf("On SaveAfsOrderFinancialInfo afsOrder.AfsOrderID:%s err: SaveAfsOrder is err", afsOrder.AfsOrderID)
return err
}
dao.Rollback(db, txDB)
return nil
}
// 京西结算扣除汇总,先不作计算,计算单条sku最终扣款金额+该条sku承担的平台结算扣除金额
for _, orderSku := range afsOrder.Skus[1:] {
orderSku.RefundMoneyByCal = orderSku.PmSkuSubsidyMoney +
utils.Float64TwoInt64(float64(afsOrder.RefundMoneyByCal-afsOrder.PmSkuSubsidyMoney)*float64(orderSku.UserMoney+orderSku.PmSubsidyMoney-orderSku.PmSkuSubsidyMoney)/float64(afsOrder.SkuUserMoney+afsOrder.PmSubsidyMoney-afsOrder.PmSkuSubsidyMoney))
afsOrder.Skus[0].RefundMoneyByCal += orderSku.RefundMoneyByCal
if err = dao.CreateEntity(db, orderSku); err != nil {
if !dao.IsDuplicateError(err) {
globals.SugarLogger.Warnf("On SaveAfsOrderFinancialInfo afsOrder.AfsOrderID:%s err: SaveAfsOrderSku is err", afsOrder.AfsOrderID)
return err
}
dao.Rollback(db, txDB)
return nil
}
}
if len(afsOrder.Skus) > 0 {
orderSku := afsOrder.Skus[0]
orderSku.RefundMoneyByCal = afsOrder.RefundMoneyByCal - orderSku.RefundMoneyByCal
if err = dao.CreateEntity(db, orderSku); err != nil {
if !dao.IsDuplicateError(err) {
globals.SugarLogger.Warnf("On SaveAfsOrderFinancialInfo afsOrder.AfsOrderID:%s err: SaveAfsOrderSku is err", afsOrder.AfsOrderID)
return err
}
dao.Rollback(db, txDB)
return nil
}
} else {
globals.SugarLogger.Warnf("On SaveAfsOrderFinancialInfo afsOrder.AfsOrderID:%s err: afsOrder have no sku", afsOrder.AfsOrderID)
}
dao.Commit(db, txDB)
return err
}
// 转自送实际使用美团/达达配送,调用此方法
func (c *OrderManager) UpdataOrderFinancialInfo(orderFinancial *model.OrderFinancial, wayBill *model.Waybill) (err error) {
// 通过本地数据库去取是否转美团/达达,并计算运费,写在上级调用函数里面传递过来
// wayBill, err2 := partner.CurOrderManager.LoadWaybill(orderFinancial.VendorOrderID, orderFinancial.VendorID)
// if err = err2; err == nil {
// orderFinancial.JxFreightMoney = wayBill.DesiredFee
// }
db := dao.GetDB()
txDB , _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil || err != nil {
dao.Rollback(db, txDB)
if r != nil {
panic(r)
}
}
}()
orderFinancial.JxFreightMoney = wayBill.DesiredFee
if (orderFinancial.JxFreightMoney - orderFinancial.SelfDeliveryDiscountMoney) > MaxFreightMoneyFromJxByShop {
orderFinancial.JxFreightMoneyByShop = orderFinancial.SelfDeliveryDiscountMoney + MaxFreightMoneyFromJxByShop
} else if (orderFinancial.JxFreightMoney - orderFinancial.SelfDeliveryDiscountMoney) < 0 {
orderFinancial.JxFreightMoneyByShop = orderFinancial.SelfDeliveryDiscountMoney
} else {
orderFinancial.JxFreightMoneyByShop = orderFinancial.JxFreightMoney
}
orderFinancial.JxShopMoney -= orderFinancial.JxFreightMoneyByShop
// orderFinancial.JxFreightMoneyByShop 的改变直接影响到单条sku的京西结算金额的改变
jxDecMoney := orderFinancial.JxFreightMoneyByShop
for _, sku := range orderFinancial.Skus[1:] {
// 重新计算单条sku京西应该结算的金额
skuJxDecMoney := utils.Float64TwoInt64(float64(jxDecMoney*sku.SalePrice*int64(sku.Count)+sku.SkuBoxMoney) / float64(orderFinancial.SalePriceMoney+orderFinancial.SkuBoxMoney))
sku.JxDeductionsMoney += skuJxDecMoney
sku.JxShopMoney -= skuJxDecMoney
jxDecMoney -= skuJxDecMoney
if _, err = dao.UpdateEntity(db, sku); err != nil {
return err
}
}
if len(orderFinancial.Skus) > 0 {
sku := orderFinancial.Skus[0]
sku.JxDeductionsMoney += jxDecMoney
sku.JxShopMoney -= jxDecMoney
if _, err = dao.UpdateEntity(db, sku); err != nil {
return err
}
}
if err = dao.CreateEntity(db, orderFinancial); err != nil {
globals.SugarLogger.Warnf("On SaveOrderFinancialInfo err: order is err")
return err
}
dao.Commit(db, txDB)
// orderFinancial 和 OrderSkuFinancial 数据计算完毕,准备进行更新
return err
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,440 +0,0 @@
package orderman
import (
"strings"
"time"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxcallback/scheduler"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/globals"
"github.com/astaxie/beego/client/orm"
)
func (c *OrderManager) LoadAfsOrder(vendorAfsOrderID string, vendorID int) (afsOrder *model.AfsOrder, err error) {
return c.loadAfsOrder(dao.GetDB(), vendorAfsOrderID, vendorID)
}
func (c *OrderManager) loadAfsOrder(db *dao.DaoDB, vendorAfsOrderID string, vendorID int) (afsOrder *model.AfsOrder, err error) {
afsOrder = &model.AfsOrder{
AfsOrderID: vendorAfsOrderID,
VendorID: vendorID,
}
if err = dao.GetEntity(db, afsOrder, "AfsOrderID", "VendorID"); err != nil {
afsOrder = nil
}
return afsOrder, err
}
func (c *OrderManager) OnAfsOrderAdjust(afsOrder *model.AfsOrder, orderStatus *model.OrderStatus) (err error) {
return c.onAfsOrderNew(afsOrder, orderStatus, true)
}
func (c *OrderManager) OnAfsOrderNew(afsOrder *model.AfsOrder, orderStatus *model.OrderStatus) (err error) {
return c.onAfsOrderNew(afsOrder, orderStatus, false)
}
func (c *OrderManager) onAfsOrderNew(afsOrder *model.AfsOrder, orderStatus *model.OrderStatus, isAdjust bool) (err error) {
db := dao.GetDB()
globals.SugarLogger.Debugf("onAfsOrderNew1 orderID:%s", afsOrder.VendorOrderID)
c.setAfsOrderID(db, orderStatus)
if afsOrder.AfsOrderID == "" {
afsOrder.AfsOrderID = orderStatus.VendorOrderID
}
if afsOrder.VendorStatus == "" {
afsOrder.VendorStatus = orderStatus.VendorStatus
}
if afsOrder.Status == model.OrderStatusUnknown {
afsOrder.Status = orderStatus.Status
}
globals.SugarLogger.Debugf("onAfsOrderNew2 orderID:%s", afsOrder.VendorOrderID)
//
if order, _ := c.LoadOrder(afsOrder.VendorOrderID, afsOrder.VendorID); order != nil {
if order.ConsigneeMobile2 == "" {
if handler := partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID); handler != nil {
if order2, _ := handler.GetOrder(order.VendorOrgCode, order.VendorOrderID, order.VendorStoreID); order2 != nil && order.ConsigneeMobile != order2.ConsigneeMobile {
order.ConsigneeMobile = order2.ConsigneeMobile
c.UpdateOrderFields(order, []string{"ConsigneeMobile"})
}
}
}
}
//
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil || err != nil {
dao.Rollback(db, txDB)
panic(r)
}
}()
isDuplicated, err := addOrderOrWaybillStatus(orderStatus, db)
globals.SugarLogger.Debugf("onAfsOrderNew afsOrderID:%s, isDuplicated:%t", afsOrder.AfsOrderID, isDuplicated)
if err != nil || isDuplicated {
if err == nil {
dao.Commit(db, txDB)
}
return err
}
var existAfsOrder *model.AfsOrder
if existAfsOrder, err = c.loadAfsOrder(db, afsOrder.AfsOrderID, afsOrder.VendorID); err != nil {
if !dao.IsNoRowsError(err) {
return err
}
}
if existAfsOrder != nil {
// todo 可能导致状态回绕
existAfsOrder.Status = afsOrder.Status
existAfsOrder.VendorStatus = afsOrder.VendorStatus
if _, err = dao.UpdateEntity(db, existAfsOrder, "Status", "VendorStatus"); err != nil {
return err
}
afsOrder = existAfsOrder
} else {
// 全退都要先全删除再建
if afsOrder.RefundType == model.AfsTypeFullRefund {
isAdjust = true
}
if err = c.SaveAfsOrder(db, afsOrder, isAdjust); err != nil {
return err
}
}
dao.Commit(db, txDB)
scheduler.CurrentScheduler.OnAfsOrderNew(afsOrder, false)
return err
}
func (c *OrderManager) SaveAfsOrder(db *dao.DaoDB, afsOrder *model.AfsOrder, isDeleteFirst bool) (err error) {
globals.SugarLogger.Debug(afsOrder.AfsOrderID)
if db == nil {
db = dao.GetDB()
}
if err = c.updateAfsOrderOtherInfo(db, afsOrder); err != nil {
return err
}
globals.SugarLogger.Debugf("SaveAfsOrder afsorder :%v", utils.Format4Output(afsOrder, true))
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil || err != nil {
dao.Rollback(db, txDB)
if r != nil {
panic(r)
}
}
}()
if isDeleteFirst {
err = utils.CallFuncLogError(func() error {
_, err = dao.DeleteEntity(db, afsOrder, "VendorOrderID", "VendorID")
return err
}, "SaveAfsOrder delete AfsOrder, afsOrderID:%s", afsOrder.AfsOrderID)
if err != nil {
return err
}
err = utils.CallFuncLogError(func() error {
_, err = dao.DeleteEntity(db, &model.OrderSkuFinancial{
VendorOrderID: afsOrder.VendorOrderID,
VendorID: afsOrder.VendorID,
IsAfsOrder: 1,
}, "VendorOrderID", "VendorID", "IsAfsOrder")
return err
}, "SaveAfsOrder delete OrderSkuFinancial, afsOrderID:%s", afsOrder.AfsOrderID)
if err != nil {
return err
}
}
// 平台结算扣除汇总--平台补贴,售后产生运费,平台收包装费,同城运费、、、
deductionsByPm := afsOrder.PmSubsidyMoney + afsOrder.AfsFreightMoney + afsOrder.BoxMoney + afsOrder.TongchengFreightMoney
afsOrder.RefundMoneyByCal = afsOrder.SkuUserMoney + afsOrder.FreightUserMoney + deductionsByPm - afsOrder.PmRefundMoney
// order.TotalMoney += order.SkuJxMoney // 退款单京西补贴部分先不作计算
if err = dao.CreateEntity(db, afsOrder); err != nil {
globals.SugarLogger.Warnf("On SaveAfsOrder afsOrder.AfsOrderID:%s err:%v", afsOrder.AfsOrderID, err)
return err
}
// 京西结算扣除汇总,先不作计算,计算单条sku最终扣款金额+该条sku承担的平台结算扣除金额
for _, orderSku := range afsOrder.Skus[1:] {
orderSku.RefundMoneyByCal = orderSku.PmSkuSubsidyMoney +
utils.Float64TwoInt64(float64(afsOrder.RefundMoneyByCal-afsOrder.PmSkuSubsidyMoney)*float64(orderSku.UserMoney+orderSku.PmSubsidyMoney-orderSku.PmSkuSubsidyMoney)/float64(afsOrder.SkuUserMoney+afsOrder.PmSubsidyMoney-afsOrder.PmSkuSubsidyMoney))
afsOrder.Skus[0].RefundMoneyByCal += orderSku.RefundMoneyByCal
if err = dao.CreateEntity(db, orderSku); err != nil {
globals.SugarLogger.Warnf("On SaveAfsOrder afsOrder.AfsOrderID:%s err:%v, orderSku:%s", afsOrder.AfsOrderID, err, utils.Format4Output(orderSku, true))
return err
}
}
if len(afsOrder.Skus) > 0 {
orderSku := afsOrder.Skus[0]
orderSku.RefundMoneyByCal = afsOrder.RefundMoneyByCal - orderSku.RefundMoneyByCal
if err = dao.CreateEntity(db, orderSku); err != nil {
globals.SugarLogger.Warnf("On SaveAfsOrder afsOrder.AfsOrderID:%s err:%v, orderSku:%s", afsOrder.AfsOrderID, err, utils.Format4Output(orderSku, true))
return err
}
} else {
globals.SugarLogger.Warnf("On SaveAfsOrder afsOrder.AfsOrderID:%s err: afsOrder have no sku", afsOrder.AfsOrderID)
}
dao.Commit(db, txDB)
return err
}
func (c *OrderManager) OnAfsOrderStatusChanged(orderStatus *model.OrderStatus) (err error) {
db := dao.GetDB()
c.setAfsOrderID(db, orderStatus)
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, txDB)
panic(r)
}
}()
isDuplicated, afsOrder, err := c.addAfsOrderStatus(db, orderStatus)
if err != nil || isDuplicated {
if err == nil {
dao.Commit(db, txDB)
} else {
dao.Rollback(db, txDB)
}
return err
}
dao.Commit(db, txDB)
scheduler.CurrentScheduler.OnAfsOrderStatusChanged(afsOrder, orderStatus, false)
return err
}
func (c *OrderManager) addAfsOrderStatus(db *dao.DaoDB, orderStatus *model.OrderStatus) (isDuplicated bool, order *model.AfsOrder, err error) {
globals.SugarLogger.Debugf("addAfsOrderStatus refOrderID:%s, orderID:%s", orderStatus.RefVendorOrderID, orderStatus.VendorOrderID)
if db == nil {
db = dao.GetDB()
}
isDuplicated, err = addOrderOrWaybillStatus(orderStatus, db)
if err == nil && !isDuplicated && (orderStatus.Status != model.OrderStatusUnknown && orderStatus.Status != model.OrderStatusMsg) {
order = &model.AfsOrder{
AfsOrderID: orderStatus.VendorOrderID,
VendorID: orderStatus.VendorID,
}
if err = db.Db.ReadForUpdate(order, "AfsOrderID", "VendorID"); err == nil {
if orderStatus.Status > model.OrderStatusUnknown { // todo 要求status不能回绕
order.VendorStatus = orderStatus.VendorStatus
order.Status = orderStatus.Status
updateFields := []string{
"VendorStatus",
"Status",
}
if model.IsAfsOrderFinalStatus(orderStatus.Status) {
order.AfsFinishedAt = orderStatus.StatusTime
if utils.IsTimeZero(order.AfsFinishedAt) {
order.AfsFinishedAt = time.Now()
}
updateFields = append(updateFields, "AfsFinishedAt")
if handler := partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID); handler != nil {
if orderAfsInfo, err := handler.GetOrderAfsInfo(nil, order.VendorOrderID, order.AfsOrderID); err == nil && orderAfsInfo.AfsTotalShopMoney != 0 {
order.AfsTotalShopMoney = orderAfsInfo.AfsTotalShopMoney
}
updateFields = append(updateFields, "AfsTotalShopMoney")
}
}
utils.CallFuncLogError(func() error {
_, err = dao.UpdateEntity(db, order, updateFields...)
return err
}, "addAfsOrderStatus update orderID:%s, status:%v", order.VendorOrderID, orderStatus)
} else {
isDuplicated = true
}
} else {
if dao.IsNoRowsError(err) { // todo 消息错序
err = nil
} else {
globals.SugarLogger.Warnf("addAfsOrderStatus orderID:%s read failed with error:%v", order.VendorOrderID, err)
}
}
}
return isDuplicated, order, err
}
func (c *OrderManager) updateAfsOrderSkuOtherInfo(db *dao.DaoDB, order *model.AfsOrder) (err error) {
globals.SugarLogger.Debugf("updateAfsOrderSkuOtherInfo orderID:%s, VendorStoreID:%s", order.VendorOrderID, order.VendorStoreID)
jxStoreID := jxutils.GetSaleStoreIDFromAfsOrder(order)
opNumStr := "2"
if jxStoreID == 0 {
globals.SugarLogger.Infof("updateAfsOrderSkuOtherInfo [运营%s]订单在京西与平台都找不到京西门店信息orderID:%s, VendorStoreID:%s", opNumStr, order.VendorOrderID, order.VendorStoreID)
return nil
}
orderSkus := order.Skus
var vendorSkuIDs []string
skuIDMap := make(map[int]int)
for _, v := range orderSkus {
if v.VendorSkuID != "" {
vendorSkuIDs = append(vendorSkuIDs, v.VendorSkuID)
}
if skuID := jxutils.GetSkuIDFromOrderSkuFinancial(v); skuID > 0 {
skuIDMap[skuID] = 1
}
}
if len(vendorSkuIDs) > 0 {
var vendorStoreID string
if order.VendorID == model.VendorIDJDShop {
vendorStoreID = model.JdShopMainVendorStoreID
} else {
vendorStoreID = order.VendorStoreID
}
l, err := dao.GetStoreSkuPriceAndWeight(db, vendorStoreID, order.VendorID, vendorSkuIDs)
if err != nil {
globals.SugarLogger.Warnf("updateAfsOrderSkuOtherInfo orderID:%s failed with err:%v", order.VendorOrderID, err)
return err
}
skumapper := storeSkuPriceAndWeight2Map(l)
var actStoreSkuMap *jxutils.ActStoreSkuMap
if len(skuIDMap) > 0 {
if order2, err2 := c.LoadOrder(order.VendorOrderID, order.VendorID); err2 == nil {
actStoreSkuList, err := dao.GetEffectiveActStoreSkuInfo(db, 0, []int{order.VendorID}, model.ActTypeAll, []int{jxStoreID}, jxutils.IntMap2List(skuIDMap), order2.OrderCreatedAt, order2.OrderCreatedAt)
if err != nil {
globals.SugarLogger.Errorf("updateAfsOrderSkuOtherInfo can not get sku promotion info for error:%v", err)
return err
}
actStoreSkuMap = jxutils.NewActStoreSkuMap(actStoreSkuList, false)
}
}
for _, v := range orderSkus {
v.AfsOrderID = order.AfsOrderID
v.VendorID = order.VendorID
v.VendorOrderID = order.VendorOrderID
v.IsAfsOrder = 1
v.VendorStoreID = order.VendorStoreID
v.StoreID = order.StoreID
v.JxStoreID = jxStoreID
intVendorSkuID := utils.Str2Int64WithDefault(v.VendorSkuID, 0)
if intVendorSkuID != 0 && v.VendorSkuID != "-70000" { // todo hard code
skuBindInfo := skumapper[v.VendorSkuID]
if skuBindInfo == nil {
globals.SugarLogger.Infof("updateAfsOrderSkuOtherInfo [运营%s]%s订单sku找不到门店价格或商品映射orderID:%s, StoreID:%d, VendorSkuID:%s, sku:%v", opNumStr, model.VendorChineseNames[order.VendorID], order.VendorOrderID, jxStoreID, v.VendorSkuID, v)
} else {
v.JxSkuID = skuBindInfo.SkuID
v.ShopPrice = int64(skuBindInfo.Price)
}
}
if actStoreSkuMap != nil {
if skuID := jxutils.GetSkuIDFromOrderSkuFinancial(v); skuID > 0 && v.StoreSubName != "" {
if actStoreSku := actStoreSkuMap.GetActStoreSku(jxStoreID, skuID, order.VendorID); actStoreSku != nil {
v.StoreSubID = actStoreSku.ActID
}
}
}
}
}
return nil
}
func (c *OrderManager) updateAfsOrderOtherInfo(db *dao.DaoDB, afsOrder *model.AfsOrder) (err error) {
globals.SugarLogger.Debugf("updateAfsOrderOtherInfo orderID:%s, VendorStoreID:%s", afsOrder.VendorOrderID, afsOrder.VendorStoreID)
if afsOrder.VendorStoreID != "" {
if storeDetail, err := dao.GetStoreDetailByVendorStoreID(db, afsOrder.VendorStoreID, 0, ""); err == nil {
afsOrder.JxStoreID = storeDetail.Store.ID
}
}
if afsOrder.StoreID == 0 && afsOrder.JxStoreID == 0 {
if order, err2 := c.LoadOrder(afsOrder.VendorOrderID, afsOrder.VendorID); err2 == nil {
afsOrder.JxStoreID = order.JxStoreID
if afsOrder.StoreID == 0 {
afsOrder.StoreID = order.StoreID
}
if afsOrder.VendorStoreID == "" {
afsOrder.VendorStoreID = order.VendorStoreID
}
}
}
if err == nil {
if handler := partner.GetPurchaseOrderHandlerFromVendorID(afsOrder.VendorID); handler != nil {
if orderAfsInfo, err := handler.GetOrderAfsInfo(nil, afsOrder.VendorOrderID, afsOrder.AfsOrderID); err == nil && orderAfsInfo.AfsTotalShopMoney != 0 {
afsOrder.AfsTotalShopMoney = orderAfsInfo.AfsTotalShopMoney
}
}
if err = c.updateAfsOrderSkuOtherInfo(db, afsOrder); err == nil {
jxutils.RefreshAfsOrderSkuRelated(afsOrder)
}
}
return err
}
func (c *OrderManager) UpdateAfsOrderFields(afsOrder *model.AfsOrder, fieldList []string) (err error) {
db := orm.NewOrm()
utils.CallFuncLogError(func() error {
_, err = db.Update(afsOrder, fieldList...)
return err
}, "UpdateAfsOrderFields orderID:%s failed with error:%v", afsOrder.VendorOrderID, err)
return err
}
func (c *OrderManager) setAfsOrderID(db *dao.DaoDB, orderStatus *model.OrderStatus) {
// globals.SugarLogger.Debugf("setAfsOrderID1 orderStatus:%v", utils.Format4Output(orderStatus, true))
if dao.IsVendorThingIDEmpty(orderStatus.VendorOrderID) {
index := 1
if afsOrderList, err2 := dao.GetAfsOrders(db, orderStatus.RefVendorID, orderStatus.RefVendorOrderID, ""); err2 == nil {
if len(afsOrderList) > 0 {
list := strings.Split(afsOrderList[0].AfsOrderID, "-")
if len(list) > 1 {
index = int(utils.Str2Int64WithDefault(list[1], 0))
if afsOrderList[0].Status >= model.AfsOrderStatusFinished {
index++
}
}
}
} else {
globals.SugarLogger.Warnf("setAfsOrderID err2:%v", err2)
}
orderStatus.VendorOrderID = composeAfsOrderID(orderStatus.RefVendorOrderID, index)
}
// globals.SugarLogger.Debugf("setAfsOrderID2 orderStatus:%v", utils.Format4Output(orderStatus, true))
}
func composeAfsOrderID(vendorOrderID string, index int) (afsOrderID string) {
return strings.Join([]string{
vendorOrderID,
utils.Int2Str(index),
}, "-")
}
func (c *OrderManager) CreateAfsOrderFromOrder(vendorOrderID string, vendorID int) (afsOrder *model.AfsOrder, err error) {
order, err := c.LoadOrder(vendorOrderID, vendorID)
// globals.SugarLogger.Debug(utils.Format4Output(order, false))
if err == nil {
afsOrder = &model.AfsOrder{
VendorID: vendorID,
VendorOrderID: vendorOrderID,
JxStoreID: order.JxStoreID,
VendorStoreID: order.VendorStoreID,
StoreID: order.StoreID,
VendorOrgCode: order.VendorOrgCode,
}
} else {
globals.SugarLogger.Warnf("CreateAfsOrderFromOrder, orderID:%s is not found from partner.CurOrderManager.LoadOrder", vendorOrderID)
return nil, err
}
for _, sku := range order.Skus {
orderSkuFinancial := &model.OrderSkuFinancial{
VendorID: sku.VendorID,
VendorOrderID: sku.VendorOrderID,
// OrderFinancialID: sku.VendorOrderID,
// ConfirmTime: afsOrder.AfsCreateAt,
VendorStoreID: afsOrder.VendorStoreID,
StoreID: afsOrder.StoreID,
JxStoreID: afsOrder.JxStoreID,
VendorSkuID: sku.VendorSkuID,
SkuID: sku.SkuID,
PromotionType: sku.PromotionType,
Name: sku.SkuName,
ShopPrice: sku.ShopPrice,
SalePrice: sku.SalePrice,
Count: sku.Count,
// UserMoney: sku.UserMoney,
// PmSubsidyMoney: sku.PmSubsidyMoney,
IsAfsOrder: 1,
}
afsOrder.Skus = append(afsOrder.Skus, orderSkuFinancial)
}
return afsOrder, nil
}

View File

@@ -1,213 +0,0 @@
package orderman
import (
"fmt"
"math/rand"
"time"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/jxutils/weixinmsg"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/business/model/legacymodel"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/globals"
)
const (
COMMENT_NOT_RESOLVED = 0 //未解决的差评状态
COMMENT_RESOLVED = 1 //已解决的差评状态
JX_BAD_COMMENTS_MAX_LEVEL = 2 // 差评最大分
JX_MIDDLE_COMMENTS_MAX_LEVEL = 4 // 中评最大分
COMMENTS_SCORE_ONE_ORTWO_BEGIN_DELAY_TIME = 1 * 60 //评论回复一星或二星回复延迟开始时间区间
COMMENTS_SCORE_ONE_ORTWO_END_DELAY_TIME = 3 * 60 //评论回复一星或二星回复延迟结束时间区间
COMMENTS_SCORE_THREE_BEGIN_DELAY_TIME = 2 * 60 //评论回复三星回复延迟开始时间区间
COMMENTS_SCORE_THREE_END_DELAY_TIME = 4 * 60 //评论回复三星回复延迟结束时间区间
COMMENTS_SCORE_FOUR_ORFIVE_BEGIN_DELAY_TIME = 2 * 60 //评论回复四星或五星回复延迟开始时间区间
COMMENTS_SCORE_FOUR_ORFIVE_END_DELAY_TIME = 5 * 60 //评论回复四星或五星回复延迟结束时间区间
MAX_REAPLY_TIME = 18 * time.Hour
)
type tReplyConfig struct {
delayGapBegin int
delayGapEnd int
comments []string
}
var (
replyConfig = map[int]*tReplyConfig{
1: &tReplyConfig{
delayGapBegin: COMMENTS_SCORE_ONE_ORTWO_BEGIN_DELAY_TIME,
delayGapEnd: COMMENTS_SCORE_ONE_ORTWO_END_DELAY_TIME,
comments: []string{
"非常抱歉让您没有得到十分满意的购物体验,我们会及时与您联系进行确认并解决问题!",
},
},
3: &tReplyConfig{
delayGapBegin: COMMENTS_SCORE_THREE_BEGIN_DELAY_TIME,
delayGapEnd: COMMENTS_SCORE_THREE_END_DELAY_TIME,
comments: []string{
"感谢您对我们的肯定,祝您生活愉快!欢迎再次光临,谢谢!",
fmt.Sprintf("感谢您对%s的关照我们会更加精益求精。", globals.StoreName),
"感谢您的光临,您的支持是我们前进的动力!",
},
},
4: &tReplyConfig{
delayGapBegin: COMMENTS_SCORE_FOUR_ORFIVE_BEGIN_DELAY_TIME,
delayGapEnd: COMMENTS_SCORE_FOUR_ORFIVE_END_DELAY_TIME,
comments: []string{
"感谢您的信赖!我们会不断提升菜品质量以及优质的服务,期待与您的再次相遇!",
"感谢您的支持,愿您天天好心情!",
"感谢您的认可!您的支持是我们前进的动力。",
"感谢您的肯定与支持!我们会坚持把最好的服务带给您,期待和您的再次相遇!",
},
},
}
)
func (c *OrderManager) OnOrderComments(orderCommentList []*model.OrderComment) (err error) {
globals.SugarLogger.Debug("OnOrderComments")
db := dao.GetDB()
for _, orderComment := range orderCommentList {
globals.SugarLogger.Debugf("OnOrderComments, orderID:%s", orderComment.VendorOrderID)
comment2 := &legacymodel.JxBadComments{
OrderId: orderComment.VendorOrderID,
}
err = dao.GetEntity(db, comment2, "OrderId")
if err == nil || dao.IsNoRowsError(err) {
isNewComment := false
if dao.IsNoRowsError(err) {
err = nil
isNewComment = true
if orderComment.IsReplied == 0 && time.Now().Sub(orderComment.CommentCreatedAt) < time.Duration(orderComment.ModifyDuration)*time.Hour {
if storeDetail, err2 := dao.GetStoreDetail(db, orderComment.StoreID, orderComment.VendorID, ""); err2 == nil {
if storeDetail.AutoReplyType == model.AutoReplyAll ||
orderComment.Score > JX_BAD_COMMENTS_MAX_LEVEL && storeDetail.AutoReplyType == model.AutoReplyGoodComment {
c.replyOrderComment(storeDetail.VendorOrgCode, orderComment)
}
}
}
}
if isNewComment /*&& orderComment.Score <= JX_BAD_COMMENTS_MAX_LEVEL*/ || !isNewComment && orderComment.Score > JX_BAD_COMMENTS_MAX_LEVEL { // 如果是直接非差评,或补评仍然是差评,忽略
if isNewComment {
comment2.Createtime = utils.Time2Str(orderComment.CommentCreatedAt)
comment2.Score = int(orderComment.Score)
comment2.Scorecontent = orderComment.Content
comment2.Vendertags = orderComment.TagList
comment2.Msg = orderComment.OriginalMsg
comment2.Status = COMMENT_NOT_RESOLVED
comment2.OrderFlag = utils.Int2Str(orderComment.VendorID)
comment2.Maxmodifytime = int(orderComment.ModifyDuration)
order, _ := partner.CurOrderManager.LoadOrder(orderComment.VendorOrderID, orderComment.VendorID)
if order != nil {
orderComment.StoreID = jxutils.GetSaleStoreIDFromOrder(order)
if order.ConsigneeMobile2 != "" {
orderComment.ConsigneeMobile = order.ConsigneeMobile2
} else {
if handler := partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID); handler != nil {
if order2, _ := handler.GetOrder(order.VendorOrgCode, order.VendorOrderID, order.VendorStoreID); order2 != nil && order.ConsigneeMobile != order2.ConsigneeMobile {
order.ConsigneeMobile = order2.ConsigneeMobile
partner.CurOrderManager.UpdateOrderFields(order, []string{"ConsigneeMobile"})
}
}
orderComment.ConsigneeMobile = order.ConsigneeMobile
}
} else {
if storeDetail, err := dao.GetStoreDetailByVendorStoreID(db, orderComment.VendorStoreID, orderComment.VendorID, ""); err == nil {
orderComment.StoreID = storeDetail.ID
}
}
if orderComment.StoreID > 0 {
comment2.Jxstoreid = utils.Int2Str(orderComment.StoreID)
}
comment2.Userphone = orderComment.ConsigneeMobile
if comment2.Jxstoreid != "" && orderComment.Score <= JX_MIDDLE_COMMENTS_MAX_LEVEL && time.Now().Sub(orderComment.CommentCreatedAt) < MAX_REAPLY_TIME {
comment2.LastPushTime = utils.Time2Str(time.Now())
comment2.PushNo = 1
weixinmsg.PushJDBadCommentToWeiXin(comment2, orderComment.Score <= JX_BAD_COMMENTS_MAX_LEVEL, order)
}
} else { // 修改评价高于JX_BAD_COMMENTS_MAX_LEVEL
if orderComment.CommentCreatedAt.Sub(str2Time(comment2.Createtime)) == 0 ||
orderComment.CommentCreatedAt.Sub(str2Time(comment2.Updatetime)) == 0 {
comment2 = nil // 重复
} else {
comment2.Updatetime = utils.Time2Str(orderComment.CommentCreatedAt)
comment2.UpdatedMsg = orderComment.OriginalMsg
comment2.UpdatedScore = int(orderComment.Score)
comment2.UpdatedScorecontent = orderComment.Content
comment2.UpdatedVendertags = orderComment.TagList
comment2.Status = COMMENT_RESOLVED
if comment2.Jxstoreid != "" && orderComment.Score <= JX_MIDDLE_COMMENTS_MAX_LEVEL && time.Now().Sub(orderComment.CommentCreatedAt) < MAX_REAPLY_TIME {
comment2.LastPushTime = utils.Time2Str(time.Now())
comment2.PushNo++
comment3 := *comment2
comment3.Createtime = comment2.Updatetime
comment3.Score = comment2.UpdatedScore
comment3.Scorecontent = comment2.UpdatedScorecontent
comment3.Vendertags = comment2.UpdatedVendertags
order, _ := partner.CurOrderManager.LoadOrder(orderComment.VendorOrderID, orderComment.VendorID)
weixinmsg.PushJDBadCommentToWeiXin(&comment3, orderComment.Score <= JX_BAD_COMMENTS_MAX_LEVEL, order)
}
}
}
if err == nil {
if isNewComment {
err = dao.CreateEntity(db, comment2)
} else if comment2 != nil {
_, err = dao.UpdateEntity(db, comment2)
}
}
}
}
if err != nil {
globals.SugarLogger.Warnf("OnOrderComments orderID:%s failed with error:%v", orderComment.VendorOrderID, err)
break
}
}
return err
}
func (c *OrderManager) replyOrderComment(vendorOrgCode string, orderComment *model.OrderComment) (err error) {
score := int(orderComment.Score)
if score <= 2 {
score = 1
} else if score >= 5 {
score = 4
}
config := replyConfig[score]
delaySeconds := config.delayGapBegin + rand.Intn(config.delayGapEnd-config.delayGapBegin)
content := config.comments[rand.Intn(len(config.comments))]
globals.SugarLogger.Debugf("replyOrderComment orderID:%s, delaySeconds:%d, content:%s", orderComment.VendorOrderID, delaySeconds, content)
utils.AfterFuncWithRecover(time.Duration(delaySeconds)*time.Second, func() {
if handler := partner.GetPurchaseOrderHandlerFromVendorID(orderComment.VendorID); handler != nil {
if err = handler.ReplyOrderComment(jxcontext.AdminCtx, vendorOrgCode, orderComment, content); err != nil {
globals.SugarLogger.Debugf("replyOrderComment orderID:%s, error:%v", orderComment.VendorOrderID, err)
}
} else {
globals.SugarLogger.Warnf("replyOrderComment can not find handler orderID:%s", orderComment.VendorOrderID)
}
})
// todo 这里直接延时,可以导致服务器重启时漏掉回复,但如果用管理任务,又会导致大量评价任务存在与任务列表中
// task := tasksch.NewParallelTask(fmt.Sprintf("回复订单:%s评价", orderComment.VendorOrderID), nil, jxcontext.AdminCtx,
// func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
// return retVal, err
// }, []int{0})
// tasksch.HandleTask(task, nil, true).Run()
return err
}
func str2Time(timeStr string) time.Time {
if timeStr == "" {
return utils.DefaultTimeValue
}
return utils.Str2Time(timeStr)
}

View File

@@ -1,180 +0,0 @@
package orderman
import (
"errors"
"sort"
"time"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxcallback/scheduler"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/globals"
)
const (
pendingOrderGapMax = 2 * 24 * time.Hour // 每次重启机子时,要检查几天内的订单状态
maxTimeHandlePendingOrder = 2 * time.Second //处理pending order的最长时间
maxSleepGapHandlePendingOrder = 5 * time.Millisecond // 每个pending order的最长时间间隙
)
var (
ErrCanNotFindOrder = errors.New("找不到相应订单")
ErrCanNotFindWaybill = errors.New("找不到相应运单")
)
var (
FixedOrderManager *OrderManager
)
// 所有公共接口调用前要求在order里或status中设置合适的Status
type OrderManager struct {
}
func NewOrderManager() *OrderManager {
return &OrderManager{}
}
type IStatusTimer interface {
GetStatusTime() time.Time
}
type StatusTimerSlice []IStatusTimer
func (s StatusTimerSlice) Len() int {
return len(s)
}
func (s StatusTimerSlice) Less(i, j int) bool {
return s[i].GetStatusTime().Sub(s[j].GetStatusTime()) < 0
}
func (s StatusTimerSlice) Swap(i, j int) {
tmp := s[i]
s[i] = s[j]
s[j] = tmp
}
func init() {
FixedOrderManager = NewOrderManager()
partner.InitOrderManager(FixedOrderManager)
}
func addOrderOrWaybillStatus(status *model.OrderStatus, db *dao.DaoDB) (isDuplicated bool, err error) {
if status.OrderType == model.OrderTypeOrder {
globals.SugarLogger.Debugf("addOrderStatus order:%v", status)
} else if status.OrderType == model.OrderTypeWaybill {
globals.SugarLogger.Debugf("addOrderStatus waybill:%v", status)
} else {
globals.SugarLogger.Debugf("addOrderStatus afsOrder:%v", status)
}
txDB , _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil || err != nil {
globals.SugarLogger.Debug("rollback")
dao.Rollback(db, txDB)
if r != nil {
panic(r)
}
}
}()
status.ID = 0
status.Remark = utils.LimitUTF8StringLen(status.Remark, 255)
created, _, err := db.Db.ReadOrCreate(status, "VendorOrderID", "VendorID", "OrderType", "Status", "VendorStatus", "StatusTime")
if err == nil {
if !created {
globals.SugarLogger.Debugf("duplicated event:%v", status)
isDuplicated = true
status.DuplicatedCount++
utils.CallFuncLogError(func() error {
_, err = db.Db.Update(status, "DuplicatedCount")
return err
}, "addOrderOrWaybillStatus update DuplicatedCount, status:%v", status)
}
}
if err != nil {
// todo 这里居然会有主键重复错误,逻辑上是不应该的
globals.SugarLogger.Warnf("addOrderOrWaybillStatus status:%v, access db error:%v", status, err)
} else {
dao.Commit(db, txDB)
}
return isDuplicated, err
}
func (c *OrderManager) GetStatusDuplicatedCount(status *model.OrderStatus) (duplicatedCount int) {
if status == nil {
return 0
}
db := dao.GetDB()
if err := dao.GetEntity(db, status, "VendorOrderID", "VendorID", "OrderType", "VendorStatus", "StatusTime"); err == nil {
return status.DuplicatedCount
}
return 0
}
// todo 最好还是改成全事件回放算了
func LoadPendingOrders() {
orders, err := dao.LoadPendingOrders(dao.GetDB(), time.Now().Add(-pendingOrderGapMax), model.OrderStatusEndBegin)
globals.SugarLogger.Infof("LoadPendingOrders orders count:%d, err:%v", len(orders), err)
if err != nil {
return
}
ordersCount := len(orders)
if ordersCount > 0 {
bills := FixedOrderManager.LoadPendingWaybills()
globals.SugarLogger.Infof("LoadPendingOrders waybills count:%d", len(bills))
var sortOrders StatusTimerSlice
orderMap := make(map[string]*model.GoodsOrder)
for _, order := range orders {
if order.Status > model.OrderStatusNew {
status := model.Order2Status(order)
sortOrders = append(sortOrders, status)
}
// order.Status = model.OrderStatusNew // 就是要以实际order状态来调用scheduler.OnOrderNew
order.StatusTime = order.OrderCreatedAt
sortOrders = append(sortOrders, order)
orderMap[jxutils.ComposeUniversalOrderID(order.VendorOrderID, order.VendorID)] = order
}
for _, bill := range bills {
if bill.Status > model.WaybillStatusNew {
bill2 := *bill
sortOrders = append(sortOrders, &bill2)
}
bill.Status = model.WaybillStatusNew
bill.StatusTime = bill.WaybillCreatedAt
sortOrders = append(sortOrders, bill)
}
sort.Sort(sortOrders)
sleepGap := maxTimeHandlePendingOrder / time.Duration(ordersCount)
if sleepGap > maxSleepGapHandlePendingOrder {
sleepGap = maxSleepGapHandlePendingOrder
}
lastTime := time.Now()
for _, item := range sortOrders {
if order, ok := item.(*model.GoodsOrder); ok {
jxutils.CallMsgHandlerAsync(func() {
scheduler.CurrentScheduler.OnOrderNew(order, true, true)
}, jxutils.ComposeUniversalOrderID(order.VendorOrderID, order.VendorID))
} else if status, ok := item.(*model.OrderStatus); ok {
jxutils.CallMsgHandlerAsync(func() {
order := orderMap[jxutils.ComposeUniversalOrderID(status.VendorOrderID, status.VendorID)]
scheduler.CurrentScheduler.OnOrderStatusChanged(order, status, true)
}, jxutils.ComposeUniversalOrderID(status.RefVendorOrderID, status.RefVendorID))
} else {
bill := item.(*model.Waybill)
jxutils.CallMsgHandlerAsync(func() {
scheduler.CurrentScheduler.OnWaybillStatusChanged(bill, true)
}, jxutils.ComposeUniversalOrderID(bill.VendorOrderID, bill.OrderVendorID))
}
curTime := time.Now()
timeout := sleepGap - curTime.Sub(lastTime)
if timeout > 0 {
time.Sleep(timeout)
}
lastTime = curTime
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,17 +0,0 @@
package orderman
import (
"git.rosy.net.cn/jx-callback/globals/api2"
"git.rosy.net.cn/jx-callback/globals/testinit"
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/ebai"
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/elm"
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/jd"
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/mtwm"
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/weimob/wsc"
)
func init() {
testinit.Init()
api2.Init()
}

View File

@@ -1,271 +0,0 @@
package orderman
import (
"fmt"
"time"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/baseapi/platformapi/dadaapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxcallback/scheduler"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/globals"
"github.com/astaxie/beego/client/orm"
)
var (
waybillOrderStatusMap = map[int]int{
model.WaybillStatusApplyFailedGetGoods: model.OrderStatusApplyFailedGetGoods,
model.WaybillStatusAgreeFailedGetGoods: model.OrderStatusAgreeFailedGetGoods,
model.WaybillStatusRefuseFailedGetGoods: model.OrderStatusRefuseFailedGetGoods,
model.WaybillStatusDeliverFailed: model.OrderStatusDeliverFailed,
}
complaintReasonsMap = map[int]string{
1: "骑手态度恶劣",
2: "骑手接单后未取货",
3: "骑手取货太慢",
4: "骑手送货太慢",
5: "货品未送达",
6: "货品有损坏",
7: "骑手违规收取顾客其他费用",
69: "骑手恶意取消订单",
71: "骑手提前点击取货/送达",
}
)
func (w *OrderManager) LoadPendingWaybills() []*model.Waybill {
db := orm.NewOrm()
var bills []*model.Waybill
tillTime := time.Now().Add(-pendingOrderGapMax)
_, err := db.Raw(`
SELECT t1.*
FROM waybill t1
JOIN goods_order t2 ON t2.vendor_order_id = t1.vendor_order_id
AND t2.vendor_id = t1.order_vendor_id
AND t2.order_created_at >= ?
AND t2.status < ?
WHERE t1.waybill_created_at >= ?
AND t1.status < ?
`, tillTime, model.OrderStatusEndBegin, tillTime, model.WaybillStatusEndBegin).QueryRows(&bills)
if err != nil {
globals.SugarLogger.Warnf("LoadPendingWaybills load pending waybills error:%v", err)
return nil
}
return bills
}
func (w *OrderManager) onWaybillNew(bill2 *model.Waybill, db *dao.DaoDB) (isDuplicated bool, err error) {
globals.SugarLogger.Debugf("onWaybillNew bill:%v", bill2)
isDuplicated, err = addOrderOrWaybillStatus(model.Waybill2Status(bill2), db)
if err == nil && !isDuplicated {
bill2.ID = 0
bill2.WaybillCreatedAt = bill2.StatusTime
bill2.WaybillFinishedAt = utils.DefaultTimeValue
billCopied := *bill2
bill := &billCopied
created, _, err2 := db.Db.ReadOrCreate(bill, "VendorWaybillID", "WaybillVendorID")
if err = err2; err == nil {
if !created {
bill.DuplicatedCount++
if bill2.VendorOrderID == bill2.VendorWaybillID { // 购物平台(比如京东)重新建的运单,单号始终是与订单相同的
globals.SugarLogger.Infof("onWaybillNew duplicated1, DuplicatedCount:%d, bill:%v msg received", bill2.DuplicatedCount, bill2)
bill2.ID = bill.ID
bill2.CreatedAt = bill.CreatedAt
bill2.DuplicatedCount = bill.DuplicatedCount
err = utils.CallFuncLogError(func() error {
_, err = db.Db.Update(bill2) //更新所有字段
return err
}, "onWaybillNew Update1")
} else {
globals.SugarLogger.Infof("onWaybillNew duplicated2 DuplicatedCount:%d, bill:%v msg received", bill.DuplicatedCount, bill2)
isDuplicated = true
err = utils.CallFuncLogError(func() error {
_, err = db.Db.Update(bill, "DuplicatedCount")
return err
}, "onWaybillNew Update2")
}
} else {
*bill2 = *bill
globals.SugarLogger.Debugf("onWaybillNew created bill:%v", bill2)
}
} else {
globals.SugarLogger.Warnf("onWaybillNew create bill:%v, error:%v", bill2, err)
}
}
return isDuplicated, err
}
func (w *OrderManager) OnWaybillStatusChanged(bill *model.Waybill) (err error) {
var isDuplicated bool
if bill.ActualFee == 0 {
bill.ActualFee = bill.DesiredFee + bill.TipFee
}
bill.CourierMobile = jxutils.FormalizeMobile(bill.CourierMobile)
db := dao.GetDB()
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, txDB)
panic(r)
}
}()
duplicatedCount := 0
if bill.Status == model.WaybillStatusNew {
isDuplicated, err = w.onWaybillNew(bill, db)
if isDuplicated {
duplicatedCount = 1
}
} else {
existingBill, err2 := w.LoadWaybill(bill.VendorWaybillID, bill.WaybillVendorID)
// todo
if err2 == nil {
bill.DeliveryFlag = existingBill.DeliveryFlag
}
if bill.Status == model.WaybillStatusAccepted { // 处理美团配送丢失新运单消息的情况
if err2 != nil {
if dao.IsNoRowsError(err2) || err2 == ErrCanNotFindWaybill {
existingBill = bill
billCopy := *bill
billCopy.Status = model.WaybillStatusNew
if isDuplicated, err = w.onWaybillNew(&billCopy, db); err != nil {
dao.Rollback(db, txDB)
return err
}
dao.Commit(db, txDB)
// 进运单调度器OnWaybillStatusChanged之前要确保事务是提交了的否则会导致死锁
scheduler.CurrentScheduler.OnWaybillStatusChanged(&billCopy, false)
dao.Begin(db)
} else {
dao.Rollback(db, txDB)
return err2
}
}
// 运单消息错序,之前已经结束了,直接返回
if existingBill.Status >= model.WaybillStatusEndBegin {
dao.Commit(db, txDB)
return nil
}
}
addParams := orm.Params{}
if bill.Status >= model.WaybillStatusAccepted {
if bill.Status == model.WaybillStatusAccepted {
if bill.DesiredFee > 0 {
addParams["desired_fee"] = bill.DesiredFee
}
if bill.ActualFee > 0 {
addParams["actual_fee"] = bill.ActualFee
}
}
if bill.CourierMobile != "" {
addParams["courier_name"] = bill.CourierName
addParams["courier_mobile"] = bill.CourierMobile
}
if bill.Status >= model.WaybillStatusEndBegin {
addParams["waybill_finished_at"] = bill.StatusTime
}
}
duplicatedCount, err = w.addWaybillStatus(bill, db, addParams)
if err != nil {
dao.Rollback(db, txDB)
return err
}
}
if err == nil {
dao.Commit(db, txDB)
if duplicatedCount == 0 {
scheduler.CurrentScheduler.OnWaybillStatusChanged(bill, false)
}
} else {
dao.Rollback(db, txDB)
}
if bill.VendorOrderID == bill.VendorWaybillID {
if status, ok := waybillOrderStatusMap[bill.Status]; ok {
fakeOrderStatus := &model.OrderStatus{
VendorOrderID: bill.VendorOrderID,
VendorID: bill.OrderVendorID,
OrderType: model.OrderTypeOrder,
RefVendorOrderID: bill.VendorOrderID,
RefVendorID: bill.OrderVendorID,
Status: status,
VendorStatus: bill.VendorStatus,
StatusTime: bill.StatusTime,
Remark: bill.Remark,
}
w.OnOrderStatusChanged(bill.VendorOrgCode, fakeOrderStatus)
}
}
return err
}
func (w *OrderManager) addWaybillStatus(bill *model.Waybill, db *dao.DaoDB, addParams orm.Params) (duplicatedCount int, err error) {
waybillStatus := model.Waybill2Status(bill)
isDuplicated, err := addOrderOrWaybillStatus(waybillStatus, db)
if err == nil && !isDuplicated {
if waybillStatus.Status > model.WaybillStatusUnknown { // todo 这里应该和addOrderStatus一样的改法状态不能回绕
params := utils.MergeMaps(orm.Params{
"status": bill.Status,
"vendor_status": bill.VendorStatus,
"status_time": bill.StatusTime,
}, addParams)
utils.CallFuncLogError(func() error {
_, err = db.Db.QueryTable("waybill").Filter("vendor_waybill_id", bill.VendorWaybillID).Filter("waybill_vendor_id", bill.WaybillVendorID).Filter("status__lte", bill.Status).Update(params)
return err
}, "addWaybillStatus update waybill status, bill:%v", bill)
} else {
duplicatedCount = -1
}
} else {
duplicatedCount = 1
}
return duplicatedCount, err
}
func (c *OrderManager) LoadWaybill(vendorWaybillID string, waybillVendorID int) (bill *model.Waybill, err error) {
db := orm.NewOrm()
bill = &model.Waybill{
VendorWaybillID: vendorWaybillID,
WaybillVendorID: waybillVendorID,
}
if err = db.Read(bill, "VendorWaybillID", "WaybillVendorID"); err != nil {
bill = nil
if err == orm.ErrNoRows {
err = ErrCanNotFindWaybill
}
globals.SugarLogger.Infof("LoadWaybill vendorWaybillID:%s failed with error:%v", vendorWaybillID, err)
}
return bill, err
}
func GetComplaintReasons() (complaintReasonList []*dadaapi.ComplaintReason) {
for k, v := range complaintReasonsMap {
complaintReason := &dadaapi.ComplaintReason{
ID: k,
Reason: v,
}
complaintReasonList = append(complaintReasonList, complaintReason)
}
return complaintReasonList
}
func ComplaintRider(ctx *jxcontext.Context, vendorOrderID string, vendorID, waybillVendorID, complaintID int) (err error) {
db := dao.GetDB()
p := partner.GetDeliveryPlatformFromVendorID(waybillVendorID).Handler
wayBillList, err := dao.GetWayBillByOrderID(db, 0, vendorID, waybillVendorID, vendorOrderID)
if err == nil && len(wayBillList) > 0 {
err = p.ComplaintRider(wayBillList[0], complaintID, complaintReasonsMap[complaintID])
} else {
return fmt.Errorf("未查询到到相关订单!订单号:[%v] ,厂商:[%v],运送厂商:[%v]", vendorOrderID, vendorID, waybillVendorID)
}
return err
}
func ComplaintRiderPlatform(ctx *jxcontext.Context, vendorOrderID string, vendorID, waybillVendorID, complaintID int) (err error) {
return fmt.Errorf("只支持三方配送投诉!")
//handler := partner.GetPurchaseOrderHandlerFromVendorID(vendorID)
//return handler.ComplaintRider(vendorOrderID, complaintID, "")
}

View File

@@ -1,200 +0,0 @@
package basesch
import (
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxcallback/scheduler"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/globals"
)
var (
FixedBaseScheduler *BaseScheduler
)
type BaseScheduler struct {
IsReallyCallPlatformAPI bool
}
func (c *BaseScheduler) AcceptOrRefuseOrder(order *model.GoodsOrder, isAcceptIt bool, userName string) (err error) {
globals.SugarLogger.Infof("AcceptOrRefuseOrder orderID:%s, isAcceptIt:%t", order.VendorOrderID, isAcceptIt)
if /*order.LockStatus == model.OrderStatusUnknown && */ order.Status == model.OrderStatusNew || order.Status == model.OrderStatusWaitAccepted {
if c.IsReallyCallPlatformAPI {
err = utils.CallFuncLogErrorWithInfo(func() error {
return partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID).AcceptOrRefuseOrder(order, isAcceptIt, userName)
}, "AcceptOrRefuseOrder orderID:%s, isAcceptIt:%t", order.VendorOrderID, isAcceptIt)
}
} else {
return scheduler.ErrOrderStatusAlreadySatisfyCurOperation
globals.SugarLogger.Debugf("AcceptOrRefuseOrder orderID:%s, status:%d is not suitable, isAcceptIt:%t", order.VendorOrderID, order.Status, isAcceptIt)
}
return err
}
func (c *BaseScheduler) PickupGoods(order *model.GoodsOrder, isSelfDelivery bool, userName string) (err error) {
globals.SugarLogger.Infof("PickupGoods orderID:%s,order :%v", order.VendorOrderID, utils.Format4Output(order, false))
if /*order.LockStatus == model.OrderStatusUnknown && */ order.Status == model.OrderStatusAccepted {
if c.IsReallyCallPlatformAPI {
handler := partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID)
err = utils.CallFuncLogErrorWithInfo(func() (err error) {
if err = handler.PickupGoods(order, isSelfDelivery, userName); err != nil {
if status, err2 := handler.GetOrderStatus(order.VendorOrgCode, order.VendorOrderID); err2 == nil && status >= model.OrderStatusFinished {
err = nil
}
}
return err
}, "PickupGoods orderID:%s", order.VendorOrderID)
}
} else {
if order.LockStatus != model.OrderStatusUnknown || order.Status < model.OrderStatusAccepted {
err = scheduler.ErrOrderStatusIsNotSuitable4CurOperation
globals.SugarLogger.Infof("PickupGoods orderID:%s, status:%d is not suitable", order.VendorOrderID, order.Status)
} else {
err = scheduler.ErrOrderStatusAlreadySatisfyCurOperation
globals.SugarLogger.Debugf("PickupGoods orderID:%s status:%d already ok", order.VendorOrderID, order.Status)
}
}
return err
}
func (c *BaseScheduler) Swtich2SelfDeliver(order *model.GoodsOrder, userName string) (err error) {
globals.SugarLogger.Infof("Swtich2SelfDeliver orderID:%s", order.VendorOrderID)
if /*order.LockStatus == model.OrderStatusUnknown && */ order.Status >= model.OrderStatusFinishedPickup && order.Status <= model.OrderStatusDelivering {
if order.DeliveryFlag&model.OrderDeliveryFlagMaskPurcahseDisabled == 0 && c.IsReallyCallPlatformAPI {
err = utils.CallFuncLogErrorWithInfo(func() error {
return partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID).Swtich2SelfDeliver(order, userName)
}, "Swtich2SelfDeliver orderID:%s", order.VendorOrderID)
}
if err == nil { // 因为有些平台转自送后,不会再发送订单在配送中消息过来,所以成功后就强制设置状态为配送中
order.Status = model.OrderStatusDelivering
order.DeliveryFlag |= model.OrderDeliveryFlagMaskPurcahseDisabled
err = partner.CurOrderManager.UpdateOrderStatusAndDeliveryFlag(order)
}
} else {
if order.LockStatus != model.OrderStatusUnknown || order.Status < model.OrderStatusFinishedPickup || order.VendorID == order.WaybillVendorID {
err = scheduler.ErrOrderStatusIsNotSuitable4CurOperation
globals.SugarLogger.Infof("Swtich2SelfDeliver orderID:%s, status:%d is not suitable", order.VendorOrderID, order.Status)
} else {
err = scheduler.ErrOrderStatusAlreadySatisfyCurOperation
globals.SugarLogger.Debugf("Swtich2SelfDeliver orderID:%s status:%d already ok", order.VendorOrderID, order.Status)
}
}
return err
}
func (c *BaseScheduler) Swtich2SelfDelivered(order *model.GoodsOrder, userName string) (err error) {
globals.SugarLogger.Infof("Swtich2SelfDelivered orderID:%s", order.VendorOrderID)
if /*order.LockStatus == model.OrderStatusUnknown && */ order.Status == model.OrderStatusDelivering {
if c.IsReallyCallPlatformAPI {
err = utils.CallFuncLogError(func() error {
return partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID).Swtich2SelfDelivered(order, userName)
}, "Swtich2SelfDelivered orderID:%s", order.VendorOrderID)
}
} else {
if order.LockStatus != model.OrderStatusUnknown || order.Status < model.OrderStatusDelivering {
err = scheduler.ErrOrderStatusIsNotSuitable4CurOperation
globals.SugarLogger.Infof("Swtich2SelfDelivered orderID:%s, status:%d is not suitable", order.VendorOrderID, order.Status)
} else {
err = scheduler.ErrOrderStatusAlreadySatisfyCurOperation
globals.SugarLogger.Debugf("Swtich2SelfDelivered orderID:%s status:%d already ok", order.VendorOrderID, order.Status)
}
}
return err
}
func (c *BaseScheduler) SelfDeliverDelivering(order *model.GoodsOrder, userName string) (err error) {
globals.SugarLogger.Infof("SelfDeliverDelivering orderID:%s", order.VendorOrderID)
if /*order.LockStatus == model.OrderStatusUnknown && */ order.Status == model.OrderStatusFinishedPickup {
if c.IsReallyCallPlatformAPI {
err = utils.CallFuncLogError(func() error {
return partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID).SelfDeliverDelivering(order, userName)
}, "SelfDeliverDelivering orderID:%s", order.VendorOrderID)
if err == nil { // 因为有些平台设置配送中后,不会发送订单在配送中消息过来,所以成功后就强制设置状态为配送中
order.Status = model.OrderStatusDelivering
err = partner.CurOrderManager.UpdateOrderStatusAndDeliveryFlag(order)
}
}
} else {
if order.LockStatus != model.OrderStatusUnknown || order.Status < model.OrderStatusFinishedPickup {
err = scheduler.ErrOrderStatusIsNotSuitable4CurOperation
globals.SugarLogger.Infof("SelfDeliverDelivering orderID:%s, status:%d is not suitable", order.VendorOrderID, order.Status)
} else {
err = scheduler.ErrOrderStatusAlreadySatisfyCurOperation
globals.SugarLogger.Debugf("SelfDeliverDelivering orderID:%s, status:%d already ok", order.VendorOrderID, order.Status)
}
}
return err
}
func (c *BaseScheduler) SelfDeliverDelivered(order *model.GoodsOrder, userName string) (err error) {
globals.SugarLogger.Infof("SelfDeliverDelivered orderID:%s", order.VendorOrderID)
if /*order.LockStatus == model.OrderStatusUnknown && */ order.Status >= model.OrderStatusFinishedPickup &&
order.Status <= model.OrderStatusDelivering {
if c.IsReallyCallPlatformAPI {
err = utils.CallFuncLogError(func() error {
return partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID).SelfDeliverDelivered(order, userName)
}, "SelfDeliverDelivered orderID:%s", order.VendorOrderID)
}
} else {
if order.LockStatus != model.OrderStatusUnknown || order.Status < model.OrderStatusDelivering {
err = scheduler.ErrOrderStatusIsNotSuitable4CurOperation
globals.SugarLogger.Infof("SelfDeliverDelivered orderID:%s, status:%d is not suitable", order.VendorOrderID, order.Status)
} else {
err = scheduler.ErrOrderStatusAlreadySatisfyCurOperation
globals.SugarLogger.Debugf("SelfDeliverDelivered orderID:%s, status:%d already ok", order.VendorOrderID, order.Status)
}
}
return err
}
func (c *BaseScheduler) CreateWaybill(platformVendorID int, order *model.GoodsOrder, maxDeliveryFee int64) (bill *model.Waybill, err error) {
globals.SugarLogger.Infof("CreateWaybill orderID:%s, vendor:%s", order.VendorOrderID, jxutils.GetVendorName(platformVendorID))
if !model.IsOrderSolid(order) { // 如果订单是不完整的
globals.SugarLogger.Warnf("CreateWaybill orderID:%s, vendorID:%d is not solid!!!", order.VendorOrderID, platformVendorID)
return nil, scheduler.ErrOrderIsNotSolid
}
// if order.DeliveryFlag&model.OrderDeliveryFlagMaskScheduleDisabled != 0 {
// waybillList, err := partner.CurOrderManager.GetOrderWaybillInfo(jxcontext.AdminCtx, order.VendorOrderID, order.VendorID, true)
// if err != nil {
// return nil, err
// }
// if len(waybillList) > 0 {
// return nil, fmt.Errorf("转商家自送的订单只允许有一个有效运单,当前已经有%s运单", jxutils.GetVendorName(waybillList[0].WaybillVendorID))
// }
// }
handlerInfo := partner.GetDeliveryPlatformFromVendorID(platformVendorID)
if handlerInfo != nil && handlerInfo.Use4CreateWaybill {
if c.IsReallyCallPlatformAPI {
bill, err = handlerInfo.Handler.CreateWaybill(order, maxDeliveryFee)
if err != nil {
globals.SugarLogger.Infof("CreateWaybill failed orderID:%s vendorID:%d with error:%v", order.VendorOrderID, platformVendorID, err)
} else {
order.DeliveryFlag |= model.WaybillVendorID2Mask(platformVendorID)
err = partner.CurOrderManager.UpdateOrderStatusAndDeliveryFlag(order)
}
}
} else {
err = scheduler.ErrDeliverProviderWrong
}
return bill, err
}
func (c *BaseScheduler) CancelWaybill(bill *model.Waybill, cancelReasonID int, cancelReason string) (err error) {
globals.SugarLogger.Infof("CancelWaybill bill:%v, cancelReasonID:%d cancelReason:%s", bill, cancelReasonID, cancelReason)
// 部分快递平台在取消成功后有时会不发运单取消消息过来比如达达904200512000442为避免二次取消报错添加状态判断
if c.IsReallyCallPlatformAPI && bill.OrderVendorID != bill.WaybillVendorID && bill.Status != model.WaybillStatusCanceled {
if handlerInfo := partner.GetDeliveryPlatformFromVendorID(bill.WaybillVendorID); handlerInfo != nil {
if err = utils.CallFuncLogErrorWithInfo(func() error {
return handlerInfo.Handler.CancelWaybill(bill, cancelReasonID, cancelReason)
}, "CancelWaybill bill:%v", bill); err == nil {
bill.Status = model.WaybillStatusCanceled
bill.DeliveryFlag |= model.WaybillDeliveryFlagMaskActiveCancel
_, err = dao.UpdateEntity(nil, bill, "Status", "DeliveryFlag")
}
globals.SugarLogger.Debugf("CancelWaybill bill:%v canceled by myself", bill)
}
}
return err
}

View File

@@ -1,479 +0,0 @@
package basesch
import (
"fmt"
"strings"
"time"
"git.rosy.net.cn/baseapi/platformapi/jdshopapi"
"git.rosy.net.cn/baseapi/platformapi/dingdingapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/baseapi/utils/errlist"
"git.rosy.net.cn/jx-callback/business/jxstore/cms"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/jxutils/ddmsg"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/globals"
)
const (
autoSelfTakeCode = "135246"
)
func (c *BaseScheduler) CreateWaybillOnProviders(ctx *jxcontext.Context, order *model.GoodsOrder, courierVendorIDs, excludeCourierVendorIDs []int, maxDeliveryFee int64, createOnlyOne bool) (bills []*model.Waybill, err error) {
userName := ctx.GetUserName()
globals.SugarLogger.Infof("CreateWaybillOnProviders orderID:%s userName:%s, courierVendorIDs:%v, excludeCourierVendorIDs:%v", order.VendorOrderID, userName, courierVendorIDs, excludeCourierVendorIDs)
storeCourierList, err := dao.GetStoreCourierList2(dao.GetDB(), []int{jxutils.GetSaleStoreIDFromOrder(order)}, nil, model.StoreStatusOpened, []int{model.StoreAuditStatusOnline, model.StoreAuditStatusUpdated})
if err != nil {
return nil, err
}
courierVendorIDMap := jxutils.IntList2Map(courierVendorIDs)
excludeCourierVendorIDMap := jxutils.IntList2Map(excludeCourierVendorIDs)
errList := errlist.New()
for _, storeCourier := range storeCourierList {
if (courierVendorIDs == nil || courierVendorIDMap[storeCourier.VendorID] == 1) &&
(excludeCourierVendorIDs == nil || excludeCourierVendorIDMap[storeCourier.VendorID] == 0) {
if handler := partner.GetDeliveryPlatformFromVendorID(storeCourier.VendorID); handler != nil && handler.Use4CreateWaybill {
courierVendorID := storeCourier.VendorID
bill, err2 := c.CreateWaybill(courierVendorID, order, maxDeliveryFee)
if err = err2; err == nil {
globals.SugarLogger.Debugf("CreateWaybillOnProviders orderID:%s userName:%s vendorID:%d bill:%v", order.VendorOrderID, userName, courierVendorID, bill)
bills = append(bills, bill)
if createOnlyOne {
break
}
} else {
globals.SugarLogger.Debugf("CreateWaybillOnProviders orderID:%s userName:%s vendorID:%d failed with error:%v", order.VendorOrderID, userName, courierVendorID, err)
errList.AddErr(fmt.Errorf("平台:%s,%s", jxutils.GetVendorName(courierVendorID), err.Error()))
}
}
}
}
if len(bills) > 0 {
err = errList.GetErrListAsOne()
if err != nil {
partner.CurOrderManager.OnOrderMsg(order, "创建三方运单部分失败", err.Error())
}
err = nil
} else if errList.GetErrListAsOne() == nil {
err = fmt.Errorf("orderID:%s没有绑定有效的三方配送门店或没有剩下可用的三方配送", order.VendorOrderID)
} else {
err = fmt.Errorf("orderID:%s所有运单失败%s", order.VendorOrderID, errList.GetErrListAsOne().Error())
}
globals.SugarLogger.Infof("CreateWaybillOnProviders orderID:%s userName:%s error:%v", order.VendorOrderID, userName, err)
return bills, err
}
func (c *BaseScheduler) SelfDeliveredAndUpdateStatus(ctx *jxcontext.Context, vendorOrderID string, vendorID int, userName string) (err error) {
jxutils.CallMsgHandler(func() {
err = func() (err error) {
globals.SugarLogger.Infof("SelfDeliveredAndUpdateStatus orderID:%s userName:%s", vendorOrderID, userName)
order, err := partner.CurOrderManager.LoadOrder(vendorOrderID, vendorID)
if err == nil {
if model.IsOrderDeliveryByStore(order) {
err = c.SelfDeliverDelivered(order, userName)
} else if model.IsOrderDeliveryByPlatform(order) {
err = c.Swtich2SelfDelivered(order, userName)
}
if err == nil {
// order.Status = model.OrderStatusFinished // todo 是否需要强制设置完成状态?
if err = dao.SetOrderFlag(dao.GetDB(), ctx.GetUserName(), order.VendorOrderID, order.VendorID, model.OrderFlagMaskSetDelivered); err == nil {
globals.SugarLogger.Infof("SelfDeliveredAndUpdateStatus orderID:%s userName:%s successfully", vendorOrderID, userName)
return err
}
}
}
globals.SugarLogger.Infof("SelfDeliveredAndUpdateStatus orderID:%s userName:%s error:%v", vendorOrderID, userName, err)
return err
}()
}, jxutils.ComposeUniversalOrderID(vendorOrderID, vendorID))
return err
}
func (c *BaseScheduler) PickupGoodsAndUpdateStatus(ctx *jxcontext.Context, vendorOrderID string, vendorID int, userName string) (err error) {
jxutils.CallMsgHandler(func() {
err = func() (err error) {
globals.SugarLogger.Infof("PickupGoodsAndUpdateStatus orderID:%s userName:%s", vendorOrderID, userName)
order, err := partner.CurOrderManager.LoadOrder(vendorOrderID, vendorID)
if err == nil {
flag := model.IsOrderDeliveryByStore(order) || model.IsOrderDeliveryBySelf(order)
err = c.PickupGoods(order, flag, userName)
if err == nil {
order.Status = model.OrderStatusFinishedPickup
if err = partner.CurOrderManager.UpdateOrderStatusAndDeliveryFlag(order); err == nil {
globals.SugarLogger.Infof("PickupGoodsAndUpdateStatus orderID:%s userName:%s successfully", vendorOrderID, userName)
return err
}
}
}
globals.SugarLogger.Infof("PickupGoodsAndUpdateStatus orderID:%s userName:%s error:%v", vendorOrderID, userName, err)
return err
}()
}, jxutils.ComposeUniversalOrderID(vendorOrderID, vendorID))
return err
}
func (c *BaseScheduler) AdjustOrder(ctx *jxcontext.Context, order *model.GoodsOrder, removedSkuList []*model.OrderSku, reason string) (err error) {
if c.IsReallyCallPlatformAPI {
err = partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID).AdjustOrder(ctx, order, removedSkuList, reason)
if err == nil {
var skuIDs []string
for _, v := range removedSkuList {
skuIDs = append(skuIDs, utils.Int2Str(v.SkuID))
}
noticeMsg := fmt.Sprintf("商品skuID列表%v订单号(点击进入详情)%v", strings.Join(skuIDs, ","), globals.BackstageHost+"/#/ordermanager/"+order.VendorOrderID)
user, err := dao.GetUserByID(dao.GetDB(), "mobile", "18982250714")
if user != nil && err == nil {
ddmsg.SendUserMessage(dingdingapi.MsgTyeText, user.UserID, "调整单调整商品", noticeMsg)
}
}
}
return err
}
func (c *BaseScheduler) CancelOrder(ctx *jxcontext.Context, order *model.GoodsOrder, reason string) (err error) {
if c.IsReallyCallPlatformAPI {
if globals.IsAddEvent {
err = cms.AddEventDetail(dao.GetDB(), ctx, model.OperateUpdate, order.StoreID, model.ThingTypeOrder, order.StoreID, order.VendorOrderID, order.StoreName)
}
err = partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID).CancelOrder(ctx, order, reason+","+ctx.GetUserName())
}
return err
}
func (c *BaseScheduler) AcceptOrRefuseFailedGetOrder(ctx *jxcontext.Context, order *model.GoodsOrder, isAcceptIt bool, reason string) (err error) {
if c.IsReallyCallPlatformAPI {
err = partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID).AcceptOrRefuseFailedGetOrder(ctx, order, isAcceptIt)
}
if err == nil {
flag := model.OrderFlagAgreeFailedGetGoods
if !isAcceptIt {
flag = model.OrderFlagRefuseFailedGetGoods
}
dao.SetOrderFlag(dao.GetDB(), ctx.GetUserName(), order.VendorOrderID, order.VendorID, flag)
}
return err
}
func (c *BaseScheduler) CallPMCourier(ctx *jxcontext.Context, order *model.GoodsOrder) (err error) {
if c.IsReallyCallPlatformAPI {
err = partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID).CallCourier(ctx, order)
}
if err == nil {
dao.SetOrderFlag(dao.GetDB(), ctx.GetUserName(), order.VendorOrderID, order.VendorID, model.OrderFlagMaskCallPMCourier)
}
return err
}
func (c *BaseScheduler) ConfirmReceiveGoods(ctx *jxcontext.Context, order *model.GoodsOrder) (err error) {
if c.IsReallyCallPlatformAPI {
err = partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID).ConfirmReceiveGoods(ctx, order)
}
if err == nil {
dao.SetOrderFlag(dao.GetDB(), ctx.GetUserName(), order.VendorOrderID, order.VendorID, model.OrderFlagMaskFailedDeliver)
}
return err
}
func (c *BaseScheduler) AgreeOrRefuseCancel(ctx *jxcontext.Context, order *model.GoodsOrder, isAcceptIt bool, reason string) (err error) {
if c.IsReallyCallPlatformAPI {
err = partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID).AgreeOrRefuseCancel(ctx, order, isAcceptIt, reason)
}
if err == nil {
flag := model.OrderFlagAgreeUserApplyCancel
if !isAcceptIt {
flag = model.OrderFlagRefuseUserApplyCancel
}
dao.SetOrderFlag(dao.GetDB(), ctx.GetUserName(), order.VendorOrderID, order.VendorID, flag)
}
return err
}
func (c *BaseScheduler) CancelWaybillByID(ctx *jxcontext.Context, vendorWaybillID string, waybillVendorID int, cancelReasonID int, cancelReason string) (err error) {
bill, err := partner.CurOrderManager.LoadWaybill(vendorWaybillID, waybillVendorID)
if err == nil {
err = c.CancelWaybill(bill, cancelReasonID, cancelReason)
}
return err
}
func (c *BaseScheduler) AgreeOrRefuseRefund(ctx *jxcontext.Context, afsOrderID string, vendorID, approveType int, reason string) (err error) {
afsOrder, err := partner.CurOrderManager.LoadAfsOrder(afsOrderID, vendorID)
if err == nil {
if c.IsReallyCallPlatformAPI {
err = partner.GetPurchaseOrderHandlerFromVendorID(vendorID).AgreeOrRefuseRefund(ctx, afsOrder, approveType, reason)
}
if err == nil {
flag := model.AfsOrderFlagAgreeUserRefund
if approveType == partner.AfsApproveTypeRefused {
flag = model.AfsOrderFlagRefuseUserRefund
afsOrder.RefuseReason = reason
partner.CurOrderManager.UpdateAfsOrderFields(afsOrder, []string{"RefuseReason"})
} else {
if order, _ := partner.CurOrderManager.LoadOrder(afsOrder.VendorOrderID, afsOrder.VendorID); order != nil {
var (
db = dao.GetDB()
)
waybills, _ := dao.GetWaybills(db, order.VendorOrderID)
//美团的订单如果是同意全部退款,要取消所有三方运单并停止调度
if order.VendorID == model.VendorIDMTWM {
var (
afsCount, orderCount int
)
skus, _ := dao.GetAfsOrderSkuInfo(db, order.VendorOrderID, afsOrderID, order.VendorID, false)
for _, v := range skus {
afsCount += v.Count
}
for _, v := range order.Skus {
orderCount += v.Count
}
//如果售后退款的商品数等于订单商品数,我就当是全部退款了
if afsCount == orderCount {
for _, v := range waybills {
if err = c.CancelWaybill(v, partner.CancelWaybillReasonOther, partner.CancelWaybillReasonStrActive); err == nil {
v.DeliveryFlag |= model.WaybillDeliveryFlagMaskActiveCancel
_, err = dao.UpdateEntity(db, v, "Status", "DeliveryFlag")
} else {
globals.SugarLogger.Debugf("AgreeOrRefuseRefund, cancelwaybill error: %v", err)
}
}
order.DeliveryFlag |= model.OrderDeliveryFlagMaskScheduleDisabled
partner.CurOrderManager.UpdateOrderFields(order, []string{"DeliveryFlag"})
}
}
if order.EarningType == model.EarningTypePoints {
var (
skuMap = make(map[int]*model.OrderSku)
diff int64
)
for _, sku := range order.Skus {
skuMap[sku.SkuID] = sku
}
//京东商城和京西要重新算totalshopmoney等
if order.VendorID == model.VendorIDJDShop || order.VendorID == model.VendorIDJX {
skus, _ := dao.GetAfsOrderSkuInfo(db, order.VendorOrderID, afsOrderID, order.VendorID, false)
for _, v := range skus {
if skuMap[v.SkuID] != nil {
diff += skuMap[v.SkuID].SalePrice * int64(v.Count)
}
}
order.TotalShopMoney = utils.Float64TwoInt64(float64(float64(order.TotalShopMoney)/jdshopapi.JdsPayPercentage-float64(diff)) * jdshopapi.JdsPayPercentage)
if len(waybills) > 0 {
jxutils.RefreshOrderEarningPrice3(order, order.OrderPayPercentage, waybills[0])
} else {
jxutils.RefreshOrderEarningPrice2(order, order.OrderPayPercentage)
}
dao.UpdateEntity(db, order, "TotalShopMoney", "NewEarningPrice")
}
}
}
}
dao.SetAfsOrderFlag(dao.GetDB(), ctx.GetUserName(), afsOrderID, vendorID, flag)
}
}
return err
}
func (c *BaseScheduler) ConfirmReceivedReturnGoods(ctx *jxcontext.Context, afsOrderID string, vendorID int) (err error) {
afsOrder, err := partner.CurOrderManager.LoadAfsOrder(afsOrderID, vendorID)
if err == nil {
if c.IsReallyCallPlatformAPI {
err = partner.GetPurchaseOrderHandlerFromVendorID(vendorID).ConfirmReceivedReturnGoods(ctx, afsOrder)
}
if err == nil {
dao.SetAfsOrderFlag(dao.GetDB(), ctx.GetUserName(), afsOrderID, vendorID, model.AfsOrderFlagMaskReturnGoods)
}
}
return err
}
func (c *BaseScheduler) PartRefundOrder(ctx *jxcontext.Context, order *model.GoodsOrder, refundSkuList []*model.OrderSku, reason string) (err error) {
if c.IsReallyCallPlatformAPI {
err = partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID).PartRefundOrder(ctx, order, refundSkuList, reason)
}
return err
}
func (c *BaseScheduler) RefundOrder(ctx *jxcontext.Context, order *model.GoodsOrder, reason string) (err error) {
if c.IsReallyCallPlatformAPI {
err = partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID).RefundOrder(ctx, order, reason)
}
return err
}
func (c *BaseScheduler) ConfirmSelfTake(ctx *jxcontext.Context, vendorOrderID string, vendorID int, selfTakeCode string) (err error) {
order, err2 := partner.CurOrderManager.LoadOrder(vendorOrderID, vendorID)
if err = err2; err == nil {
err = c.confirmSelfTake(ctx, order, selfTakeCode)
}
return err
}
func (c *BaseScheduler) SetOrderWaybillTip(ctx *jxcontext.Context, vendorOrderID string, vendorID int, tipFee int64) (errCode string, err error) {
if order, err := partner.CurOrderManager.LoadOrder(vendorOrderID, vendorID); err == nil {
if errCode, err = c.CheckStoreBalanceWithTip(ctx, order, tipFee); err == nil {
err = c.SetOrderWaybillTipByOrder(ctx, order, tipFee)
}
}
return errCode, err
}
func (c *BaseScheduler) CheckStoreBalanceWithTip(ctx *jxcontext.Context, order *model.GoodsOrder, tipFee int64) (errCode string, err error) {
if order.CreateDeliveryType == model.YES {
//加小费只判断余额
storeAcct, err := cms.GetStoreAcctBalance(ctx, jxutils.GetSaleStoreIDFromOrder(order))
if err != nil {
return errCode, fmt.Errorf("获取账户余额失败!")
}
if tipFee > int64(storeAcct.AccountBalance) {
return model.ErrCodeAccountBalanceNotEnough, fmt.Errorf("门店账户余额不足,不能加小费!")
}
}
return errCode, err
}
func isWaybillCanAddTip(waybill *model.Waybill) (isCan bool) {
isCan = waybill.Status >= model.WaybillStatusNew && waybill.Status < model.WaybillStatusAccepted && partner.GetWaybillTipUpdater(waybill.WaybillVendorID) != nil
return isCan
}
func (c *BaseScheduler) SetOrderWaybillTipByOrder(ctx *jxcontext.Context, order *model.GoodsOrder, tipFee int64) (err error) {
roundTipFee := tipFee / 100 * 100
if roundTipFee != tipFee {
return fmt.Errorf("小费必须是1元的整数倍")
}
if order.WaybillTipMoney >= tipFee {
return fmt.Errorf("当前小费已经是%s元想要设置%s元", jxutils.IntPrice2StandardString(order.WaybillTipMoney), jxutils.IntPrice2StandardString(tipFee))
}
globals.SugarLogger.Debugf("SetOrderWaybillTipByOrder, orderID %s, tip:%d", order.VendorOrderID, tipFee)
db := dao.GetDB()
storeDetail, _ := dao.GetStoreDetail(db, jxutils.GetSaleStoreIDFromOrder(order), order.VendorID, "")
flag := false
// 如果平台支持设置配送小费,必须要成功设置
if handler := partner.GetWaybillTipUpdater(order.VendorID); handler != nil {
if err = handler.UpdateWaybillTip(ctx, order.VendorOrgCode, order.VendorStoreID, order.VendorOrderID, "", "", utils.Int2Str(storeDetail.CityCode), tipFee); err != nil {
return err
} else {
//加小费成功扣钱
if order.CreateDeliveryType == model.YES {
if err = partner.CurStoreAcctManager.InsertStoreAcctExpendAndUpdateStoreAcctBalance(ctx, jxutils.GetSaleStoreIDFromOrder(order), 100, partner.StoreAcctTypeExpendCreateWaybillTip, order.VendorOrderID, 0); err == nil {
flag = true
}
}
}
} //有可能进else没加得起平台小费就要到下面扣账户
order.WaybillTipMoney = tipFee
partner.CurOrderManager.UpdateOrderFields(order, []string{"WaybillTipMoney"})
waybills, err := dao.GetWayBillByOrderID(db, 0, order.VendorID, 0, order.VendorOrderID)
if err == nil {
var waybills2 []*model.Waybill
for _, v := range waybills {
// 必须是三方配送
if !model.IsWaybillPlatformOwn(v) && isWaybillCanAddTip(v) {
waybills2 = append(waybills2, v)
}
}
if len(waybills2) > 0 {
task := tasksch.NewParallelTask("SetOrderWaybillTipByOrder", nil, ctx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
waybill := batchItemList[0].(*model.Waybill)
handler := partner.GetWaybillTipUpdater(waybill.WaybillVendorID)
if err == nil {
err = handler.UpdateWaybillTip(ctx, waybill.VendorOrgCode, storeDetail.VendorStoreID, waybill.VendorOrderID, waybill.VendorWaybillID, waybill.VendorWaybillID2, utils.Int2Str(storeDetail.CityCode), tipFee)
}
return nil, err
}, waybills2)
tasksch.HandleTask(task, nil, false).Run()
_, err = task.GetResult(0)
if err == nil {
//加起了至少只扣一次钱
if !flag {
//加小费成功扣钱
if order.CreateDeliveryType == model.YES {
partner.CurStoreAcctManager.InsertStoreAcctExpendAndUpdateStoreAcctBalance(ctx, jxutils.GetSaleStoreIDFromOrder(order), 100, partner.StoreAcctTypeExpendCreateWaybillTip, order.VendorOrderID, 0)
}
}
}
}
}
return err
}
func (c *BaseScheduler) confirmSelfTake(ctx *jxcontext.Context, order *model.GoodsOrder, selfTakeCode string) (err error) {
globals.SugarLogger.Debugf("confirmSelfTake orderID:%s, selfTakeCode:%s", order.VendorOrderID, selfTakeCode)
vendorID := order.VendorID
// if vendorID == model.VendorIDJD || vendorID == model.VendorIDJX {
if vendorID != model.VendorIDJX {
handler := partner.GetPurchaseOrderHandlerFromVendorID(vendorID)
if selfTakeCode == autoSelfTakeCode {
if selfTakeCode, err = handler.GetSelfTakeCode(ctx, order); err != nil {
return fmt.Errorf("获取订单:%s自提货码失败原始错误:%s", order.VendorOrderID, err.Error())
}
if selfTakeCode == "" {
return fmt.Errorf("订单:%s 自动提货失败,请手动输入自提码", order.VendorOrderID)
}
}
err = handler.ConfirmSelfTake(ctx, order, selfTakeCode)
} else {
orderStatus := &model.OrderStatus{
VendorOrderID: order.VendorOrderID,
VendorID: model.VendorIDJX,
OrderType: model.OrderTypeOrder,
RefVendorOrderID: order.VendorOrderID,
RefVendorID: model.VendorIDJX,
VendorStatus: utils.Int2Str(model.OrderStatusFinished),
Status: model.OrderStatusFinished,
StatusTime: time.Now(),
Remark: "自提完成",
}
jxutils.CallMsgHandlerAsync(func() {
err = partner.CurOrderManager.OnOrderStatusChanged("", orderStatus)
}, jxutils.ComposeUniversalOrderID(order.VendorOrderID, model.VendorIDJX))
}
// } else {
// err = fmt.Errorf("自提核销不支持%s平台订单", model.VendorChineseNames[order.VendorID])
// }
return err
}
func (c *BaseScheduler) ConfirmSelfTakeOrders(ctx *jxcontext.Context, vendorIDs []int, orderCreatedAfter, orderCreatedBefore time.Time, isAsync, isContinueWhenError bool) (hint string, err error) {
orderList, err := dao.GetPendingFakeOrders(dao.GetDB(), vendorIDs, orderCreatedAfter, orderCreatedBefore)
if err == nil {
if len(orderList) > 0 {
task := tasksch.NewParallelTask(fmt.Sprintf("自动完成内部自提单%v,%s", vendorIDs, utils.Time2Str(orderCreatedAfter)), tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError), ctx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
order := batchItemList[0].(*model.GoodsOrder)
if order.Status == model.OrderStatusAccepted {
if handler := partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID); handler != nil {
err = handler.AcceptOrRefuseOrder(order, true, ctx.GetUserName())
time.Sleep(2 * time.Second)
}
}
if err == nil {
if err = c.confirmSelfTake(ctx, order, autoSelfTakeCode); err == nil {
retVal = []int{1}
}
}
return retVal, err
}, orderList)
tasksch.HandleTask(task, nil, true).Run()
if isAsync {
hint = task.GetID()
} else {
resultList, err2 := task.GetResult(0)
if err = err2; err == nil {
hint = utils.Int2Str(len(resultList))
}
}
}
}
return hint, err
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,59 +0,0 @@
package defsch
import (
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
push "git.rosy.net.cn/jx-callback/business/jxutils/unipush"
"git.rosy.net.cn/jx-callback/business/jxutils/weixinmsg"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/msghub"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/globals"
)
var (
autoRejectSkuMap = map[int]int{
33996: 1,
33995: 1,
33994: 1,
33991: 1,
}
)
func (s *DefScheduler) OnAfsOrderNew(order *model.AfsOrder, isPending bool) (err error) {
if order.Status == model.AfsOrderStatusWait4Approve {
if !isPending {
if isAutoRejectAfsOrder(order) {
if handler := partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID); handler != nil {
if err := handler.AgreeOrRefuseRefund(jxcontext.AdminCtx, order, partner.AfsApproveTypeRefused, "抱歉,蟹券不接受退货或换货"); err != nil {
globals.SugarLogger.Debugf("OnAfsOrderNew, orderID:%s, afsOrderID:%s failed with err:%v", order.VendorOrderID, order.AfsOrderID, err)
}
}
}
msghub.OnNewWait4ApproveAfsOrder(order)
weixinmsg.NotifyAfsOrderStatus(order)
push.NotifyAfsOrder(order)
}
}
return err
}
func (s *DefScheduler) OnAfsOrderStatusChanged(order *model.AfsOrder, status *model.OrderStatus, isPending bool) (err error) {
if status.Status == model.AfsOrderStatusWait4ReceiveGoods {
if !isPending {
msghub.OnKeyAfsOrderStatusChanged(order)
weixinmsg.NotifyAfsOrderStatus(order)
}
}
return err
}
func isAutoRejectAfsOrder(order *model.AfsOrder) (isReject bool) {
for _, v := range order.Skus {
if autoRejectSkuMap[jxutils.GetSkuIDFromOrderSkuFinancial(v)] == 1 {
isReject = true
break
}
}
return isReject
}

View File

@@ -1,403 +0,0 @@
package defsch
import (
"fmt"
"math"
"time"
"git.rosy.net.cn/jx-callback/business/jxstore/cms"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/business/jxcallback/scheduler"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/globals"
)
func (s *DefScheduler) loadSavedOrderByID(vendorOrderID string, vendorID int, isForceLoad bool) *WatchOrderInfo {
return s.loadSavedOrderFromMap(&model.OrderStatus{
RefVendorOrderID: vendorOrderID,
RefVendorID: vendorID,
}, isForceLoad)
}
func (s *DefScheduler) SelfDeliveringAndUpdateStatus(ctx *jxcontext.Context, vendorOrderID string, vendorID int, userName string) (err error) {
var order *model.GoodsOrder
jxutils.CallMsgHandler(func() {
err = func() (err error) {
globals.SugarLogger.Infof("SelfDeliveringAndUpdateStatus orderID:%s userName:%s", vendorOrderID, userName)
savedOrderInfo := s.loadSavedOrderByID(vendorOrderID, vendorID, true)
if savedOrderInfo != nil {
order = savedOrderInfo.order
if err = s.isPossibleSwitch2SelfDelivery(order); err == nil {
globals.SugarLogger.Infof("SelfDeliveringAndUpdateStatus ordersavedOrderInfoID:%s", utils.Format4Output(savedOrderInfo, false))
err = s.cancelOtherWaybillsCheckOrderDeliveryFlag(savedOrderInfo, nil, partner.CancelWaybillReasonOther, partner.CancelWaybillReasonStrActive)
if err == nil {
if model.IsOrderDeliveryByStore(order) {
if order.Status < model.OrderStatusDelivering {
storeDetail, err2 := dao.GetStoreDetail(dao.GetDB(), order.StoreID, order.VendorID, "")
phone := userName
if err = err2; err == nil {
phone = storeDetail.Tel1
}
err = s.SelfDeliverDelivering(order, phone)
}
} else {
if order.Status < model.OrderStatusDelivering {
err = s.Swtich2SelfDeliver(order, userName)
} else if order.VendorID == order.WaybillVendorID { // 状态为配送中,且是购物平台运单,不能转自送了
err = scheduler.ErrOrderStatusIsNotSuitable4CurOperation
}
}
}
}
if err == nil {
order.Status = model.OrderStatusDelivering
order.DeliveryFlag |= model.OrderDeliveryFlagMaskScheduleDisabled | model.OrderDeliveryFlagMaskPurcahseDisabled
if err = partner.CurOrderManager.UpdateOrderStatusAndDeliveryFlag(order); err == nil {
s.stopTimer(savedOrderInfo)
globals.SugarLogger.Infof("SelfDeliveringAndUpdateStatus orderID:%s userName:%s successfully", vendorOrderID, userName)
return err
}
}
} else {
order = &model.GoodsOrder{
VendorOrderID: vendorOrderID,
VendorID: vendorID,
}
err = scheduler.ErrCanNotFindOrder
}
globals.SugarLogger.Infof("SelfDeliveringAndUpdateStatus orderID:%s userName:%s error:%v", vendorOrderID, userName, err)
return err
}()
}, jxutils.ComposeUniversalOrderID(vendorOrderID, vendorID))
vendorStatus := fmt.Sprintf("%s转商户自送成功", ctx.GetUserName())
remark := ""
if err != nil {
vendorStatus = fmt.Sprintf("%s转商户自送失败", ctx.GetUserName())
remark = err.Error()
}
partner.CurOrderManager.OnOrderMsg(order, vendorStatus, remark)
return err
}
func (s *DefScheduler) canOrderCreateWaybillNormally(order *model.GoodsOrder, savedOrderInfo *WatchOrderInfo) (err error) {
if !(order.LockStatus != model.OrderStatusLocked && order.Status >= model.OrderStatusFinishedPickup && order.Status < model.OrderStatusEndBegin) {
err = fmt.Errorf("当前订单%s没有处于拣货完成且没有结束没有锁定的订单才能进行召唤配送操作", order.VendorOrderID)
} else if model.IsOrderHaveWaybill(order) {
err = fmt.Errorf("当前订单%s已经有了有效的承运人%s了", order.VendorOrderID, jxutils.GetVendorName(order.WaybillVendorID))
}
return err
}
func (s *DefScheduler) isPossibleSwitch2SelfDelivery(order *model.GoodsOrder) (err error) {
if model.IsOrderDeliveryByPlatform(order) {
if order.Status < model.OrderStatusFinishedPickup {
err = fmt.Errorf("拣货完成后才能转自配送")
} else if order.Status == model.OrderStatusFinishedPickup {
if time.Now().Sub(order.StatusTime) < minMinute2Schedule3rdCarrier*time.Minute {
err = fmt.Errorf("非自配送门店转3方配送至少要求拣货完成后%d分钟才能操作", minMinute2Schedule3rdCarrier)
}
} else if order.Status >= model.OrderStatusDelivering && order.Status < model.OrderStatusEndBegin {
if model.IsOrderHaveOwnWaybill(order) {
err = fmt.Errorf("%s物流已在配送中不能转自配送", jxutils.GetVendorName(order.VendorID))
}
} else if order.Status >= model.OrderStatusEndBegin {
err = fmt.Errorf("订单%s已经结束请刷新状态", order.VendorOrderID)
}
}
return err
}
func (s *DefScheduler) CreateWaybillOnProviders4SavedOrder(ctx *jxcontext.Context, savedOrderInfo *WatchOrderInfo, courierVendorIDs, excludeCourierVendorIDs []int, forceCreate bool, maxDeliveryFee int64) (bills []*model.Waybill, err error) {
order := savedOrderInfo.order
if !forceCreate {
err = s.canOrderCreateWaybillNormally(order, nil)
}
if err == nil {
if forceCreate {
maxDeliveryFee = math.MaxInt64
}
if bills, err = s.CreateWaybillOnProviders(ctx, order, courierVendorIDs, excludeCourierVendorIDs, maxDeliveryFee, forceCreate); err == nil {
if forceCreate {
order.DeliveryFlag |= model.OrderDeliveryFlagMaskScheduleDisabled
err = partner.CurOrderManager.UpdateOrderStatusAndDeliveryFlag(order)
}
if err == nil {
if forceCreate {
s.stopTimer(savedOrderInfo)
}
//门店发单开始扣钱
if order.CreateDeliveryType == model.YES {
deliveryFeeMap, _ := s.QueryOrderWaybillFeeInfoEx(ctx, order.VendorOrderID, order.VendorID)
isEqual, isZero, _ := partner.CurStoreAcctManager.CheckStoreAcctExpendExist(order.VendorOrderID)
if !isZero && !isEqual {
var newPrice int64
if len(courierVendorIDs) == 1 {
courierVendorID := courierVendorIDs[0]
if _, ok := deliveryFeeMap[courierVendorID]; ok {
newPrice = deliveryFeeMap[courierVendorID].DeliveryFee
}
} else if len(courierVendorIDs) == 0 {
var maxFee int64
for _, v := range deliveryFeeMap {
if v.DeliveryFee > maxFee {
v.DeliveryFee = maxFee
}
}
newPrice = maxFee
}
expend, lastFee, _ := partner.CurStoreAcctManager.GetStoreAcctExpendLastCreateWayBillFee(order.VendorOrderID)
if int(newPrice) > lastFee {
partner.CurStoreAcctManager.InsertStoreAcctExpendAndUpdateStoreAcctBalance(ctx, jxutils.GetSaleStoreIDFromOrder(order), int(newPrice)-lastFee, partner.StoreAcctTypeExpendCreateWaybill2ndMore, order.VendorOrderID, expend.ID)
}
} else {
if len(courierVendorIDs) == 1 {
courierVendorID := courierVendorIDs[0]
if _, ok := deliveryFeeMap[courierVendorID]; ok {
partner.CurStoreAcctManager.InsertStoreAcctExpendAndUpdateStoreAcctBalance(ctx, jxutils.GetSaleStoreIDFromOrder(order), int(deliveryFeeMap[courierVendorID].DeliveryFee), partner.StoreAcctTypeExpendCreateWaybillEx, order.VendorOrderID, 0)
}
} else if len(courierVendorIDs) == 0 {
var maxFee int64
for _, v := range deliveryFeeMap {
if v.DeliveryFee > maxFee {
v.DeliveryFee = maxFee
}
}
partner.CurStoreAcctManager.InsertStoreAcctExpendAndUpdateStoreAcctBalance(ctx, jxutils.GetSaleStoreIDFromOrder(order), int(maxFee), partner.StoreAcctTypeExpendCreateWaybillEx, order.VendorOrderID, 0)
}
}
}
globals.SugarLogger.Debugf("CreateWaybillOnProviders4SavedOrder orderID:%s userName:%s successfully", order.VendorOrderID, ctx.GetUserName())
return bills, err
}
}
}
if err != nil {
globals.SugarLogger.Debugf("CreateWaybillOnProviders4SavedOrder orderID:%s failed with error:%v", order.VendorOrderID, err)
}
return nil, err
}
func (s *DefScheduler) CreateWaybillOnProvidersEx(ctx *jxcontext.Context, vendorOrderID string, vendorID int, courierVendorIDs []int, forceCreate bool, maxDeliveryFee int64) (bills []*model.Waybill, errCode string, err error) {
savedOrderInfo := s.loadSavedOrderByID(vendorOrderID, vendorID, true)
if savedOrderInfo != nil {
order := savedOrderInfo.order
//1表示为门店发单需要验证门店账户余额情况
if errCode, err = s.CheckStoreBalance(ctx, order, courierVendorIDs); err != nil {
return nil, errCode, err
}
}
jxutils.CallMsgHandler(func() {
bills, err = func() (bills []*model.Waybill, err error) {
userName := ctx.GetUserName()
globals.SugarLogger.Debugf("CreateWaybillOnProvidersEx orderID:%s userName:%s", vendorOrderID, userName)
if vendorID == model.VendorIDELM {
return nil, fmt.Errorf("不要直接使用饿了么订单号,请使用相应的饿百订单号")
}
savedOrderInfo := s.loadSavedOrderByID(vendorOrderID, vendorID, true)
if savedOrderInfo != nil {
order := savedOrderInfo.order
if order.DeliveryType == model.OrderDeliveryTypeSelfTake {
return nil, fmt.Errorf("订单:%s是自提单", vendorOrderID)
}
if !forceCreate {
err = s.isPossibleSwitch2SelfDelivery(order)
}
if err == nil {
if savedOrderInfo.order.VendorID == model.VendorIDEBAI {
courierVendorIDs = []int{model.VendorIDMTPS, model.VendorIDDada}
}
order := savedOrderInfo.order
order.DeliveryFlag = 0
err = partner.CurOrderManager.UpdateOrderStatusAndDeliveryFlag(order)
if bills, err = s.CreateWaybillOnProviders4SavedOrder(ctx, savedOrderInfo, courierVendorIDs, nil, forceCreate, maxDeliveryFee); err == nil && len(bills) > 0 {
partner.CurOrderManager.OnOrderMsg(order, "手动创建运单成功", fmt.Sprintf("%s创建%s平台运单,强发:%t,最高限价:%d", ctx.GetUserName(), model.VendorChineseNames[bills[0].WaybillVendorID], forceCreate, maxDeliveryFee))
}
}
} else {
err = scheduler.ErrCanNotFindOrder
}
globals.SugarLogger.Infof("CreateWaybillOnProvidersEx orderID:%s userName:%s error:%v", vendorOrderID, userName, err)
return bills, err
}()
}, jxutils.ComposeUniversalOrderID(vendorOrderID, vendorID))
return bills, errCode, err
}
func (s *DefScheduler) CheckStoreBalance(ctx *jxcontext.Context, order *model.GoodsOrder, courierVendorIDs []int) (errCode string, err error) {
if order.CreateDeliveryType == model.YES {
//暂时这么认为len courierVendorIDs 为1表示是老板或者运营从小程序上点的立即发单因为小程序上是点哪个发哪个
//京西后台则是点一下发3个len courierVendorIDs 是0
//如果是小程序上点哪个扣哪个平台的钱
//如果是后台,则选最高的那个扣
storeAcct, err := cms.GetStoreAcctBalance(ctx, jxutils.GetSaleStoreIDFromOrder(order))
deliveryFeeMap, _ := s.QueryOrderWaybillFeeInfoEx(ctx, order.VendorOrderID, order.VendorID)
if err != nil {
return errCode, fmt.Errorf("获取账户余额失败!")
}
//1、先判断是不是第一次发查询库里是否有这个订单的运费支出记录再查询是否有相同金额并且类型为回退的收入记录取消运单退回
//前者有,后者无, 表示已经发过了,暂未取消,若这这次的发单金额小于上次的金额则不进行判断也不多扣钱,若大于则扣除‘这次金额-上次金额’的钱,余额不足问题也根据这个判断
//前者有,后者有,表示发过并且取消过了,是多次发,直接扣
//前者无,表示就是第一次发,直接扣
//2、小程序里这次金额用发单平台的金额后台里这次金额用所有平台最高费用
isEqual, isZero, err := partner.CurStoreAcctManager.CheckStoreAcctExpendExist(order.VendorOrderID)
globals.SugarLogger.Debugf("CheckStoreBalance orderID :%v, isEqual : %v, isZero: %v", order.VendorOrderID, isEqual, isZero)
//表示前者有,后者无
if !isZero && !isEqual {
var newPrice int64
if len(courierVendorIDs) == 1 {
courierVendorID := courierVendorIDs[0]
if _, ok := deliveryFeeMap[courierVendorID]; ok {
newPrice = deliveryFeeMap[courierVendorID].DeliveryFee
}
} else if len(courierVendorIDs) == 0 {
var maxFee int64
for _, v := range deliveryFeeMap {
if v.DeliveryFee > maxFee {
v.DeliveryFee = maxFee
}
}
newPrice = maxFee
}
_, lastFee, _ := partner.CurStoreAcctManager.GetStoreAcctExpendLastCreateWayBillFee(order.VendorOrderID)
if int(newPrice) > lastFee {
if storeAcct.AccountBalance < int(newPrice)-lastFee {
return model.ErrCodeAccountBalanceNotEnough, fmt.Errorf("门店账户余额小于[%v]元,不能发配送!", jxutils.IntPrice2Standard(newPrice-int64(lastFee)))
}
}
} else {
if storeAcct.AccountBalance < partner.MinCreateWaybillBalance {
return model.ErrCodeAccountBalanceNotEnough, fmt.Errorf("门店账户余额小于[%v]元,不能发配送!", jxutils.IntPrice2Standard(partner.MinCreateWaybillBalance))
}
if len(courierVendorIDs) == 1 {
courierVendorID := courierVendorIDs[0]
if _, ok := deliveryFeeMap[courierVendorID]; ok {
if deliveryFeeMap[courierVendorID].DeliveryFee > int64(storeAcct.AccountBalance) {
return model.ErrCodeAccountBalanceNotEnough, fmt.Errorf("门店账户余额小于[%v]元,不能发配送!", jxutils.IntPrice2Standard(deliveryFeeMap[courierVendorID].DeliveryFee))
}
}
} else if len(courierVendorIDs) == 0 {
var maxFee int64
for _, v := range deliveryFeeMap {
if v.DeliveryFee > maxFee {
v.DeliveryFee = maxFee
}
}
if maxFee > int64(storeAcct.AccountBalance) {
return model.ErrCodeAccountBalanceNotEnough, fmt.Errorf("门店账户余额小于[%v]元,不能发配送!", jxutils.IntPrice2Standard(maxFee))
}
}
}
}
return errCode, err
}
// todo 这个函数可以和SelfDeliveringAndUpdateStatus合并
func (s *DefScheduler) CancelAll3rdWaybills(ctx *jxcontext.Context, vendorOrderID string, vendorID int, isStopSchedule bool) (err error) {
jxutils.CallMsgHandler(func() {
err = func() (err error) {
globals.SugarLogger.Infof("CancelAll3rdWaybills orderID:%s userName:%s", vendorOrderID, ctx.GetUserName())
savedOrderInfo := s.loadSavedOrderByID(vendorOrderID, vendorID, true)
if savedOrderInfo != nil {
err = s.cancelOtherWaybills(savedOrderInfo, nil, partner.CancelWaybillReasonOther, partner.CancelWaybillReasonStrActive)
} else {
err = scheduler.ErrCanNotFindOrder
}
globals.SugarLogger.Infof("CancelAll3rdWaybills orderID:%s userName:%s error:%v", vendorOrderID, ctx.GetUserName(), err)
if err == nil && isStopSchedule {
order := savedOrderInfo.order
order.DeliveryFlag |= model.OrderDeliveryFlagMaskScheduleDisabled
if err = partner.CurOrderManager.UpdateOrderStatusAndDeliveryFlag(order); err == nil {
s.stopTimer(savedOrderInfo)
globals.SugarLogger.Infof("CancelAll3rdWaybills orderID:%s userName:%s successfully", vendorOrderID, ctx.GetUserName())
}
}
return err
}()
}, jxutils.ComposeUniversalOrderID(vendorOrderID, vendorID))
return err
}
func (s *DefScheduler) QueryOrderWaybillFeeInfoEx(ctx *jxcontext.Context, vendorOrderID string, vendorID int) (deliveryFeeMap map[int]*partner.WaybillFeeInfo, err error) {
jxutils.CallMsgHandler(func() {
deliveryFeeMap, err = func() (deliveryFeeMap map[int]*partner.WaybillFeeInfo, err error) {
userName := ctx.GetUserName()
globals.SugarLogger.Infof("GetWaybillsInfoEx orderID:%s userName:%s", vendorOrderID, userName)
db := dao.GetDB()
order, err := partner.CurOrderManager.LoadOrder(vendorOrderID, vendorID)
if err != nil {
return nil, err
}
if order.DeliveryType == model.OrderDeliveryTypeSelfTake {
return nil, fmt.Errorf("订单:%s是自提单", vendorOrderID)
}
storeCourierList, err := dao.GetStoreCourierList(db, []int{jxutils.GetSaleStoreIDFromOrder(order)}, nil, model.StoreStatusAll, model.StoreAuditStatusOnline)
if err != nil {
return nil, err
}
waybillList, err := partner.CurOrderManager.GetOrderWaybillInfo(ctx, vendorOrderID, vendorID, true, false)
if err != nil {
return nil, err
}
waybillMap := make(map[int]*model.Waybill)
for _, bill := range waybillList {
waybillMap[bill.WaybillVendorID] = &bill.Waybill
}
deliveryFeeMap = make(map[int]*partner.WaybillFeeInfo)
var timeoutSecond int
if savedOrderInfo := s.loadSavedOrderByID(vendorOrderID, vendorID, false); savedOrderInfo != nil {
timeoutSecond = savedOrderInfo.GetCreateWaybillTimeout()
}
for _, storeCourier := range storeCourierList {
var feeInfo *partner.WaybillFeeInfo
if waybillMap[storeCourier.VendorID] != nil {
feeInfo = &partner.WaybillFeeInfo{
Waybill: waybillMap[storeCourier.VendorID],
}
} else {
if storeCourier.Status != model.StoreStatusOpened {
feeInfo = &partner.WaybillFeeInfo{
ErrCode: partner.WaybillFeeErrCodeCourierNotOpen,
ErrStr: fmt.Sprintf("暂未开通,联系运营"),
}
} else {
if handler := partner.GetDeliveryPlatformFromVendorID(storeCourier.VendorID); handler != nil {
if handler.Use4CreateWaybill {
if feeInfo, err = handler.Handler.GetWaybillFee(order); err != nil {
feeInfo = &partner.WaybillFeeInfo{
ErrCode: partner.WaybillFeeErrCodeCourierOthers,
ErrStr: err.Error(),
}
} else {
feeInfo.TimeoutSecond = timeoutSecond
}
} else {
feeInfo = &partner.WaybillFeeInfo{
ErrCode: partner.WaybillFeeErrCodeCourierForbidden,
ErrStr: fmt.Sprintf("内部错误,%d不能用于创建运单", storeCourier.VendorID),
}
}
} else {
feeInfo = &partner.WaybillFeeInfo{
ErrCode: partner.WaybillFeeErrCodeCourierNotSupported,
ErrStr: fmt.Sprintf("内部错误,%d不被支持", storeCourier.VendorID),
}
}
}
}
deliveryFeeMap[storeCourier.VendorID] = feeInfo
}
err = nil
return deliveryFeeMap, err
}()
}, jxutils.ComposeUniversalOrderID(vendorOrderID, vendorID))
return deliveryFeeMap, err
}

View File

@@ -1,47 +0,0 @@
package scheduler
import (
"errors"
"git.rosy.net.cn/jx-callback/business/model"
)
const (
StoreDeliveryTypeCrowdSourcing = 0 //缺省,平台众包配送,可转自送
StoreDeliveryTypeByPlatform = 1 //平台专送
StoreDeliveryTypeByStore = 2 //完全门店自送,这个表示的意思是平台的门店属性(就是购物平台不负责配送),而不是真正是否是老板自己送
)
const (
TimerStatusTypeUnknown = -1
TimerStatusTypeOrder = 0
TimerStatusTypeWaybill = 1
)
var (
CurrentScheduler IScheduler
)
var (
ErrOrderStatusIsNotSuitable4CurOperation = errors.New("订单锁定或状态不适合当前操作")
ErrOrderStatusAlreadySatisfyCurOperation = errors.New("订单当前状态已满足当前操作")
ErrCanNotCreateAtLeastOneWaybill = errors.New("一个运单都不能创建")
ErrCanNotFindOrder = errors.New("不能找到订单(一般是由于事件错序)")
ErrCanNotFindWaybill = errors.New("不能找到运单(一般是由于事件错序)")
ErrOrderIsNotSolid = errors.New("订单是临时订单,不完整,不能用于创建运单")
ErrDeliverProviderWrong = errors.New("快递商不存在或不能用于创建运单")
)
type IScheduler interface {
// 以下是订单
OnOrderNew(order *model.GoodsOrder, isPending bool, isAuto bool) (err error)
OnOrderStatusChanged(order *model.GoodsOrder, status *model.OrderStatus, isPending bool) (err error)
// 以下是运单
OnWaybillStatusChanged(bill *model.Waybill, isPending bool) (err error)
// 以下是售后单
OnAfsOrderNew(order *model.AfsOrder, isPending bool) (err error)
OnAfsOrderStatusChanged(order *model.AfsOrder, status *model.OrderStatus, isPending bool) (err error)
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,206 +0,0 @@
package act
import (
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/globals/testinit"
"testing"
"git.rosy.net.cn/jx-callback/business/model"
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/ebai"
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/jd"
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/mtwm"
)
func init() {
testinit.Init()
}
func TestInitDb(t *testing.T) {
dao.ExecuteSQL(dao.GetDB(), `
DROP TABLE IF EXISTS act, act_map, act_order_rule, act_store_sku, act_store_sku_map;
`)
}
func TestCreateActOnAlpha(t *testing.T) {
actStoreSkuList := []*ActStoreSkuParam{
&ActStoreSkuParam{
ActStoreSku: model.ActStoreSku{
StoreID: 2,
SkuID: 2142,
},
},
&ActStoreSkuParam{
ActStoreSku: model.ActStoreSku{
StoreID: 2,
SkuID: 1162,
},
},
&ActStoreSkuParam{
ActStoreSku: model.ActStoreSku{
StoreID: 2,
SkuID: 1167,
},
},
&ActStoreSkuParam{
ActStoreSku: model.ActStoreSku{
StoreID: 2,
SkuID: 1172,
},
},
}
t.Log(utils.Format4Output(actStoreSkuList, true))
// actID, err := CreateAct(jxcontext.AdminCtx, &model.Act{
// Name: "测试活动",
// PricePercentage: 80,
// Type: model.ActSkuDirectDown,
// }, []int{model.VendorIDJD, model.VendorIDMTWM, model.VendorIDEBAI}, nil, actStoreSkuList, false)
// if err != nil {
// t.Fatal(err)
// }
// globals.SugarLogger.Debug(actID)
}
func TestCreateActOnDev(t *testing.T) {
//actStoreSkuList := []*ActStoreSkuParam{
// &ActStoreSkuParam{
// ActStoreSku: model.ActStoreSku{
// StoreID: 100884,
// SkuID: 22716,
// },
// },
// &ActStoreSkuParam{
// ActStoreSku: model.ActStoreSku{
// StoreID: 100884,
// SkuID: 22717,
// },
// },
// &ActStoreSkuParam{
// ActStoreSku: model.ActStoreSku{
// StoreID: 100920,
// SkuID: 22714,
// },
// },
// &ActStoreSkuParam{
// ActStoreSku: model.ActStoreSku{
// StoreID: 100920,
// SkuID: 22715,
// },
// },
// // &ActStoreSkuParam{
// // ActStoreSku: model.ActStoreSku{
// // StoreID: 100119,
// // SkuID: 26595,
// // },
// // },
//}
// t.Log(utils.Format4Output(actStoreSkuList, true))
//actID, err := CreateAct(jxcontext.AdminCtx, &model.Act{
// Name: "测试活动",
// PricePercentage: 80,
// Type: model.ActSkuDirectDown,
// BeginAt: time.Now().Add(-24 * time.Hour),
// EndAt: time.Now().Add(10 * 24 * time.Hour),
//}, []int{model.VendorIDJD, model.VendorIDMTWM /*, model.VendorIDEBAI*/}, nil, actStoreSkuList, false)
//if err != nil {
// t.Fatal(err)
//}
//globals.SugarLogger.Debug(actID)
}
func TestCancelAct(t *testing.T) {
err := CancelAct(jxcontext.AdminCtx, 1)
if err != nil {
t.Fatal(err)
}
}
func TestDeleteActStoreBind(t *testing.T) {
_, err := DeleteActStoreSkuBind(jxcontext.AdminCtx, dao.GetDB(), 1, []*ActStoreSkuParam{
// &ActStoreSkuParam{
// ActStoreSku: model.ActStoreSku{
// StoreID: 100119,
// SkuID: 30828,
// },
// },
// &ActStoreSkuParam{
// ActStoreSku: model.ActStoreSku{
// StoreID: 100119,
// SkuID: 30827,
// },
// },
&ActStoreSkuParam{
ActStoreSku: model.ActStoreSku{
StoreID: 100884,
SkuID: 22716,
},
},
&ActStoreSkuParam{
ActStoreSku: model.ActStoreSku{
StoreID: 100884,
SkuID: 22717,
},
},
})
if err != nil {
t.Fatal(err)
}
}
func TestAddActStoreBind(t *testing.T) {
err := AddActStoreSkuBind(jxcontext.AdminCtx, dao.GetDB(), 1, []*ActStoreSkuParam{
// &ActStoreSkuParam{
// ActStoreSku: model.ActStoreSku{
// StoreID: 100119,
// SkuID: 30828,
// },
// },
// &ActStoreSkuParam{
// ActStoreSku: model.ActStoreSku{
// StoreID: 100119,
// SkuID: 30827,
// },
// },
&ActStoreSkuParam{
ActStoreSku: model.ActStoreSku{
StoreID: 100884,
SkuID: 22716,
},
},
&ActStoreSkuParam{
ActStoreSku: model.ActStoreSku{
StoreID: 100884,
SkuID: 22717,
},
},
})
if err != nil {
t.Fatal(err)
}
}
func TestSyncAct(t *testing.T) {
_, err := SyncAct(jxcontext.AdminCtx, nil, 1, nil, false)
if err != nil {
t.Fatal(err)
}
}
func TestForceUpdateVendorPrice(t *testing.T) {
//hint, err := ForceUpdateVendorPrice(jxcontext.AdminCtx, model.VendorIDJD, model.ActSkuDirectDown, []*ActStoreSkuParam{
// &ActStoreSkuParam{
// ActStoreSku: model.ActStoreSku{
// StoreID: 100118,
// SkuID: 22509,
// ActPrice: 9900,
// },
// VendorPrice: 19900,
// },
//}, false)
//if err != nil {
// t.Fatal(err)
//}
//t.Log(hint)
}

View File

@@ -1,130 +0,0 @@
package cms
import (
"git.rosy.net.cn/jx-callback/business/auth2"
"git.rosy.net.cn/jx-callback/business/auth2/authprovider/weixin"
"git.rosy.net.cn/jx-callback/business/authz/autils"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/business/model/legacymodel"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/globals/api2"
)
// todo 是否需要将Store.MarketManPhone与OperatorPhone成角色
func TransferLegacyWeixins(mobile string) (err error) {
globals.SugarLogger.Debugf("TransferLegacyWeixins mobile:%s", mobile)
if !globals.EnableWXAuth2 || globals.DisableWXAuth1 {
return nil
}
remark4Transfer := "transfer"
// DELETE t1
// FROM auth_bind t1
// WHERE t1.remark = 'transfer';
// DELETE t1
// FROM user t1
// WHERE t1.remark = 'transfer';
// TRUNCATE TABLE casbin_rule;
sql := `
SELECT t1.*
FROM weixins t1
LEFT JOIN user t2 ON t2.mobile = t1.tel
LEFT JOIN auth_bind t3 ON t3.auth_id = t1.openid AND t3.type = 'weixinsns'
LEFT JOIN auth_bind t4 ON t4.auth_id = t1.openid_mini AND t4.type = 'weixinmini'
WHERE`
sqlParams := []interface{}{}
if mobile != "" {
remark4Transfer = "transfer2"
sql += " t1.tel = ?"
sqlParams = append(sqlParams, mobile)
} else {
sql += " t2.id IS NULL OR (t1.openid <> '' AND t3.id IS NULL) OR (t1.openid_mini <> '' AND t4.id IS NULL)"
}
sql += " ORDER BY t1.parentid;"
var weixinList []*legacymodel.WeiXins
db := dao.GetDB()
err = dao.GetRows(db, &weixinList, sql, sqlParams...)
if err != nil {
return err
}
parentMap := make(map[int]*legacymodel.WeiXins)
for _, v := range weixinList {
if v.ParentID == -1 {
parentMap[v.ID] = v
} else {
if parentMap[v.ParentID] != nil {
v.JxStoreID = parentMap[v.ParentID].JxStoreID
}
}
if v.Tel != "" {
user := &model.User{
UserID2: v.Tel,
Name: v.NickName,
Mobile: &v.Tel,
Type: model.UserTypeStoreBoss,
Remark: remark4Transfer,
}
if user.Name == "" {
user.Name = user.GetMobile()
}
userList, _, err2 := dao.GetUsers(db, 0, "", nil, nil, []string{v.Tel}, 0, -1)
if err = err2; err != nil {
return err
}
// globals.SugarLogger.Debug(utils.Format4Output(user, false))
if len(userList) == 0 {
err = CreateUser(user, v.LastOperator)
} else {
user = userList[0]
}
if err != nil {
return err
}
if v.OpenID != "" {
auth2.AddAuthBind(user, &auth2.AuthInfo{
AuthBindInfo: &auth2.AuthBindEx{
AuthBind: model.AuthBind{
Type: weixin.AuthTypeMP,
AuthID: v.OpenID,
AuthID2: v.OpenIDUnion,
Remark: remark4Transfer,
},
},
})
}
if v.OpenIDMini != "" {
auth2.AddAuthBind(user, &auth2.AuthInfo{
AuthBindInfo: &auth2.AuthBindEx{
AuthBind: model.AuthBind{
Type: weixin.AuthTypeMini,
AuthID: v.OpenIDMini,
AuthID2: v.OpenIDUnion,
Remark: remark4Transfer,
},
},
})
}
if v.JxStoreID > 0 { // 运营就不加到门店老板组里了
if user.Type&model.UserTypeOperator == 0 {
api2.RoleMan.AddRole4User(user.GetID(), autils.NewStoreBossRole(v.JxStoreID))
}
} else {
if mobile != "" {
rList, err2 := api2.RoleMan.GetUserRoleList(user.GetID())
if err = err2; err == nil {
for _, role := range rList {
if role.StoreID > 0 {
api2.RoleMan.DeleteRole4User(user.GetID(), autils.NewStoreBossRole(role.StoreID))
}
}
}
}
}
}
}
return err
}

View File

@@ -1,30 +0,0 @@
package cms
import (
"testing"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/globals/api2"
"git.rosy.net.cn/jx-callback/business/authz/autils"
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/ebai"
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/elm"
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/jd"
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/mtwm"
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/weimob/wsc"
)
func TestTransferLegacyWeixins(t *testing.T) {
err := TransferLegacyWeixins("")
if err != nil {
t.Fatal(err)
}
}
func TestCasbin(t *testing.T) {
userList, err := api2.RoleMan.GetRoleUserList(autils.NewStoreBossRole(100324))
t.Log(utils.Format4Output(userList, false))
if err != nil {
t.Fatal(err)
}
}

View File

@@ -2,32 +2,17 @@ package cms
import (
"fmt"
"git.rosy.net.cn/baseapi/platformapi/mtunionapi"
"reflect"
"regexp"
"strconv"
"strings"
"time"
"git.rosy.net.cn/jx-callback/business/partner/purchase/ebai"
"git.rosy.net.cn/baseapi/utils/errlist"
"git.rosy.net.cn/jx-callback/globals/api2"
"git.rosy.net.cn/baseapi/platformapi/dingdingapi"
"git.rosy.net.cn/jx-callback/business/auth2/authprovider/mobile"
"git.rosy.net.cn/jx-callback/business/authz/autils"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils/ddmsg"
"git.rosy.net.cn/jx-callback/business/dao"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/globals/api"
)
const (
@@ -43,61 +28,8 @@ type SysConfigLimit struct {
}
var (
serviceInfo map[string]interface{}
allowUpdatePlaceFieldsMap = map[string]bool{
"name": true,
"enabled": true,
"mtpsPrice": true,
}
serviceInfo map[string]interface{}
regexpMsgContentOpID = regexp.MustCompile(`"openid":"(.*?)"`)
receiveMsgUsersMap = map[string][]string{
SendMsgTypeOpenStoreRequest: []string{
"石锋",
// "x",
// "周扬",
},
SendMsgTypeSuggestRequest: []string{
"石锋",
// "x",
// "周扬",
// "苏尹岚",
},
}
needConfirmRequestMap = map[string]int{
SendMsgTypeOpenStoreRequest: 1,
}
SysConfigLimitMap = map[string]*SysConfigLimit{
model.ConfigSysEbaiBoxFee: &SysConfigLimit{
ValueType: reflect.Int,
MinValue: 0,
MaxValue: 500,
AfterChanged: func() (err error) {
_, err = dao.SetStoreMapSyncStatus(dao.GetDB(), []int{model.VendorIDEBAI}, nil, model.SyncFlagModifiedMask)
return err
},
},
model.ConfigSysMtwmBoxFee: &SysConfigLimit{
ValueType: reflect.Int,
MinValue: 0,
MaxValue: 500,
AfterChanged: func() (err error) {
_, err = dao.SetStoreMapSyncStatus(dao.GetDB(), []int{model.VendorIDMTWM}, nil, model.SyncFlagModifiedMask)
return err
},
},
model.ConfigSysMtwmSkuBoxFee: &SysConfigLimit{
ValueType: reflect.Int,
MinValue: 0,
MaxValue: 50,
AfterChanged: func() (err error) {
_, err = dao.SetStoreSkuSyncStatus(dao.GetDB(), model.VendorIDMTWM, nil, nil, model.SyncFlagModifiedMask)
return err
},
},
}
)
func InitServiceInfo(version string, buildTime time.Time, gitCommit string) {
@@ -111,49 +43,41 @@ func InitServiceInfo(version string, buildTime time.Time, gitCommit string) {
"buildTime": buildTimeStr,
"gitCommit": gitCommit,
"metaData": map[string]interface{}{
"skuNamePrefix": model.SkuNamePrefixNames,
"skuNameUnit": model.UnitNames,
"skuSpecUnit": model.SpecUnitNames,
"skuStatus": model.SkuStatusName,
"storeDeliveryRangeType": model.DeliveryRangeTypeName,
"storeDeliveryType": model.DeliveryTypeName,
"storeStatus": model.StoreStatusName,
"categoryType": model.CategoryTypeName,
"vendorTypeName": model.VendorTypeName,
"vendorName": model.VendorChineseNames,
"vendorTypeName": model.VendorTypeName,
"vendorName": model.VendorChineseNames,
//"vendorImg": model.VendorImg,
//"vendorColors": model.VendorColors,
"orderStatus": model.OrderStatusName,
"waybillStatus": model.WaybillStatusName,
"orderTypeName": model.OrderTypeName,
"taskStatusName": tasksch.TaskStatusName,
"opRequestTypeName": model.RequestTypeName,
"opRequestStatusName": model.RequestStatusName,
"storeMsgSendStatusName": model.StoreMsgSendStatusName,
"shopChineseNames": model.ShopChineseNames,
"printerVendorInfo": model.PrinterVendorInfo,
"printerStatusName": partner.PrinterStatusName,
"purchaseVendorInfo": model.PurchaseVendorInfo,
"afsReasonTypeName": model.AfsReasonTypeName,
"afsAppealTypeName": model.AfsAppealTypeName,
"actTypeName": model.ActTypeName,
"actStatusName": model.ActStatusName,
"actCreateTypeName": model.ActCreateTypeName,
"storeAuditStatusName": model.StoreAuditStatusName,
"configTypeName": model.ConfigTypeName,
"autoSaleAt": AutoSaleAtStr,
"userTypeName": model.UserTypeName,
"storePriceTypeName": model.StorePriceTypeName,
"payStatusName": model.PayStatusName,
"refundStatusName": model.RefundStatusName,
"autoReplyTypeName": model.AutoReplyTypeName,
"complaintReasons": model.ComplaintReasons,
"supplementType": model.SupplementTypeName,
"operateType": model.OperateTypeName,
"thingType": model.ThingTypeName,
"apiFunctionName": model.ApiFunctionName,
"vendorStatus": model.VendorStatus,
"couponsStatus": model.CouponStatusName,
"ebaiSupplierID": ebai.EbaiSupplierIDMap,
"ebaiSupplierInfo": ebai.EbaiSupplierInfo,
"unionActTypeNames": map[int]map[int]interface{}{
model.VendorIDMTWM: map[int]interface{}{
mtunionapi.ActTypeQB: "券包推广",
},
//model.VendorIDTB: map[int]interface{}{
// tbunionapi.TbElmActTypeBDH: "本地化",
//},
//model.VendorIDPDD: map[int]interface{}{
// 1: "进行中的活动",
//},
model.VendorIDJDShop: map[int]interface{}{
2: "进行中",
},
},
"unionOrderStatusName": model.UnionOrderStatusName,
},
}
}
@@ -195,213 +119,15 @@ func GetPlaces(ctx *jxcontext.Context, keyword string, includeDisabled bool, par
return places, dao.GetRows(nil, &places, sql, sqlParams)
}
func UpdatePlaces(ctx *jxcontext.Context, places []map[string]interface{}, userName string) (num int64, err error) {
if len(places) == 0 {
return 0, ErrMissingInput
}
updateFields := []string{}
for k := range places[0] {
if allowUpdatePlaceFieldsMap[k] {
updateFields = append(updateFields, k)
}
}
for _, place := range places {
if place["code"] == nil {
return 0, ErrMissingInput
}
placeid := &model.Place{}
valid := dao.NormalMakeMapByFieldList(place, updateFields, userName)
if num, err = dao.UpdateEntityLogically(nil, placeid, valid, userName, utils.Params2Map("Code", place["code"])); err != nil {
return num, err
}
}
return num, err
}
func UpdatePlace(ctx *jxcontext.Context, placeCode int, payload map[string]interface{}, userName string) (num int64, err error) {
payload["code"] = placeCode
return UpdatePlaces(ctx, []map[string]interface{}{payload}, userName)
}
func GetCoordinateDistrictCode(ctx *jxcontext.Context, lng, lat float64) (code int, err error) {
return api.AutonaviAPI.GetCoordinateDistrictCode(lng, lat), nil
}
func GetCoordinateCityInfo(ctx *jxcontext.Context, lng, lat float64) (name string, err error) {
name, _ = api.AutonaviAPI.GetCoordinateCityInfo(lng, lat)
return name, err
}
func SendMsg2Somebody(ctx *jxcontext.Context, mobileNum, verifyCode, msgType, msgContent string) (err error) {
if needConfirmRequestMap[msgType] == 1 {
if _, err = mobile.AutherObj.VerifySecret(mobileNum, verifyCode); err != nil {
return err
}
}
db := dao.GetDB()
//获取门店信息
var (
stores []*model.Store
authBinds []*model.AuthBind
order *model.GoodsOrder
storeName string
storeID int
vendorOrderID string
)
if mobileNum != "" {
sql := `
SELECT * FROM store WHERE (tel1 = ? OR tel2 = ?) AND deleted_at = ?
`
sqlParams := []interface{}{mobileNum, mobileNum, utils.DefaultTimeValue}
err = dao.GetRows(db, &stores, sql, sqlParams)
if len(stores) > 0 {
storeName = stores[0].Name
storeID = stores[0].ID
}
if storeID == 0 {
results := regexpMsgContentOpID.FindStringSubmatch(msgContent)
if len(results) > 0 {
sql3 := `
SELECT * FROM auth_bind WHERE auth_id = ? OR auth_id2 = ?
`
sqlParams3 := []interface{}{results[1], results[1]}
err = dao.GetRows(db, &authBinds, sql3, sqlParams3)
if len(authBinds) > 0 {
user, _ := dao.GetUserByID(db, "user_id", authBinds[0].UserID)
mobileNum = *user.Mobile
sqlParams4 := []interface{}{mobileNum, mobileNum, utils.DefaultTimeValue}
err = dao.GetRows(db, &stores, sql, sqlParams4)
if len(stores) > 0 {
storeName = stores[0].Name
storeID = stores[0].ID
}
}
}
}
} else {
results := regexpMsgContentOpID.FindStringSubmatch(msgContent)
if len(results) > 0 {
sql3 := `
SELECT * FROM auth_bind WHERE auth_id = ? OR auth_id2 = ?
`
sqlParams3 := []interface{}{results[1], results[1]}
err = dao.GetRows(db, &authBinds, sql3, sqlParams3)
if len(authBinds) > 0 {
user, _ := dao.GetUserByID(db, "user_id", authBinds[0].UserID)
mobileNum = *user.Mobile
sql4 := `
SELECT * FROM store WHERE (tel1 = ? OR tel2 = ?) AND deleted_at = ?
`
sqlParams4 := []interface{}{mobileNum, mobileNum, utils.DefaultTimeValue}
err = dao.GetRows(db, &stores, sql4, sqlParams4)
if len(stores) > 0 {
storeName = stores[0].Name
storeID = stores[0].ID
}
}
}
}
sql2 := `
SELECT *
FROM goods_order
WHERE IF(store_id <> '', store_id, jx_store_id) = ?
ORDER BY order_created_at DESC
LIMIT 1
`
sqlParams2 := []interface{}{storeID}
err = dao.GetRow(db, &order, sql2, sqlParams2)
if order != nil {
vendorOrderID = order.VendorOrderID
}
if storeID == 0 {
vendorOrderID = ""
}
msgContent = msgContent + " 门店名称:" + storeName + " 门店ID" + utils.Int2Str(storeID) + " 最新订单号:" + vendorOrderID
for _, v := range receiveMsgUsersMap[msgType] {
user, err2 := dao.GetUserByID(db, "name", v)
if err2 == nil {
ddmsg.SendUserMessage(dingdingapi.MsgTyeText, user.GetID(), msgType, msgContent)
} else if err == nil {
err = err2
}
}
return err
}
func checkSysConfig(key, value string) (err error) {
if limit := SysConfigLimitMap[key]; limit != nil {
if limit.ValueType == reflect.Int {
int64Value, err2 := strconv.ParseInt(value, 10, 64)
if err = err2; err == nil {
if int64Value < limit.MinValue || int64Value > limit.MaxValue {
err = fmt.Errorf("配置%s,值%s超范围[%d,%d]", key, value, limit.MinValue, limit.MaxValue)
}
}
}
}
return err
}
func onSysConfigChanged(key, value string) (err error) {
if limit := SysConfigLimitMap[key]; limit != nil && limit.AfterChanged != nil {
err = limit.AfterChanged()
}
return err
}
func checkConfig(opFlag int, configType, key, value string) (err error) {
switch configType {
case model.ConfigTypePricePack:
if value != "" {
pricePack := dao.PricePercentagePack2Obj(value)
if pricePack == nil {
err = fmt.Errorf("配置:%s不合法", value)
}
}
case model.ConfigTypeFreightPack:
if value != "" {
freightPack := dao.FreightDeductionPack2Obj(value)
if freightPack == nil {
err = fmt.Errorf("配置:%s不合法", value)
} else {
var lastStage *model.FreightDeductionItem
for _, v := range freightPack.FreightDeductionList {
if lastStage != nil && lastStage.DeductFreight > v.DeductFreight {
err = fmt.Errorf("免运设置不合理:门槛:%s,免运金额:%s,门槛:%s,免运金额:%s",
jxutils.IntPrice2StandardString(int64(lastStage.BeginPrice)), jxutils.IntPrice2StandardString(int64(lastStage.DeductFreight)),
jxutils.IntPrice2StandardString(int64(v.BeginPrice)), jxutils.IntPrice2StandardString(int64(v.DeductFreight)))
return err
}
lastStage = v
}
}
}
case model.ConfigTypeBank:
if value != "" {
if model.BankName[key] == "" {
err = fmt.Errorf("此银行代码:%s不支持请联系开发", value)
}
}
case model.ConfigTypeRole:
case model.ConfigTypeSys:
if opFlag&( /*model.SyncFlagNewMask|*/ model.SyncFlagDeletedMask) != 0 {
err = fmt.Errorf("系统参数只支持修改或添加,不支持删除")
} else {
err = checkSysConfig(key, value)
}
case model.ConfigTypeJxStore:
case model.ConfigTypeCookie:
case model.ConfigTypeDiscountCard:
default:
err = fmt.Errorf("当前只支持配置:%s, 传入的配置类型:%s", utils.Format4Output(model.ConfigTypeName, true), configType)
}
return err
}
func AddConfig(ctx *jxcontext.Context, key, configType, value string) (err error) {
if err = checkConfig(model.SyncFlagNewMask, configType, key, value); err != nil {
return err
}
// if err = checkConfig(model.SyncFlagNewMask, configType, key, value); err != nil {
// return err
// }
db := dao.GetDB()
conf := &model.NewConfig{
@@ -412,75 +138,7 @@ func AddConfig(ctx *jxcontext.Context, key, configType, value string) (err error
dao.WrapAddIDCULDEntity(conf, ctx.GetUserName())
err = dao.CreateEntity(db, conf)
if configType == model.ConfigTypeSys && err == nil {
err = onSysConfigChanged(key, value)
}
return err
}
func DeleteConfig(ctx *jxcontext.Context, key, configType string) (err error) {
if err = checkConfig(model.SyncFlagDeletedMask, configType, key, ""); err != nil {
return err
}
db := dao.GetDB()
switch configType {
case model.ConfigTypePricePack:
storeMapList, err2 := dao.GetStoresMapList(db, nil, nil, nil, model.StoreStatusAll, model.StoreIsSyncYes, key, "", "")
if err = err2; err == nil {
var storeInfo []string
for _, v := range storeMapList {
storeInfo = append(storeInfo, fmt.Sprintf("门店:%d, 平台:%s", v.StoreID, model.VendorChineseNames[v.VendorID]))
}
if len(storeInfo) > 0 {
err = fmt.Errorf("还有门店在使用价格包:%s门店信息:%s", key, strings.Join(storeInfo, ","))
}
}
case model.ConfigTypeFreightPack:
storeMapList, err2 := dao.GetStoresMapList(db, nil, nil, nil, model.StoreStatusAll, model.StoreIsSyncYes, "", "", "")
if err = err2; err == nil {
var storeInfo []string
for _, v := range storeMapList {
if v.FreightDeductionPack == key {
storeInfo = append(storeInfo, fmt.Sprintf("门店:%d, 平台:%s", v.StoreID, model.VendorChineseNames[v.VendorID]))
}
}
if len(storeInfo) > 0 {
err = fmt.Errorf("还有门店在使用价格包:%s门店信息:%s", key, strings.Join(storeInfo, ","))
}
}
case model.ConfigTypeBank:
//todo
return fmt.Errorf("暂不支持删除银行")
case model.ConfigTypeRole:
errList := errlist.New()
userIDs, err2 := api2.RoleMan.GetRoleUserList(autils.NewRole(key, 0))
if err = err2; err == nil && len(userIDs) > 0 {
userList, totalCount, err2 := dao.GetUsers(dao.GetDB(), 0, "", userIDs, nil, nil, 0, -1)
if err = err2; err == nil && totalCount > 0 {
// todo
// err = fmt.Errorf("还有人员在使用角色:%s人员信息:%s", key, utils.MustMarshal(utils.Struct2Map(userList, "compact")))
err = fmt.Errorf("还有人员在使用角色:%s人员信息:%s", key, utils.Format4Output(userList, false))
}
}
errList.AddErr(err)
storeList, err2 := dao.GetStoreList(db, nil, nil, nil, nil, nil, key)
if err = err2; err == nil && len(storeList) > 0 {
storeIDs := make([]int, len(storeList))
for k, v := range storeList {
storeIDs[k] = v.ID
}
err = fmt.Errorf("还有门店在使用角色:%s门店信息:%s", key, utils.MustMarshal(storeIDs))
}
errList.AddErr(err)
err = errList.GetErrListAsOne()
}
if err == nil {
_, err = dao.DeleteEntityLogically(db, &model.NewConfig{}, nil, ctx.GetUserName(), map[string]interface{}{
"Key": key,
"Type": configType,
})
}
if configType == model.ConfigTypeSys && err == nil {
err = onSysConfigChanged(key, "")
// err = onSysConfigChanged(key, value)
}
return err
}
@@ -489,13 +147,10 @@ func UpdateConfig(ctx *jxcontext.Context, key, configType, value string) (hint s
if key == "" {
return "", fmt.Errorf("修改配置必须给定key")
}
if err = checkConfig(model.SyncFlagModifiedMask, configType, key, value); err != nil {
return "", err
}
hint = "1"
db := dao.GetDB()
txDB , _ := dao.Begin(db)
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, txDB)
@@ -515,54 +170,12 @@ func UpdateConfig(ctx *jxcontext.Context, key, configType, value string) (hint s
}
switch configType {
case model.ConfigTypePricePack:
storeMapList, err := dao.GetStoresMapList(db, nil, nil, nil, model.StoreStatusAll, model.StoreIsSyncYes, key, "", "")
if err != nil {
dao.Rollback(db, txDB)
return "", err
}
dao.Commit(db, txDB)
vendorStoreMap := make(map[int][]int)
for _, v := range storeMapList {
vendorStoreMap[v.VendorID] = append(vendorStoreMap[v.VendorID], v.StoreID)
}
for vendorID, storeIDs := range vendorStoreMap {
if vendorID != model.VendorIDJX {
dao.SetStoreSkuSyncStatus(db, vendorID, storeIDs, nil, model.SyncFlagPriceMask)
} else {
hint, err = ReCalculateJxPrice(db, ctx, storeIDs)
}
}
case model.ConfigTypeFreightPack:
dao.Commit(db, txDB)
storeMapList, err := dao.GetStoresMapList(db, nil, nil, nil, model.StoreStatusAll, model.StoreIsSyncYes, "", "", "")
if err != nil {
return "", err
}
for _, v := range storeMapList {
var storeMapList2 []*model.StoreMap
if v.FreightDeductionPack == key {
storeMapList2 = append(storeMapList2, v)
}
if len(storeMapList2) > 0 {
task := tasksch.NewParallelTask("同步门店配送免运", tasksch.NewParallelConfig().SetIsContinueWhenError(true), ctx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
storeMap := batchItemList[0].(*model.StoreMap)
_, err = CurVendorSync.SyncStore(ctx, db, storeMap.VendorID, storeMap.StoreID, false, ctx.GetUserName())
return retVal, err
}, storeMapList2)
tasksch.HandleTask(task, nil, true).Run()
if len(storeMapList2) < 5 {
_, err = task.GetResult(0)
} else {
hint = task.GetID()
}
}
}
default:
dao.Commit(db, txDB)
}
if configType == model.ConfigTypeSys && err == nil {
err = onSysConfigChanged(key, value)
// err = onSysConfigChanged(key, value)
}
return hint, err
}
@@ -570,17 +183,3 @@ func UpdateConfig(ctx *jxcontext.Context, key, configType, value string) (hint s
func QueryConfigs(key, configType, keyword string) (configList []*model.NewConfig, err error) {
return dao.QueryConfigs(dao.GetDB(), key, configType, keyword)
}
func GetCityBankBranches(ctx *jxcontext.Context, cityCode int, bankCode string) (info map[int]map[string][]string, err error) {
list, err := dao.GetCityBankBranches(dao.GetDB(), cityCode, bankCode)
if err == nil && len(list) > 0 {
info = make(map[int]map[string][]string)
for _, v := range list {
if info[v.CityCode] == nil {
info[v.CityCode] = make(map[string][]string)
}
info[v.CityCode][v.PayeeBankCode] = append(info[v.CityCode][v.PayeeBankCode], v.PayeeBankBranchName)
}
}
return info, err
}

View File

@@ -1,17 +0,0 @@
package cms
import (
"git.rosy.net.cn/jx-callback/globals/api2"
"git.rosy.net.cn/jx-callback/globals/testinit"
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/ebai"
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/elm"
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/jd"
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/mtwm"
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/weimob/wsc"
)
func init() {
testinit.Init()
api2.Init()
}

View File

@@ -4,10 +4,10 @@ import (
"time"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/dao"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
)
type MessageStatusExt struct {
@@ -65,20 +65,20 @@ func GetStoreMessages(ctx *jxcontext.Context, msgIDs, storeIDs, types []int, fro
pageSize = jxutils.FormalizePageSize(pageSize)
sqlParams = append(sqlParams, pageSize, offset)
db := dao.GetDB()
txDB , _ := dao.Begin(db)
txDB, _ := dao.Begin(db)
defer dao.Commit(db, txDB)
var msgList []*model.Message
// globals.SugarLogger.Debug(sql)
if err = dao.GetRowsTx(txDB, &msgList, sql, sqlParams...); err == nil {
pagedInfo = &model.PagedInfo{
TotalCount: dao.GetLastTotalRowCount2(db, txDB),
TotalCount: dao.GetLastTotalRowCountTx(txDB),
Data: msgList,
}
}
return pagedInfo, err
}
func GetStoreMessageStatuses(ctx *jxcontext.Context, msgIDs, storeIDs, confirmStatuss []int, fromReadCount, toReadCount int, fromTime, toTime time.Time, keyword string, offset, pageSize int) (pagedInfo *model.PagedInfo, err error) {
func GetStoreMessageStatuses(ctx *jxcontext.Context, msgIDs, storeIDs []int, fromReadCount, toReadCount int, fromTime, toTime time.Time, keyword string, offset, pageSize int) (pagedInfo *model.PagedInfo, err error) {
sql := `
SELECT SQL_CALC_FOUND_ROWS
t1.*,
@@ -92,10 +92,6 @@ func GetStoreMessageStatuses(ctx *jxcontext.Context, msgIDs, storeIDs, confirmSt
sql += " AND t1.store_id IN (" + dao.GenQuestionMarks(len(storeIDs)) + ")"
sqlParams = append(sqlParams, storeIDs)
}
if len(confirmStatuss) > 0 {
sql += " AND t1.confirm_status IN (" + dao.GenQuestionMarks(len(confirmStatuss)) + ")"
sqlParams = append(sqlParams, confirmStatuss)
}
if len(msgIDs) > 0 {
sql += " AND t1.message_id IN (" + dao.GenQuestionMarks(len(msgIDs)) + ")"
sqlParams = append(sqlParams, msgIDs)
@@ -124,14 +120,14 @@ func GetStoreMessageStatuses(ctx *jxcontext.Context, msgIDs, storeIDs, confirmSt
sql += " LIMIT ? OFFSET ?"
sqlParams = append(sqlParams, jxutils.FormalizePageSize(pageSize), offset)
db := dao.GetDB()
txDB , _ := dao.Begin(db)
txDB, _ := dao.Begin(db)
defer dao.Commit(db, txDB)
var msgStatusList []*MessageStatusExt
// globals.SugarLogger.Debug(sql)
// globals.SugarLogger.Debug(utils.Format4Output(sqlParams, false))
if err = dao.GetRowsTx(txDB, &msgStatusList, sql, sqlParams...); err == nil {
pagedInfo = &model.PagedInfo{
TotalCount: dao.GetLastTotalRowCount2(db, txDB),
TotalCount: dao.GetLastTotalRowCountTx(txDB),
Data: msgStatusList,
}
}

View File

@@ -1 +0,0 @@
package cms

View File

@@ -0,0 +1,445 @@
package cms
import (
"encoding/json"
"fmt"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/dao"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/model"
"net"
"regexp"
"time"
)
const (
sounda = "sounda" //提示音a
soundb = "soundb" //提示音b
soundc = "soundc" //提示音c
soundd = "soundd" //提示音d
sounde = "sounde" //报警音e
soundf = "soundf" //报警音f
soundg = "soundg" //报警音g
)
type PrintInfo struct {
PrintNo string
AppID int
}
var (
regexpMobile = regexp.MustCompile("^1(3[0-9]|4[01456879]|5[0-35-9]|6[2567]|7[0-8]|8[0-9]|9[0-35-9])\\d{8}$")
soundMap = map[string]string{
"sounda": "sounda",
"soundb": "soundb",
"soundc": "soundc",
"soundd": "soundd",
"sounde": "sounde",
"soundf": "soundf",
"soundg": "soundg",
}
)
func AddPrinter(appID int, printers []*model.AddPrinterParam) (err error) {
var (
db = dao.GetDB()
errs []error
)
if len(printers) > 50 {
return fmt.Errorf("一次最多只能绑定50台")
}
for _, v := range printers {
if printers2, _ := dao.GetPrinters(db, appID, v.PrintNo, 0, 0); len(printers2) > 0 {
// 代表打印机已经在小程序注册了,查询打印机授权门店
bindStoreList, err := dao.QueryPrintBindStore(v.PrintNo)
if err != nil {
errs = append(errs, fmt.Errorf("QueryPrintBindStore err : %v ", err))
continue
}
if len(bindStoreList) >= 5 {
errs = append(errs, fmt.Errorf("当前打印机绑定门店数据超过五个,无法继续绑定"))
continue
}
have := false
userId := ""
for _, bsl := range bindStoreList {
if bsl.StoreID == v.StoreId {
have = true
userId = bsl.UserId
}
}
if !have {
if err := dao.BindStoreList(printers[0], userId); err != nil {
errs = append(errs, fmt.Errorf("BindStoreList err : %v ", err))
continue
}
}
continue
}
//验证
if err = checkPrinterInfo(v.PrintNo, v.Name, "", "", 0); err != nil {
errs = append(errs, err)
continue
}
// 检查心跳
exits, err := dao.CheckHeard(v.PrintNo)
if err != nil {
errs = append(errs, fmt.Errorf("CheckHeard err : %v ", err))
continue
}
if !exits {
errs = append(errs, fmt.Errorf("打印机未激活,请激活后在绑定"))
continue
}
printer := &model.Printer{
AppID: appID,
PrintNo: v.PrintNo,
Name: v.Name,
IccID: "",
Status: model.PrinterStatusOffline,
Sound: "sounda",
PrintKey: v.SIM,
IsOnline: 0,
Volume: 1,
FlowFlag: 0,
OfflineCount: 0,
UserId: "system_user",
}
// 创建打印机
if err := InitPrint(printer, v); err != nil {
return err
}
}
if len(errs) > 0 {
err = jxutils.BuildErr(errs)
}
return err
}
func InitPrint(printer *model.Printer, printParam *model.AddPrinterParam) error {
txDb, _ := dao.Begin(dao.GetDB())
// 创建打印机
dao.WrapAddIDCULDEntity(printer, "")
if err := dao.CreateEntityTx(txDb, printer); err != nil {
txDb.Rollback()
return err
}
// 赋予打印机默认配置
day := time.Now()
param, err := MarshalJson2String(&model.PrintSetting{
CreatedAt: day,
UpdatedAt: day,
DeletedAt: utils.DefaultTimeValue,
PrintNo: printer.PrintNo,
CallNameSetting: 64, // 老板
BusinessOffLineVoice: 1, // 离线开关
BalanceNotEnoughVoice: 1, // 余额不足
EveryDayGreetVoice: 1, // 问好
BusinessPrintNum: 1, // 商户侧打印次数
CustomerPrintNum: 1, // 用户侧打印次数
})
if err != nil {
return err
}
if err := dao.CreateEntityTx(txDb, param); err != nil {
txDb.Rollback()
return err
}
// 初始化打印机账户
if err := dao.CreateEntityTx(txDb, &model.PrintBill{
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
PrintNo: param.PrintNo,
PrintBalance: 20000,
UserId: "system",
}); err != nil {
txDb.Rollback()
return err
}
// 初始化绑定信息
if err := dao.BindStoreList(printParam, ""); err != nil {
txDb.Rollback()
return err
}
defer txDb.Commit()
return err
}
// MarshalJson2String 工具类
func MarshalJson2String(param *model.PrintSetting) (*model.PrintSetting, error) {
// 语音设置
voiceSetting := &model.VoiceSettingDetail{
WaitOrderVoice: model.SettingOpen,
RiderTakeOrderVoice: model.SettingOpen,
ApplyUserOrderCancelVoice: model.SettingOpen,
ApplyRefundOrderVoice: model.SettingOpen,
ApplyRefundGoodsVoice: model.SettingOpen,
RefundGoodsVoice: model.SettingOpen,
ConfirmGoodsVoice: model.SettingOpen,
SuccessGoodsVoice: model.SettingOpen,
ConsultingPrint: model.SettingOpen,
ReminderVoice: model.SettingOpen,
CustomerRejectionVoice: model.SettingOpen,
CusterRefundVoice: model.SettingOpen,
LoseAuthorization: model.SettingOpen,
}
customerVoiceSettingByte, err := json.Marshal(voiceSetting)
if err != nil {
return nil, err
}
param.VoiceSetting = string(customerVoiceSettingByte)
// 打印设置
printSetting := &model.PrintSettingDetail{
UserOrderCancel: model.SettingOpen,
RefundOrder: model.SettingOpen,
BusinessOrderCancel: model.SettingOpen,
RiderTakeOrder: model.SettingOpen,
CusterRefundPrint: model.SettingOpen,
WaitOrderPrint: model.SettingOpen,
ApplyUserCancelOrder: model.SettingOpen,
ApplyUserRefund: model.SettingOpen,
OrderCancelSuccess: model.SettingOpen,
}
pickingSettingByte, err := json.Marshal(printSetting)
if err != nil {
return nil, err
}
param.PrintSetting = string(pickingSettingByte)
return param, nil
}
func checkPrinterInfo(printNo, name, sound, sim string, volume int) (err error) {
if printNo != "" {
}
if sim != "" {
//if regexpMobile.FindString(sim) == "" {
return fmt.Errorf("暂不支持修改sim卡号码print_no : %v ", printNo)
//}
}
if volume != 0 {
if volume <= 0 || volume > 5 {
return fmt.Errorf("请输入正确的音量1-5print_no : %v ", printNo)
}
}
if sound != "" {
if soundMap[sound] == "" {
return fmt.Errorf("请输入正确的提示音print_no : %v ", printNo)
}
}
if name != "" {
if len(name) > 255 {
return fmt.Errorf("打印机备注不能超过255个字符print_no : %v ", printNo)
}
}
return err
}
func DelPrinter(appID int, printNos []string, storeId string) (err error) {
var (
db = dao.GetDB()
errs []error
)
for _, v := range printNos {
if printers, _ := dao.GetPrinters(db, appID, v, 0, 0); len(printers) == 0 {
errs = append(errs, fmt.Errorf("该应用下未找到该打印机print_no : %v ", v))
continue
} else {
if err := dao.DeleteStoreList(printers[0].PrintNo, storeId); err != nil {
errs = append(errs, err)
continue
}
}
}
if len(errs) > 0 {
err = jxutils.BuildErr(errs)
}
return err
}
func UpdatePrinter(appID int, printNo string, name, sim, sound *string, volume *int) (err error) {
var (
db = dao.GetDB()
fields []string
)
//看有没有
if printers, _ := dao.GetPrinters(db, appID, printNo, 0, 0); len(printers) == 0 {
return fmt.Errorf("该应用下未找到该打印机print_no : %v", printNo)
} else {
if name != nil {
if *name != "" {
if len(*name) > 20 {
return fmt.Errorf("打印机备注不能超过20个字符print_no : %v ", printNo)
}
}
if printers[0].Name != *name {
printers[0].Name = *name
fields = append(fields, "name")
}
}
if sim != nil {
if *sim != "" {
//if regexpMobile.FindString(*sim) == "" {
return fmt.Errorf("暂不支持修改sim卡号码print_no : %v ", printNo)
//}
}
//if printers[0].SIM != *sim {
// printers[0].SIM = *sim
// fields = append(fields, "sim")
//}
}
if sound != nil {
if *sound != "" {
if soundMap[*sound] == "" {
return fmt.Errorf("请输入正确的提示音print_no : %v ", printNo)
}
}
if printers[0].Sound != *sound {
printers[0].Sound = *sound
fields = append(fields, "sound")
}
}
if volume != nil {
if *volume <= 0 || *volume > 5 {
return fmt.Errorf("请输入正确的音量 1-5print_no : %v ", printNo)
}
if printers[0].Volume != *volume {
printers[0].Volume = *volume
fields = append(fields, "volume")
}
}
if _, err = dao.UpdateEntity(db, printers[0], fields...); err != nil {
return err
}
}
return err
}
func DelPrinterSeq(appID int, printNo string) (err error) {
var (
db = dao.GetDB()
)
//看有没有
if printers, _ := dao.GetPrinters(db, appID, printNo, 0, 0); len(printers) == 0 {
return fmt.Errorf("该应用下未找到该打印机print_no : %v", printNo)
} else {
printMsgs, _ := dao.GetPrintMsgs(db, printNo, "", model.PrintMsgAll, model.PrintMsgSuccess)
for _, v := range printMsgs {
v.DeletedAt = time.Now()
if _, err = dao.UpdateEntity(db, v, "DeletedAt"); err != nil {
return err
}
}
}
return err
}
func DoPrintMsg(appID int, msgID, printNo, content string, orderNo string) (err error) {
var (
db = dao.GetDB()
)
//打印机必须绑定在该应用下才能打印
if printers, _ := dao.GetPrinters(db, appID, printNo, 0, 0); len(printers) == 0 {
return fmt.Errorf("未在该应用下获取到此打印机print_no %v", printNo)
}
printMsg := &model.PrintMsg{
PrintNo: printNo,
Content: content,
OrderNo: orderNo,
MsgID: msgID,
}
dao.WrapAddIDCULDEntity(printMsg, "")
if err = dao.CreateEntity(db, printMsg); err != nil {
return err
}
return err
}
type GetPrintMsgResult struct {
MsgID string `json:"msg_id"` //消息ID
PrintNo string `json:"print_no"` //打印机编号
OrderNo string `json:"order_no"` //订单序号
Content string `json:"content"` //订单内容
Status int `json:"status"` //打印状态
Comment string `json:"comment"` //失败原因
}
func GetPrintMsg(appID int, msgID string) (printMsg *GetPrintMsgResult, err error) {
var (
db = dao.GetDB()
)
if printMsgs, _ := dao.GetPrintMsgs(db, "", msgID, model.PrintMsgAll, model.PrintMsgAll); len(printMsgs) > 0 {
result := printMsgs[0]
printMsg = &GetPrintMsgResult{
MsgID: result.MsgID,
PrintNo: result.PrintNo,
OrderNo: result.OrderNo,
Content: result.Content,
Status: result.Status,
Comment: result.Comment,
}
return printMsg, err
} else {
return printMsg, fmt.Errorf("未找到该消息msg_id :%v", msgID)
}
}
func GetPrinterStatus(appID int, printNo string) (status int, err error) {
var (
db = dao.GetDB()
)
//看有没有
if printers, _ := dao.GetPrinters(db, appID, printNo, 0, 0); len(printers) == 0 {
return status, fmt.Errorf("该应用下未找到该打印机print_no : %v", printNo)
} else {
return printers[0].Status + printers[0].IsOnline, nil // 当两个值都唯一时->在线正常
server := "print.jxcs.net:8000"
tcpAddr, err := net.ResolveTCPAddr("tcp4", server)
if err != nil {
//os.Exit(1)
return status, err
}
conn, err := net.DialTCP("tcp", nil, tcpAddr)
if err != nil {
return status, err
}
status = connHandler(conn, &PrintInfo{
PrintNo: printNo,
AppID: appID,
})
return status, nil
}
}
func connHandler(c net.Conn, printInfo *PrintInfo) (status int) {
defer c.Close()
//缓冲
buf := make([]byte, 1024)
data, _ := json.Marshal(printInfo)
//写入数据
c.Write(data)
//服务器端返回的数据写入buf
n, _ := c.Read(buf)
status = utils.Str2Int(string(buf[:n]))
//服务器端回传的信息
fmt.Println("server response:", string(buf[:n]))
return status
}
//#region 打印机拼装模板
// QueryPrinterSetting 查询用户设置
func QueryPrinterSetting() {
}
//#endregion 打印机

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,181 +0,0 @@
package cms
import (
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/globals"
)
type StoreAcctManager struct {
}
var (
FixedStoreAcctManager *StoreAcctManager
)
func init() {
FixedStoreAcctManager = &StoreAcctManager{}
partner.InitStoreAcctManager(FixedStoreAcctManager)
}
func (s *StoreAcctManager) InsertStoreAcctIncome(ctx *jxcontext.Context, storeID, price, acctType int, vendorOrderID string, expendID int) (err error) {
var (
userID, userName string
goodsVendorOrderID string
db = dao.GetDB()
)
if ctx != nil {
userID = ctx.GetUserID()
userName = ctx.GetUserName()
goodsVendorOrderID = vendorOrderID
} else {
storeOrder := &model.StoreAcctOrder{
VendorOrderID: vendorOrderID,
}
if err = dao.GetEntity(db, storeOrder, "VendorOrderID"); err == nil && storeOrder.ID != 0 {
userID = storeOrder.UserID
userName = storeOrder.LastOperator
goodsVendorOrderID = storeOrder.GoodsVendorOrderID
}
}
storeAcctIncome := &model.StoreAcctIncome{
StoreID: storeID,
IncomePrice: price,
Type: acctType,
UserID: userID,
VendorOrderID: goodsVendorOrderID,
}
dao.WrapAddIDCULEntity(storeAcctIncome, userName)
if expendID != 0 {
storeAcctIncome.ExpID = expendID
}
err = dao.CreateEntity(db, storeAcctIncome)
globals.SugarLogger.Debugf("InsertStoreAcctIncome orderID: [%v] , price :[%v] , type :[%v]", vendorOrderID, price, acctType)
return err
}
func (s *StoreAcctManager) InsertStoreAcctExpend(ctx *jxcontext.Context, storeID, price, acctType int, vendorOrderID string, expendID int) (err error) {
var (
userID, userName string
db = dao.GetDB()
)
if ctx != nil {
userID = ctx.GetUserID()
userName = ctx.GetUserName()
} else {
storeOrder := &model.StoreAcctOrder{
VendorOrderID: vendorOrderID,
}
if err = dao.GetEntity(db, storeOrder, "VendorOrderID"); err == nil && storeOrder.ID != 0 {
userID = storeOrder.UserID
userName = storeOrder.LastOperator
}
}
storeAcctExpend := &model.StoreAcctExpend{
StoreID: storeID,
ExpendPrice: price,
Type: acctType,
UserID: userID,
VendorOrderID: vendorOrderID,
}
dao.WrapAddIDCULEntity(storeAcctExpend, userName)
if expendID != 0 {
storeAcctExpend.ExpID = expendID
}
err = dao.CreateEntity(db, storeAcctExpend)
globals.SugarLogger.Debugf("InsertStoreAcctExpend orderID: [%v] , price :[%v] , type :[%v]", vendorOrderID, price, acctType)
return err
}
func (s *StoreAcctManager) UpdateStoreAcctBalance(ctx *jxcontext.Context, storeID, price int, isIncome bool) (err error) {
var (
db = dao.GetDB()
)
globals.SugarLogger.Debugf("UpdateStoreAcctBalance storeID: [%v] , price :[%v] ,", storeID, price)
if ctx == nil {
ctx = jxcontext.AdminCtx
}
storeAcct := &model.StoreAcct{
StoreID: storeID,
}
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil || err != nil {
dao.Rollback(db, txDB)
if r != nil {
panic(r)
}
}
}()
if err = dao.GetEntity(db, storeAcct, "StoreID"); err != nil && dao.IsNoRowsError(err) {
//新增门店账单
dao.WrapAddIDCULEntity(storeAcct, ctx.GetUserName())
if err = dao.CreateEntityTx(txDB, storeAcct); err != nil {
dao.Rollback(db, txDB)
return err
}
} else {
globals.SugarLogger.Debugf("UpdateStoreAcctBalance1 storeID: [%v] , balance :[%v] ,", storeID, storeAcct.AccountBalance)
if isIncome {
storeAcct.AccountBalance += price
} else {
storeAcct.AccountBalance -= price
}
if _, err = dao.UpdateEntityTx(txDB, storeAcct, "AccountBalance"); err != nil {
dao.Rollback(db, txDB)
return err
}
globals.SugarLogger.Debugf("UpdateStoreAcctBalance2 storeID: [%v] , balance :[%v] ,", storeID, storeAcct.AccountBalance)
}
dao.Commit(db, txDB)
return err
}
func (s *StoreAcctManager) InsertStoreAcctExpendAndUpdateStoreAcctBalance(ctx *jxcontext.Context, storeID, price, acctType int, vendorOrderID string, expendID int) (err error) {
utils.CallFuncAsync(func() {
if err = s.InsertStoreAcctExpend(ctx, storeID, price, acctType, vendorOrderID, expendID); err == nil {
s.UpdateStoreAcctBalance(ctx, storeID, price, false)
}
})
return err
}
func (s *StoreAcctManager) InsertStoreAcctIncomeAndUpdateStoreAcctBalance(ctx *jxcontext.Context, storeID, price, acctType int, vendorOrderID string, expendID int) (err error) {
utils.CallFuncAsync(func() {
if err = s.InsertStoreAcctIncome(ctx, storeID, price, acctType, vendorOrderID, expendID); err == nil {
s.UpdateStoreAcctBalance(ctx, storeID, price, true)
}
})
return err
}
func (s *StoreAcctManager) CheckStoreAcctExpendExist(vendorOrderID string) (isEqual, isZero bool, err error) {
var (
expends, incomes int
db = dao.GetDB()
)
globals.SugarLogger.Debugf("CheckStoreAcctExpendExist orderID:[%v]", vendorOrderID)
expends, err = dao.GetStoreAcctExpendTotal(db, 0, []int{partner.StoreAcctTypeExpendCreateWaybillEx, partner.StoreAcctTypeRealFeeExpend}, vendorOrderID, utils.ZeroTimeValue, utils.ZeroTimeValue)
incomes, err = dao.GetStoreAcctIncomeTotal(db, 0, []int{partner.StoreAcctTypeRealFeeIncome, partner.StoreAcctTypeIncomeCancelTemp, partner.StoreAcctTypeIncomeCancelReal}, vendorOrderID, utils.ZeroTimeValue, utils.ZeroTimeValue)
if expends != incomes {
if expends > incomes {
return false, false, err
} else {
globals.SugarLogger.Debugf("CheckStoreAcctExpendExist 收入大于支出! orderID:[%v]", vendorOrderID)
}
} else {
if expends == 0 && incomes == 0 {
return true, true, err
} else {
return true, false, err
}
}
return false, false, err
}
func (s *StoreAcctManager) GetStoreAcctExpendLastCreateWayBillFee(vendorOrderID string) (expend *dao.GetStoreAcctExpendLastCreateWayBillFeeResult, lastFee int, err error) {
return dao.GetStoreAcctExpendLastCreateWayBillFee(dao.GetDB(), vendorOrderID)
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,35 +0,0 @@
package cms
import (
"testing"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
)
func TestGetStoresVendorSnapshot(t *testing.T) {
result, err := GetStoresVendorSnapshot(jxcontext.AdminCtx, nil, []int{model.VendorIDEBAI}, nil)
if err != nil {
t.Fatal(err)
}
t.Log(utils.Format4Output(result, false))
t.Log(len(result))
}
func TestSendAlarmVendorSnapshot(t *testing.T) {
db := dao.GetDB()
prevSnapshotList, _ := dao.GetVendorStoreSnapshot(db, utils.Str2Time("2019-09-19 11:00:00"))
curSnapshotList, _ := dao.GetVendorStoreSnapshot(db, utils.Str2Time("2019-09-19 15:00:00"))
err := SendAlarmVendorSnapshot(jxcontext.AdminCtx, nil, prevSnapshotList, curSnapshotList)
if err != nil {
t.Fatal(err)
}
}
func TestUpdateVendorStoreStatusBySnapshot(t *testing.T) {
db := dao.GetDB()
curSnapshotList, _ := dao.GetVendorStoreSnapshot(db, utils.Str2Time("2019-07-30 08:00:00"))
updateVendorStoreStatusBySnapshot(db, curSnapshotList)
}

View File

@@ -1,145 +0,0 @@
package cms
import (
"git.rosy.net.cn/baseapi/platformapi/dingdingapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils/ddmsg"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/globals"
)
type StoreManager struct {
}
var (
FixedStoreManager *StoreManager
)
func init() {
FixedStoreManager = &StoreManager{}
partner.InitStoreManager(FixedStoreManager)
}
func (s *StoreManager) OnStoreStatusChanged(vendorStoreID string, vendorID int, storeStatus int) (err error) {
//return err
globals.SugarLogger.Debugf("OnStoreStatusChanged venvendorStoreID:%s, storeStatus:%d", vendorStoreID, storeStatus)
db := dao.GetDB()
storeDetail, err := dao.GetStoreDetailByVendorStoreID(db, vendorStoreID, vendorID, "")
if err == nil {
if storeDetail.IsSync == model.NO || storeDetail.Status == model.StoreStatusDisabled || storeDetail.Status == model.StoreStatusHaveRest {
return err
}
var storeKV, storeMapKV map[string]interface{}
if storeStatus == model.StoreStatusOpened {
if storeDetail.Status != model.StoreStatusOpened {
storeKV = map[string]interface{}{
"Status": model.StoreStatusOpened,
}
content := "您的门店 [" + storeDetail.Name + "]ID:[" + utils.Int2Str(storeDetail.ID) + "],在[" + model.VendorChineseNames[vendorID] + "] 平台上营业状态和京西不一致!平台状态:【营业】,京西状态:【非营业】"
if user, err := dao.GetUserByID(db, "mobile", storeDetail.MarketManPhone); err == nil {
ddmsg.SendUserMessage(dingdingapi.MsgTyeText, user.UserID, "平台门店状态变化", content)
}
}
if storeDetail.VendorStatus != model.StoreStatusOpened {
storeMapKV = map[string]interface{}{
"Status": model.StoreStatusOpened,
}
}
} else {
if storeDetail.Status == model.StoreStatusOpened {
if storeDetail.VendorStatus != storeStatus {
storeMapKV = map[string]interface{}{
"Status": storeStatus,
}
}
content := "您的门店 [" + storeDetail.Name + "]ID:[" + utils.Int2Str(storeDetail.ID) + "],在[" + model.VendorChineseNames[vendorID] + "] 平台上营业状态和京西不一致!平台状态:【非营业】,京西状态:【营业】"
if user, err := dao.GetUserByID(db, "mobile", storeDetail.MarketManPhone); err == nil {
ddmsg.SendUserMessage(dingdingapi.MsgTyeText, user.UserID, "平台门店状态变化", content)
}
} else if storeDetail.Status <= storeStatus {
if storeDetail.VendorStatus != model.StoreStatusOpened {
storeMapKV = map[string]interface{}{
"Status": model.StoreStatusOpened,
}
}
}
}
if err == nil && (storeKV != nil || storeMapKV != nil) {
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil || err != nil {
dao.Rollback(db, txDB)
if r != nil {
panic(r)
}
}
}()
if storeKV != nil {
globals.SugarLogger.Debugf("OnStoreStatusChanged venvendorStoreID:%s, storeKV:%s", vendorStoreID, utils.Format4Output(storeKV, true))
store := &model.Store{}
store.ID = storeDetail.Store.ID
if err = utils.CallFuncLogError(func() error {
_, err = dao.UpdateEntityLogically(db, store, storeKV, model.AdminName, nil)
return err
}, "OnStoreStatusChanged Update Store venvendorStoreID:%s", vendorStoreID); err != nil {
return err
}
}
if storeMapKV != nil {
globals.SugarLogger.Debugf("OnStoreStatusChanged venvendorStoreID:%s, storeMapKV:%s", vendorStoreID, utils.Format4Output(storeMapKV, true))
if err = utils.CallFuncLogError(func() error {
_, err = dao.UpdateEntityLogically(db, &model.StoreMap{}, storeMapKV, model.AdminName, map[string]interface{}{
model.FieldStoreID: storeDetail.Store.ID,
model.FieldVendorID: vendorID,
model.FieldDeletedAt: utils.DefaultTimeValue,
})
return err
}, "OnStoreStatusChanged Update StoreMap venvendorStoreID:%s", vendorStoreID); err != nil {
return err
}
}
if storeStatus != model.StoreStatusOpened {
// 因为storeStatus != model.StoreStatusOpened不会修改京西门店的状态所以直接用storeDetail.Status是合适的
if err = utils.CallFuncLogError(func() error {
return dao.FormalizeStoreStatus(db, storeDetail.Store.ID, storeDetail.Status)
}, "OnStoreStatusChanged FormalizeStoreStatus venvendorStoreID:%s", vendorStoreID); err != nil {
return err
}
}
dao.Commit(db, txDB)
}
}
return err
}
func (s *StoreManager) OnCourierStoreStatusChanged(ctx *jxcontext.Context, vendorStoreID string, vendorID int, auditStatus int, message string) (err error) {
if vendorStoreID != "" {
db := dao.GetDB()
_, err2 := dao.GetStoreDetail2(db, 0, vendorStoreID, vendorID)
if err = err2; err == nil {
status := model.StoreStatusOpened
if auditStatus != model.StoreAuditStatusOnline && auditStatus != model.StoreAuditStatusUpdated {
status = model.StoreStatusDisabled
}
comment := ""
if auditStatus == model.StoreAuditStatusRejected {
comment = message
}
_, err = dao.UpdateEntityLogically(db, &model.StoreCourierMap{}, map[string]interface{}{
model.FieldStatus: status,
"AuditStatus": auditStatus,
"Comment": comment,
}, ctx.GetUserName(), map[string]interface{}{
model.FieldVendorStoreID: vendorStoreID,
model.FieldVendorID: vendorID,
})
} else if dao.IsNoRowsError(err) {
err = nil
}
}
globals.SugarLogger.Debugf("OnCourierStoreStatusChanged vendorStoreID:%s, auditStatus:%d, err:%v", vendorStoreID, auditStatus, err)
return err
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,698 +0,0 @@
package cms
import (
"fmt"
"strings"
"time"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/baseapi/utils/errlist"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/business/partner/putils"
"git.rosy.net.cn/jx-callback/globals"
)
type MultiStoreVendorInfo struct {
VendorID int
OrgCode string
}
func CombineVendorIDAndOrgCode(vendorID int, orgCode string) string {
return fmt.Sprintf("%d-%s", vendorID, orgCode)
}
func getMultiStoreVendorInfoList() (list []*MultiStoreVendorInfo) {
vendorIDs := partner.GetMultiStoreVendorIDs()
for _, vendorID := range vendorIDs {
orgCodeList := partner.CurAPIManager.GetAppOrgCodeList(vendorID)
for _, v := range orgCodeList {
list = append(list, &MultiStoreVendorInfo{
VendorID: vendorID,
OrgCode: v,
})
}
}
return list
}
func syncCategories(ctx *jxcontext.Context, db *dao.DaoDB, parentTask tasksch.ITask, catList []*dao.SkuStoreCatInfo, isAsync bool) (hint string, err error) {
if len(catList) > 0 {
// todo 按vendorID orgCode合并操作
task := tasksch.NewParallelTask(fmt.Sprintf("同步分类2:%d", len(catList)), tasksch.NewParallelConfig().SetIsContinueWhenError(true), ctx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
catVendorInfo := batchItemList[0].(*dao.SkuStoreCatInfo)
if catVendorInfo.Level != 1 && catVendorInfo.ParentVendorCatID == "" {
return nil, fmt.Errorf("%d的父目录%d没有同步", catVendorInfo.ID, catVendorInfo.ParentID)
}
if catVendorInfo.MapID == 0 {
return nil, fmt.Errorf("分类:%d的数据异常", catVendorInfo.ID)
}
//表示是不用京西分类,要用平台分类
if catVendorInfo.IsJxCat == model.YES {
if catVendorInfo.VendorCategoryID != 0 {
catVendorInfo.Seq = catVendorInfo.VendorCategorySeq
catVendorInfo.Name = catVendorInfo.VendorCategoryName
}
}
if multiStoresHandler, ok := partner.GetPurchasePlatformFromVendorID(catVendorInfo.VendorID).(partner.IMultipleStoresHandler); ok {
if model.IsSyncStatusDelete(catVendorInfo.CatSyncStatus) { //删除
if !dao.IsVendorThingIDEmpty(catVendorInfo.VendorCatID) &&
model.IsSyncStatusNeedDelete(catVendorInfo.CatSyncStatus) {
err = multiStoresHandler.DeleteCategory2(ctx, catVendorInfo.VendorOrgCode, catVendorInfo.VendorCatID)
}
} else if model.IsSyncStatusNew(catVendorInfo.CatSyncStatus) { // 新增
err = multiStoresHandler.CreateCategory2(ctx, catVendorInfo)
} else if model.IsSyncStatusUpdate(catVendorInfo.CatSyncStatus) { // 修改
err = multiStoresHandler.UpdateCategory2(ctx, catVendorInfo)
}
} else {
err = fmt.Errorf("平台:%d不合法", catVendorInfo.VendorID)
}
if err = OnThingSync(ctx, dao.GetDB(), SkuCategoryVendor2ThingMap(catVendorInfo), err); err == nil {
retVal = []int{1}
}
return retVal, err
}, catList)
tasksch.HandleTask(task, parentTask, len(catList) == 0 || len(catList) > 10).Run()
if isAsync {
hint = task.GetID()
} else {
resultList, err2 := task.GetResult(0)
if err = err2; err == nil {
hint = utils.Int2Str(len(resultList))
}
}
}
return hint, err
}
func SyncCategories(ctx *jxcontext.Context, parentTask tasksch.ITask, vendorIDs []int, appOrgCodes []string, catIDs []int, isAsync bool) (hint string, err error) {
globals.SugarLogger.Debugf("SyncCategories vendorIDs:%v, appOrgCodes:%v, catIDs:%v", vendorIDs, appOrgCodes, catIDs)
db := dao.GetDB()
catList, err := dao.GetSkuCategoryWithVendor(db, vendorIDs, appOrgCodes, -1, catIDs, true)
if err == nil && len(catList) > 0 {
//TODO 同一平台不同账号会有影响needSyncParentIDs暂不处理
var needSyncParentIDs []int
for _, cat := range catList {
if cat.Level == 2 && cat.ParentVendorCatID == "" && cat.IsExdSpec == model.NO {
needSyncParentIDs = append(needSyncParentIDs, cat.ParentID)
}
}
if len(needSyncParentIDs) > 0 {
task := tasksch.NewSeqTask(fmt.Sprintf("同步分类1:%v", catIDs), ctx,
func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
switch step {
case 0:
catList2, err := dao.GetSkuCategoryWithVendor(db, vendorIDs, appOrgCodes, -1, needSyncParentIDs, true)
if err == nil {
_, err = syncCategories(ctx, db, task, catList2, false)
}
case 1:
catList2, err := dao.GetSkuCategoryWithVendor(db, vendorIDs, appOrgCodes, -1, catIDs, true)
if err == nil {
_, err = syncCategories(ctx, db, task, catList2, false)
}
}
return result, err
}, 2)
tasksch.HandleTask(task, parentTask, len(catIDs) == 0 || len(catIDs) > 10).Run()
if isAsync {
hint = task.GetID()
} else {
resultList, err2 := task.GetResult(0)
if err = err2; err == nil {
hint = utils.Int2Str(len(resultList))
}
}
} else {
hint, err = syncCategories(ctx, db, parentTask, catList, false)
}
}
return hint, err
}
func SyncSkus(ctx *jxcontext.Context, parentTask tasksch.ITask, vendorIDs []int, appOrgCodes []string, nameIDs, skuIDs []int, isAsync bool) (hint string, err error) {
globals.SugarLogger.Debugf("SyncSkus vendorIDs:%v, appOrgCodes:%v, nameIDs:%v, skuIDs:%v", vendorIDs, appOrgCodes, nameIDs, skuIDs)
db := dao.GetDB()
skuList, err := dao.GetSkusWithVendor(db, vendorIDs, appOrgCodes, nameIDs, skuIDs, true)
if err == nil && len(skuList) > 0 {
// todo 按vendorID orgCode合并操作
task := tasksch.NewParallelTask(fmt.Sprintf("同步商品:%v,%v", nameIDs, skuIDs), tasksch.NewParallelConfig().SetIsContinueWhenError(true), ctx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
skuVendorInfo := batchItemList[0].(*dao.StoreSkuSyncInfo)
var failedList []*partner.StoreSkuInfoWithErr
// if skuVendorInfo.VendorCatID == "" {
// return nil, fmt.Errorf("商品:%d的商家分类没有同步", skuVendorInfo.SkuID)
// }
if skuVendorInfo.BindID == 0 {
return nil, fmt.Errorf("商品:%d的数据异常", skuVendorInfo.SkuID)
}
if skuVendorInfo.ExdSkuID != "" {
return nil, err
}
if !model.IsSyncStatusNew(skuVendorInfo.SkuSyncStatus) && skuVendorInfo.VendorSkuID == "" {
return nil, err
}
if skuVendorInfo.SkuVendorMapCatID != "" {
skuVendorInfo.VendorVendorCatID = utils.Str2Int64(skuVendorInfo.SkuVendorMapCatID)
}
skuVendorInfo.SkuName = jxutils.ComposeSkuNameSync(skuVendorInfo.Prefix, skuVendorInfo.Name, skuVendorInfo.Comment, skuVendorInfo.Unit, skuVendorInfo.SpecQuality, skuVendorInfo.SpecUnit, 0, skuVendorInfo.ExPrefix, skuVendorInfo.ExPrefixBegin, skuVendorInfo.ExPrefixEnd, true)
skuVendorInfo.SkuNameOrigin = jxutils.ComposeSkuNameOriginal(skuVendorInfo.Prefix, skuVendorInfo.Name, skuVendorInfo.Comment, skuVendorInfo.Unit, skuVendorInfo.SpecQuality, skuVendorInfo.SpecUnit, 0)
if skuVendorInfo.ImgWatermark != "" {
downLoad, _ := uploadImgStandard(skuVendorInfo.ImgWatermark)
skuVendorInfo.ImgMix = jxutils.MixWatermarkImg(downLoad, skuVendorInfo.Img, skuVendorInfo.ExPrefixBegin, skuVendorInfo.ExPrefixEnd)
}
skuVendorInfo.MergedStatus = jxutils.MergeSkuStatus(skuVendorInfo.Status, skuVendorInfo.NameStatus)
if multiStoresHandler, ok := partner.GetPurchasePlatformFromVendorID(skuVendorInfo.VendorID).(partner.IMultipleStoresHandler); ok {
if model.IsSyncStatusDelete(skuVendorInfo.SkuSyncStatus) { //删除
if !dao.IsVendorThingIDEmpty(skuVendorInfo.VendorSkuID) &&
model.IsSyncStatusNeedDelete(skuVendorInfo.SkuSyncStatus) {
err = multiStoresHandler.DeleteSku2(ctx, skuVendorInfo.VendorOrgCode, storeSkuSyncInfo2Bare(skuVendorInfo))
if err != nil {
failedList = putils.GetErrMsg2FailedSingleList(skuVendorInfo, err, 0, model.VendorChineseNames[skuVendorInfo.VendorID], "删除商品")
}
}
} else if model.IsSyncStatusNew(skuVendorInfo.SkuSyncStatus) { // 新增
err = multiStoresHandler.CreateSku2(ctx, skuVendorInfo)
if err != nil {
failedList = putils.GetErrMsg2FailedSingleList(skuVendorInfo, err, 0, model.VendorChineseNames[skuVendorInfo.VendorID], "新增商品")
}
} else if model.IsSyncStatusUpdate(skuVendorInfo.SkuSyncStatus) { // 修改
err = multiStoresHandler.UpdateSku2(ctx, skuVendorInfo)
if err != nil {
failedList = putils.GetErrMsg2FailedSingleList(skuVendorInfo, err, 0, model.VendorChineseNames[skuVendorInfo.VendorID], "修改商品")
}
}
} else {
err = fmt.Errorf("平台:%d不合法", skuVendorInfo.VendorID)
}
if len(failedList) > 0 {
task.AddFailedList(failedList)
}
if err = OnThingSync(ctx, dao.GetDB(), SkuVendor2ThingMap(skuVendorInfo), err); err == nil {
retVal = []int{1}
}
return retVal, err
}, skuList)
if isAsync {
buildSetFinishHook(task, ctx)
}
tasksch.HandleTask(task, parentTask, len(skuList) == 0 || len(skuList) > 10).Run()
if isAsync {
hint = task.GetID()
} else {
resultList, err2 := task.GetResult(0)
if len(task.GetFailedList()) > 0 {
err2 = buildErrMsg(task)
err2 = makeSyncError(err2)
}
if err = err2; err == nil {
hint = utils.Int2Str(len(resultList))
}
}
}
return hint, err
}
func SyncReorderCategories(ctx *jxcontext.Context, parentCatID int, isAsync bool) (hint string, err error) {
globals.SugarLogger.Debugf("SyncReorderCategories parentCatID:%d", parentCatID)
db := dao.GetDB()
hint, err = CurVendorSync.LoopMultiStoresVendors(ctx, db, fmt.Sprintf("分类重排序:%d", parentCatID), isAsync, false,
func(t *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
vendorInfo := batchItemList[0].(*MultiStoreVendorInfo)
multiStoresHandler := CurVendorSync.GetMultiStoreHandler(vendorInfo.VendorID)
vendorOrgCode, err := dao.GetVendorOrgCode(db, vendorInfo.VendorID, vendorInfo.OrgCode, "")
if multiStoresHandler != nil {
var vendorCatIDList []string
var parentVendorCatID string
//如果用平台分类就走else用京西分类就还是原来的if
if vendorOrgCode[0].IsJxCat == model.NO {
catList, err2 := dao.GetSkuCategoryWithVendor(db, []int{vendorInfo.VendorID}, []string{vendorInfo.OrgCode}, parentCatID, nil, false)
if err = err2; err == nil {
for _, v := range catList {
if v.VendorCatID != "" {
vendorCatIDList = append(vendorCatIDList, v.VendorCatID)
}
}
}
parentVendorCatID = catList[0].ParentVendorCatID
} else {
vendorCatList, _ := dao.GetVendorCategoryMapExt(db, parentCatID, 0, vendorInfo.VendorID, vendorInfo.OrgCode, 0)
for _, v := range vendorCatList {
if v.VendorThingID != "" {
vendorCatIDList = append(vendorCatIDList, v.VendorThingID)
}
}
thingMaps, _ := dao.GetThingMapList(db, model.ThingTypeCategory, []int{vendorInfo.VendorID}, []int{parentCatID}, []string{vendorInfo.OrgCode})
parentVendorCatID = thingMaps[0].VendorThingID
}
if len(vendorCatIDList) > 0 {
if err = multiStoresHandler.ReorderCategories2(ctx, vendorInfo.OrgCode, parentVendorCatID, vendorCatIDList); err == nil {
retVal = []int{len(vendorCatIDList)}
}
}
} else {
err = fmt.Errorf("非法平台:%d", vendorInfo.VendorID)
}
return retVal, err
})
return hint, err
}
func SyncReorderCategories2(ctx *jxcontext.Context, parentCatID, vendorID int, vendorOrgCode string) (err error) {
globals.SugarLogger.Debugf("SyncReorderCategories parentCatID:%d", parentCatID)
db := dao.GetDB()
multiStoresHandler := CurVendorSync.GetMultiStoreHandler(vendorID)
if multiStoresHandler != nil {
var vendorCatIDList []string
var parentVendorCatID string
vendorCatList, _ := dao.GetVendorCategoryMapExt(db, parentCatID, 0, vendorID, vendorOrgCode, 0)
for _, v := range vendorCatList {
if v.VendorThingID != "" {
vendorCatIDList = append(vendorCatIDList, v.VendorThingID)
}
}
thingMaps, _ := dao.GetThingMapList(db, model.ThingTypeCategory, []int{vendorID}, []int{parentCatID}, []string{vendorOrgCode})
if len(thingMaps) > 0 {
parentVendorCatID = thingMaps[0].VendorThingID
}
if len(vendorCatIDList) > 0 {
err = multiStoresHandler.ReorderCategories2(ctx, vendorOrgCode, parentVendorCatID, vendorCatIDList)
}
} else {
err = fmt.Errorf("非法平台:%d", vendorID)
}
return err
}
func getThingMap(db *dao.DaoDB, thingMap *model.ThingMap) (err error) {
return dao.GetEntity(db, thingMap, "ThingID", "ThingType", "VendorID", "VendorOrgCode", model.FieldDeletedAt)
}
func OnCreateThing(ctx *jxcontext.Context, db *dao.DaoDB, vendorInfoList []*model.VendorOrgCode, thingID int64, thingType, syncFlag int8, vendorFlag bool) (err error) {
if thingType == model.ThingTypeSkuName {
return nil
}
if len(vendorInfoList) == 0 {
vendorInfoList, err = dao.GetVendorOrgCode(db, model.VendorIDJD, "", model.VendorOrgTypePlatform)
}
errList := errlist.New()
for _, v := range vendorInfoList {
thingMap := &model.ThingMap{
ThingID: thingID,
ThingType: thingType,
VendorID: v.VendorID,
VendorOrgCode: v.VendorOrgCode,
}
if thingType == model.ThingTypeCategory && !vendorFlag {
if v.IsJxCat == model.YES {
syncFlag = 0
}
}
thingMap.SyncStatus = syncFlag
dao.WrapAddIDCULDEntity(thingMap, ctx.GetUserName())
if err2 := dao.CreateEntity(db, thingMap); err2 != nil {
if dao.IsDuplicateError(err2) {
errList.AddErr(onUpdateThing(ctx, db, vendorInfoList, thingID, thingType, syncFlag))
} else {
errList.AddErr(err2)
}
}
updateThingMapEntity(db, thingMap)
}
err = errList.GetErrListAsOne()
return err
}
func onUpdateThing(ctx *jxcontext.Context, db *dao.DaoDB, vendorInfoList []*model.VendorOrgCode, thingID int64, thingType int8, syncStatus int8) (err error) {
if thingType == model.ThingTypeSkuName {
return nil
}
if len(vendorInfoList) == 0 {
vendorInfoList, err = dao.GetVendorOrgCode(db, model.VendorIDJD, "", model.VendorOrgTypePlatform)
}
errList := errlist.New()
for _, v := range vendorInfoList {
thingMap := &model.ThingMap{
ThingID: thingID,
ThingType: thingType,
VendorID: v.VendorID,
VendorOrgCode: v.VendorOrgCode,
}
thingMap.DeletedAt = utils.DefaultTimeValue
if err2 := getThingMap(db, thingMap); err2 == nil {
thingMap.SyncStatus |= syncStatus
thingMap.LastOperator = ctx.GetUserName()
_, err2 = dao.UpdateEntity(db, thingMap)
errList.AddErr(err2)
updateThingMapEntity(db, thingMap)
} else {
if dao.IsNoRowsError(err2) {
err2 = nil
} else {
errList.AddErr(err2)
}
}
}
err = errList.GetErrListAsOne()
return err
}
func OnUpdateThing(ctx *jxcontext.Context, db *dao.DaoDB, vendorInfoList []*model.VendorOrgCode, thingID int64, thingType int8) (err error) {
return onUpdateThing(ctx, db, vendorInfoList, thingID, thingType, model.SyncFlagModifiedMask)
}
func OnDeleteThing(ctx *jxcontext.Context, db *dao.DaoDB, vendorInfoList []*MultiStoreVendorInfo, thingID int64, thingType int8) (err error) {
if thingType == model.ThingTypeSkuName {
return nil
}
if len(vendorInfoList) == 0 {
vendorInfoList = getMultiStoreVendorInfoList()
}
errList := errlist.New()
for _, v := range vendorInfoList {
thingMap := &model.ThingMap{
ThingID: thingID,
ThingType: thingType,
VendorID: v.VendorID,
VendorOrgCode: v.OrgCode,
}
thingMap.DeletedAt = utils.DefaultTimeValue
if err2 := getThingMap(db, thingMap); err2 == nil {
if model.IsSyncStatusNew(thingMap.SyncStatus) {
thingMap.SyncStatus = 0
thingMap.DeletedAt = time.Now()
} else {
thingMap.SyncStatus |= model.SyncFlagDeletedMask
}
thingMap.LastOperator = ctx.GetUserName()
_, err2 = dao.UpdateEntity(db, thingMap)
errList.AddErr(err2)
updateThingMapEntity(db, thingMap)
} else if !dao.IsNoRowsError(err2) {
errList.AddErr(err2)
}
}
err = errList.GetErrListAsOne()
return err
}
func SkuCategoryVendor2ThingMap(cat *dao.SkuStoreCatInfo) (thingMap *model.ThingMap) {
thingMap = &model.ThingMap{
ThingID: int64(cat.ID),
ThingType: model.ThingTypeCategory,
VendorID: cat.VendorID,
VendorOrgCode: cat.VendorOrgCode,
SyncStatus: cat.CatSyncStatus,
VendorThingID: cat.VendorCatID,
}
thingMap.ID = cat.MapID // 一定要赋值
return thingMap
}
func SkuVendor2ThingMap(sku *dao.StoreSkuSyncInfo) (thingMap *model.ThingMap) {
thingMap = &model.ThingMap{
ThingID: int64(sku.SkuID),
ThingType: model.ThingTypeSku,
VendorID: sku.VendorID,
VendorOrgCode: sku.VendorOrgCode,
SyncStatus: sku.SkuSyncStatus,
VendorThingID: sku.VendorSkuID,
}
thingMap.DeletedAt = utils.DefaultTimeValue
thingMap.ID = sku.BindID // 一定要赋值
return thingMap
}
func OnThingSync(ctx *jxcontext.Context, db *dao.DaoDB, thingMap *model.ThingMap, syncErr error) (err error) {
globals.SugarLogger.Debugf("OnThingSync thingMap:%s", utils.Format4Output(thingMap, true))
if syncErr != nil {
err = syncErr
thingMap.Remark = utils.LimitUTF8StringLen(err.Error(), 255)
dao.UpdateEntity(db, thingMap, "Remark")
if thingMap.VendorOrgCode == globals.JdcsOrgCode {
if strings.Contains(err.Error(), "店内分类信息不存在") {
err = nil
}
}
} else {
updateFields := []string{
model.FieldSyncStatus,
model.FieldUpdatedAt,
model.FieldLastOperator,
"Remark",
}
if model.IsSyncStatusDelete(thingMap.SyncStatus) { //删除
thingMap.DeletedAt = time.Now()
thingMap.VendorThingID = ""
updateFields = append(updateFields, "VendorThingID", model.FieldDeletedAt)
} else if model.IsSyncStatusNew(thingMap.SyncStatus) { // 新增
updateFields = append(updateFields, "VendorThingID")
}
thingMap.SyncStatus = 0
thingMap.LastOperator = ctx.GetUserName()
thingMap.UpdatedAt = time.Now()
thingMap.Remark = ""
_, err = dao.UpdateEntity(db, thingMap, updateFields...)
updateThingMapEntity(db, thingMap)
}
return err
}
func updateThingMapEntity(db *dao.DaoDB, thingMap *model.ThingMap) {
// if thingMap.VendorOrgCode == globals.JdOrgCode {
// if thingMap.ThingType == model.ThingTypeCategory {
// cat := &model.SkuCategory{
// JdID: utils.Str2Int64WithDefault(thingMap.VendorThingID, 0),
// JdSyncStatus: thingMap.SyncStatus,
// }
// cat.ID = int(thingMap.ThingID)
// dao.UpdateEntity(db, cat, "JdID", "JdSyncStatus")
// } else if thingMap.ThingType == model.ThingTypeSku {
// sku := &model.Sku{
// JdID: utils.Str2Int64WithDefault(thingMap.VendorThingID, 0),
// JdSyncStatus: thingMap.SyncStatus,
// }
// sku.ID = int(thingMap.ThingID)
// dao.UpdateEntity(db, sku, "JdID", "JdSyncStatus")
// }
// }
}
func amendAndPruneVendorStuff(ctx *jxcontext.Context, parentTask tasksch.ITask, storeID, vendorID int, vendorOrgCode string, isAsync, isContinueWhenError bool, opType int, isForceUpdate bool) (hint string, err error) {
handler, _ := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.IMultipleStoresHandler)
if handler == nil {
return "", fmt.Errorf("平台:%s不支持此操作", model.VendorChineseNames[vendorID])
}
db := dao.GetDB()
vendorOrgCodes, _ := dao.GetVendorOrgCode(db, vendorID, vendorOrgCode, model.VendorOrgTypePlatform)
var sku2Delete []*partner.StoreSkuInfo
var cat2Delete []*partner.BareCategoryInfo
task := tasksch.NewParallelTask(fmt.Sprintf("平台:%s,账号:%s上的商品与商家分类", model.VendorChineseNames[vendorID], vendorOrgCode),
tasksch.NewParallelConfig().SetParallelCount(1).SetIsContinueWhenError(isContinueWhenError), ctx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
step := batchItemList[0].(int)
switch step {
case 0:
localSkuList, err := dao.GetSkusWithVendor(db, []int{vendorID}, []string{vendorOrgCode}, nil, nil, false)
if err != nil {
return nil, err
}
localSkuMap := make(map[string]*dao.StoreSkuSyncInfo)
for _, v := range localSkuList {
if v.VendorSkuID != "" {
localSkuMap[v.VendorSkuID] = v
}
}
remoteSkuList, err2 := handler.GetSkus(ctx, vendorOrgCode, 0, "")
if err = err2; err == nil {
remoteSkuMap := make(map[string]int)
for _, v := range remoteSkuList {
if vendorSkuID := v.SkuList[0].VendorSkuID; vendorSkuID != "" {
if localSkuMap[vendorSkuID] == nil {
sku2Delete = append(sku2Delete, &partner.StoreSkuInfo{
SkuID: v.SkuList[0].SkuID,
VendorSkuID: vendorSkuID,
})
} else {
remoteSkuMap[vendorSkuID] = 1
}
} else if v.VendorNameID != "" {
sku2Delete = append(sku2Delete, &partner.StoreSkuInfo{
SkuID: v.NameID,
VendorSkuID: v.VendorNameID,
})
}
}
StoreSkuMap := make(map[int]*dao.StoreSkuSyncInfo)
if storeID != 0 {
skuList2, _ := dao.GetStoreSkuListWithVendor(db, storeID, vendorID, vendorOrgCode)
for _, v := range skuList2 {
if _, ok := StoreSkuMap[v.ID]; !ok {
StoreSkuMap[v.ID] = v
}
}
}
getSyncFlag := func(skuID int) int8 {
if StoreSkuMap[skuID] != nil {
return model.SyncFlagNewMask
}
return 0
}
if opType == AmendPruneOnlyAmend || opType == AmendPruneAll {
for _, v := range localSkuList {
if v.ExdSkuID == "" {
if v.BindID != 0 {
if !model.IsSyncStatusDelete(v.SkuSyncStatus) {
if remoteSkuMap[v.VendorSkuID] == 0 {
if !model.IsSyncStatusNew(v.SkuSyncStatus) {
OnCreateThing(ctx, db, vendorOrgCodes, int64(v.SkuID), model.ThingTypeSku, getSyncFlag(v.SkuID), false)
}
} else if isForceUpdate {
OnUpdateThing(ctx, db, vendorOrgCodes, int64(v.SkuID), model.ThingTypeSku)
}
}
} else {
//表示根据某门店的门店商品同步京东商品库中这个门店关注并可售了这个商品插到thingmap里同步标志是待创建SyncFlagNewMask才会创建
//若该门店没关注可售那插到thingmap里的话就该同步标志为0就不会创建
//getSyncFlag
OnCreateThing(ctx, db, vendorOrgCodes, int64(v.SkuID), model.ThingTypeSku, getSyncFlag(v.SkuID), false)
}
}
}
}
}
case 1:
// if (opType == AmendPruneOnlyPrune || opType == AmendPruneAll) && len(sku2Delete) > 0 {
// _, err = putils.FreeBatchStoreSkuInfo("删除商品", func(task tasksch.ITask, batchedStoreSkuList []*partner.StoreSkuInfo) (result interface{}, successCount int, err error) {
// if err = handler.DeleteSku2(ctx, vendorOrgCode, batchedStoreSkuList[0]); err == nil {
// successCount = 1
// }
// return nil, successCount, err
// }, ctx, task, sku2Delete, 1, isContinueWhenError)
// }
sku2Delete = nil
case 2:
localCatList, err := dao.GetSkuCategoryWithVendor(db, []int{vendorID}, []string{vendorOrgCode}, -1, nil, false)
if err != nil {
return nil, err
}
localCatMap := make(map[string]*dao.SkuStoreCatInfo)
for _, v := range localCatList {
localCatMap[v.VendorCatID] = v
localCatMap[v.Name] = v
localCatMap[utils.Int2Str(v.ID)] = v
}
vendorCatMap := make(map[int]*model.VendorCategoryMap)
if vendorOrgCodes[0].IsJxCat == model.YES {
vendorCats, _ := dao.GetVendorCategoryMap(db, -1, 0, vendorID, vendorOrgCode, 0)
for _, v := range vendorCats {
if _, ok := vendorCatMap[v.CategoryID]; !ok {
vendorCatMap[v.CategoryID] = v
}
}
}
getSyncFlagCat := func(categoryID int) int8 {
if vendorCatMap[categoryID] != nil || vendorOrgCodes[0].IsJxCat == model.NO {
return model.SyncFlagNewMask
}
return 0
}
remoteCatList, err2 := handler.GetAllCategories(ctx, vendorOrgCode)
if err = err2; err == nil {
remoteCatMap := make(map[string]int)
cat2Delete = checkRemoteCatExist(remoteCatMap, localCatMap, remoteCatList)
for _, v := range localCatList {
if v.IsExdSpec == model.NO {
if v.MapID != 0 {
if !model.IsSyncStatusDelete(v.CatSyncStatus) {
if remoteCatMap[v.VendorCatID] == 0 {
if !model.IsSyncStatusNew(v.CatSyncStatus) {
OnCreateThing(ctx, db, vendorOrgCodes, int64(v.ID), model.ThingTypeCategory, getSyncFlagCat(v.ID), true)
}
} else if isForceUpdate && !model.IsSyncStatusUpdate(v.CatSyncStatus) {
OnUpdateThing(ctx, db, vendorOrgCodes, int64(v.ID), model.ThingTypeCategory)
}
}
} else {
OnCreateThing(ctx, db, vendorOrgCodes, int64(v.ID), model.ThingTypeCategory, getSyncFlagCat(v.ID), true)
}
}
}
}
case 3:
if (opType == AmendPruneOnlyPrune || opType == AmendPruneAll) && len(cat2Delete) > 0 {
for i := 0; i < 2; i++ {
level := 2 - i
var levelCat2Delete []*partner.BareCategoryInfo
for _, v := range cat2Delete {
if v.Level == level {
levelCat2Delete = append(levelCat2Delete, v)
}
}
if len(levelCat2Delete) > 0 {
// task4Delete := tasksch.NewParallelTask(fmt.Sprintf("删除商家分类,level:%d", level), tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError), ctx,
// func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
// cat := batchItemList[0].(*partner.BareCategoryInfo)
// err = handler.DeleteCategory2(ctx, vendorOrgCode, cat.VendorCatID)
// return nil, err
// }, levelCat2Delete)
// tasksch.HandleTask(task4Delete, task, true).Run()
// _, err = task4Delete.GetResult(0)
}
}
}
cat2Delete = nil
}
return nil, err
}, []int{0, 1, 2, 3})
tasksch.HandleTask(task, parentTask, true).Run()
if !isAsync {
_, err = task.GetResult(0)
hint = "1"
} else {
hint = task.ID
}
return hint, err
}
func FullSyncVendorStuff(ctx *jxcontext.Context, parentTask tasksch.ITask, storeID, vendorID int, vendorOrgCode string, isAsync, isContinueWhenError bool) (hint string, err error) {
multiStoreHandler, _ := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.IMultipleStoresHandler)
if multiStoreHandler == nil {
return "", fmt.Errorf("vendorID:%d不是多门店平台", vendorID)
}
task := tasksch.NewParallelTask("FullSyncStoreSkuNew", tasksch.NewParallelConfig().SetParallelCount(1).SetIsContinueWhenError(false), ctx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
step := batchItemList[0].(int)
switch step {
case 0:
_, err = amendAndPruneVendorStuff(ctx, task, storeID, vendorID, vendorOrgCode, false, isContinueWhenError, AmendPruneAll, false)
case 1:
_, err = SyncCategories(ctx, task, []int{vendorID}, []string{vendorOrgCode}, nil, false)
case 2:
_, err = SyncSkus(ctx, task, []int{vendorID}, []string{vendorOrgCode}, nil, nil, false)
}
return retVal, err
}, []int{0, 1, 2})
tasksch.HandleTask(task, parentTask, true).Run()
if !isAsync {
_, err = task.GetResult(0)
} else {
hint = task.GetID()
}
return hint, err
}

View File

@@ -1,59 +0,0 @@
package cms
import (
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/business/partner"
)
// 如果京西门为打开,打开状态为非营业的平台门店
func OpenRemoteStoreByJxStatus(ctx *jxcontext.Context, vendorIDs, storeIDs []int, isForce, isAsync, isContinueWhenError bool) (hint string, err error) {
db := dao.GetDB()
status := model.StoreStatusAll
if !isForce {
status = model.StoreStatusClosed
}
storeMapList, err := dao.GetStoresMapList(db, vendorIDs, storeIDs, nil, status, model.StoreIsSyncYes, "", "", "")
if err != nil {
return "", err
}
vendorIDMap := make(map[int]int)
if len(vendorIDs) == 0 {
for k := range partner.PurchasePlatformHandlers {
vendorIDMap[k] = 1
}
} else {
for _, v := range vendorIDs {
vendorIDMap[v] = 1
}
}
task := tasksch.NewParallelTask("OpenRemoteStoreByJxStatus", tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError), ctx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
storeMap := batchItemList[0].(*model.StoreMap)
if handler, _ := partner.GetPurchasePlatformFromVendorID(storeMap.VendorID).(partner.IStoreHandler); handler != nil {
storeDetail, err := dao.GetStoreDetail(db, storeMap.StoreID, storeMap.VendorID, "")
if err == nil && storeDetail.Status == model.StoreStatusOpened {
if err = handler.UpdateStoreStatus(ctx, storeMap.VendorOrgCode, storeMap.StoreID, storeMap.VendorStoreID, model.StoreStatusOpened); err == nil {
storeMap.Status = model.StoreStatusOpened
dao.UpdateEntity(db, storeMap, model.FieldStatus)
retVal = []int{1}
}
}
}
return retVal, err
}, storeMapList)
tasksch.HandleTask(task, nil, true).Run()
if isAsync {
hint = task.GetID()
} else {
resultList, err2 := task.GetResult(0)
if err = err2; err == nil {
hint = utils.Int2Str(len(resultList))
}
}
return hint, err
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,329 +0,0 @@
package cms
import (
"fmt"
"io"
"time"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/business/partner/putils"
"git.rosy.net.cn/jx-callback/globals/api/apimanager"
"github.com/360EntSecGroup-Skylar/excelize"
)
func storeOrSkuMap2List(intStrMap map[int]string) (ids []int) {
for k, v := range intStrMap {
if v != "" {
ids = append(ids, k)
}
}
return ids
}
func getStoreSkus(db *dao.DaoDB, storeID int, skuIDs []int) (skus []*dao.StoreSkuSyncInfo, err error) {
sql := `
SELECT
t1.id bind_id, t1.sku_id, t1.price, t1.unit_price, t1.status store_sku_status,
t1.jd_sync_status sku_sync_status, t1.jd_price vendor_price, t1.jd_lock_time lock_time,
t1.store_id, t1.deleted_at bind_deleted_at,t1.status_sale_begin,t1.status_sale_end,
t2.*,
t3.id name_id, t3.prefix, t3.name, t3.unit, t3.upc, t3.status name_status, t3.ex_prefix, t3.ex_prefix_begin, t3.ex_prefix_end
FROM store_sku_bind t1
LEFT JOIN sku t2 ON t1.sku_id = t2.id AND t2.deleted_at = ?/* AND t2.status = ?*/
LEFT JOIN sku_name t3 ON t2.name_id = t3.id AND t3.deleted_at = ?/* AND t3.status = ?*/
WHERE 1 = 1
AND t1.store_id = ?
AND t1.deleted_at = ?
AND t1.sku_id IN ( ` + dao.GenQuestionMarks(len(skuIDs)) + `)
ORDER BY t1.price`
sqlParams := []interface{}{
utils.DefaultTimeValue,
utils.DefaultTimeValue,
storeID,
utils.DefaultTimeValue,
skuIDs,
}
if err = dao.GetRows(db, &skus, sql, sqlParams...); err != nil {
return nil, err
}
return skus, err
}
func SyncStoreSku4FakeJD(ctx *jxcontext.Context, parentTask tasksch.ITask, storeID int, vendorStoreID string, inSkuMap map[int]string, isContinueWhenError bool) (err error) {
vendorID := model.VendorIDJD
db := dao.GetDB()
storeDetail, err := dao.GetStoreDetail(db, storeID, vendorID, "")
if err != nil {
return err
}
storeDetail.VendorOrgCode = apimanager.FakeJdOrgCode
skuIDs := storeOrSkuMap2List(inSkuMap)
skus, err := getStoreSkus(db, storeID, skuIDs)
if err != nil || len(skus) == 0 {
return err
}
formalizeStoreSkuList(skus)
storeSkuHandler := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.IPurchasePlatformStoreSkuHandler)
var (
stockList, onlineList, offlineList, priceList []*partner.StoreSkuInfo
)
skuMap := make(map[*partner.StoreSkuInfo]*dao.StoreSkuSyncInfo)
now := jxutils.OperationTime2HourMinuteFormat(time.Now())
var failedList []*partner.StoreSkuInfoWithErr
for _, sku := range skus {
sku.SkuSyncStatus = model.SyncFlagSaleMask | model.SyncFlagPriceMask | model.SyncFlagStockMask
sku.VendorSkuID = inSkuMap[sku.SkuID]
sku.SkuID = int(utils.Str2Int64(sku.VendorSkuID)) // skuID与vendorID一样
sku.VendorOrgCode = apimanager.FakeJdOrgCode
sku.VendorPrice = 0
sku.MergedStatus = MergeSkuSaleStatusWithStoreOpTime(sku, storeDetail, now)
var bareSku *partner.StoreSkuInfo
if isStoreSkuSyncNeedDelete(sku) {
if !dao.IsVendorThingIDEmpty(sku.VendorSkuID) {
bareSku = storeSkuSyncInfo2Bare(sku)
stockList = append(stockList, bareSku)
} else {
// updateItems = append(updateItems, sku2Update(vendorID, sku, model.SyncFlagDeletedMask))
}
} else if model.IsSyncStatusNew(sku.SkuSyncStatus) {
calVendorPrice4StoreSku(sku, storeDetail.PricePercentagePackObj, int(storeDetail.PricePercentage))
if dao.IsVendorThingIDEmpty(sku.VendorSkuID) {
// todo 多平台商品库没有正常创建,直接跳过
} else {
sku.SkuSyncStatus |= model.SyncFlagSaleMask | model.SyncFlagPriceMask
bareSku = storeSkuSyncInfo2Bare(sku)
stockList = append(stockList, bareSku)
priceList = append(priceList, bareSku)
if sku.MergedStatus == model.SkuStatusNormal {
onlineList = append(onlineList, bareSku)
} else {
offlineList = append(offlineList, bareSku)
}
}
} else {
if dao.IsVendorThingIDEmpty(sku.VendorSkuID) {
// err = fmt.Errorf("门店:%d修改没有创建的商品:%d", storeID, sku.SkuID)
err = utils.NewErrorCode(fmt.Sprintf("门店:%d修改没有创建的商品:%d", storeID, sku.SkuID), "-1", 0)
failedList = putils.GetErrMsg2FailedSingleList(nil, err, storeID, model.VendorChineseNames[vendorID], "异常同步错误")
if parentTask == nil {
return err
}
parentTask.AddBatchErr(err)
parentTask.AddFailedList(failedList)
} else {
isAdded2Update := false
if model.IsSyncStatusPrice(sku.SkuSyncStatus) {
bareSku = storeSkuSyncInfo2Bare(calVendorPrice4StoreSku(sku, storeDetail.PricePercentagePackObj, int(storeDetail.PricePercentage)))
priceList = append(priceList, bareSku)
}
if !isAdded2Update {
if model.IsSyncStatusSale(sku.SkuSyncStatus) {
if bareSku == nil {
bareSku = storeSkuSyncInfo2Bare(sku)
}
if sku.MergedStatus == model.SkuStatusNormal {
onlineList = append(onlineList, bareSku)
stockList = append(stockList, bareSku)
} else {
offlineList = append(offlineList, bareSku)
// 因为京东平台以是否有库存表示是否关注,所以不论是否可售,都要设置库存
stockList = append(stockList, bareSku)
}
}
}
}
}
if bareSku != nil {
skuMap[bareSku] = sku
}
}
bareSku2Sync := func(bareSkuList []*partner.StoreSkuInfo) (skuList []*dao.StoreSkuSyncInfo) {
if len(bareSkuList) > 0 {
skuList = make([]*dao.StoreSkuSyncInfo, len(bareSkuList))
for k, v := range bareSkuList {
skuList[k] = skuMap[v]
}
}
return skuList
}
isContinueWhenError2 := true
realStoreID := int(utils.Str2Int64(vendorStoreID))
task := tasksch.NewParallelTask("SyncStoreSku4FakeJD", tasksch.NewParallelConfig().SetParallelCount(1).SetIsContinueWhenError(isContinueWhenError2), ctx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
step := batchItemList[0].(int)
// globals.SugarLogger.Debugf("step:%d", step)
switch step {
case 0:
for k, list := range [][]*partner.StoreSkuInfo{stockList /*, onlineList*/} {
if len(list) > 0 {
_, err = putils.FreeBatchStoreSkuInfo("更新门店商品库存", func(task tasksch.ITask, batchedStoreSkuList []*partner.StoreSkuInfo) (result interface{}, successCount int, err error) {
var failedList []*partner.StoreSkuInfoWithErr
failedList, err = storeSkuHandler.UpdateStoreSkusStock(ctx, storeDetail.VendorOrgCode, realStoreID, vendorStoreID, batchedStoreSkuList)
if len(failedList) > 0 {
task.AddFailedList(failedList)
}
successList := putils.UnselectStoreSkuListByVendorSkuIDs(batchedStoreSkuList, GetVendorSkuIDList(failedList))
if k == 0 && len(successList) > 0 {
updateStoreSku(dao.GetDB(), vendorID, bareSku2Sync(successList), model.SyncFlagStockMask)
}
return nil, len(successList), err
}, ctx, task, list, storeSkuHandler.GetStoreSkusBatchSize(partner.FuncUpdateStoreSkusStock), isContinueWhenError2)
}
}
case 1, 2:
statusList := onlineList
status := model.SkuStatusNormal
name := "可售门店商品"
if step == 2 {
statusList = offlineList
status = model.SkuStatusDontSale
name = "不可售门店商品"
}
if len(statusList) > 0 {
_, err = putils.FreeBatchStoreSkuInfo(name, func(task tasksch.ITask, batchedStoreSkuList []*partner.StoreSkuInfo) (result interface{}, successCount int, err error) {
var failedList []*partner.StoreSkuInfoWithErr
failedList, err = storeSkuHandler.UpdateStoreSkusStatus(ctx, storeDetail.VendorOrgCode, realStoreID, vendorStoreID, batchedStoreSkuList, status)
if len(failedList) > 0 {
task.AddFailedList(failedList)
}
successList := putils.UnselectStoreSkuListByVendorSkuIDs(batchedStoreSkuList, GetVendorSkuIDList(failedList))
if len(successList) > 0 {
updateStoreSku(dao.GetDB(), vendorID, bareSku2Sync(successList), model.SyncFlagSaleMask)
}
return nil, len(successList), err
}, ctx, task, statusList, storeSkuHandler.GetStoreSkusBatchSize(partner.FuncUpdateStoreSkusStatus), isContinueWhenError2)
}
case 3:
if len(priceList) > 0 {
_, err = putils.FreeBatchStoreSkuInfo("更新门店商品价格", func(task tasksch.ITask, batchedStoreSkuList []*partner.StoreSkuInfo) (result interface{}, successCount int, err error) {
var failedList []*partner.StoreSkuInfoWithErr
failedList, err = storeSkuHandler.UpdateStoreSkusPrice(ctx, storeDetail.VendorOrgCode, realStoreID, vendorStoreID, batchedStoreSkuList)
if len(failedList) > 0 {
task.AddFailedList(failedList)
}
successList := putils.UnselectStoreSkuListByVendorSkuIDs(batchedStoreSkuList, GetVendorSkuIDList(failedList))
if len(successList) > 0 {
updateStoreSku(dao.GetDB(), vendorID, bareSku2Sync(successList), model.SyncFlagPriceMask)
}
return nil, len(successList), err
}, ctx, task, priceList, storeSkuHandler.GetStoreSkusBatchSize(partner.FuncUpdateStoreSkusPrice), isContinueWhenError2)
}
}
return retVal, err
}, []int{0, 1, 2, 3})
tasksch.HandleTask(task, parentTask, true).Run()
_, err = task.GetResult(0)
return err
}
func SyncFakeJdStoreSku(ctx *jxcontext.Context, parentTask tasksch.ITask, storeMap, skuMap map[int]string, isAsync, isContinueWhenError bool) (hint string, err error) {
storeIDs := storeOrSkuMap2List(storeMap)
task := tasksch.NewParallelTask("同步假京东", nil, ctx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
storeID := batchItemList[0].(int)
err = SyncStoreSku4FakeJD(ctx, task, storeID, storeMap[storeID], skuMap, isContinueWhenError)
return retVal, err
}, storeIDs)
tasksch.HandleTask(task, parentTask, true).Run()
if isAsync {
hint = task.GetID()
} else {
_, err = task.GetResult(0)
hint = utils.Int2Str(len(storeIDs))
}
return hint, err
}
func excel2FakeJdThingMap(ctx *jxcontext.Context, reader io.Reader) (thingMapList []*model.FakeJdThingMap, err error) {
xlsx, err := excelize.OpenReader(reader)
if err != nil {
return nil, err
}
for sheetIndex := 0; sheetIndex < xlsx.SheetCount; sheetIndex++ {
rows, err2 := xlsx.GetRows(xlsx.GetSheetName(sheetIndex + 1))
if err2 != nil {
return nil, err2
}
for rowNum, row := range rows {
thingMap := &model.FakeJdThingMap{
JxID: int(utils.Str2Int64WithDefault(row[0], 0)),
JdID: utils.Str2Int64WithDefault(row[1], 0),
}
if thingMap.JxID == 0 || thingMap.JdID == 0 {
if rowNum == 0 {
continue
} else {
break
}
}
if sheetIndex == 0 {
thingMap.ThingType = model.ThingTypeStore
} else {
thingMap.ThingType = model.ThingTypeSku
}
dao.WrapAddIDCULEntity(thingMap, ctx.GetUserName())
thingMapList = append(thingMapList, thingMap)
}
}
return thingMapList, err
}
func getFakeThingMap(ctx *jxcontext.Context, db *dao.DaoDB) (storeMap, skuMap map[int]string, err error) {
var thingMapList []*model.FakeJdThingMap
err = dao.GetRows(db, &thingMapList, "SELECT t1.* FROM fake_jd_thing_map t1")
if err == nil {
storeMap, skuMap = make(map[int]string), make(map[int]string)
for _, v := range thingMapList {
if v.ThingType == model.ThingTypeStore {
storeMap[v.JxID] = utils.Int64ToStr(v.JdID)
} else {
skuMap[v.JxID] = utils.Int64ToStr(v.JdID)
}
}
}
return storeMap, skuMap, err
}
func UploadFakeJdThingMap(ctx *jxcontext.Context, reader io.Reader, isSyncNow, isAsync, isContinueWhenError bool) (hint string, err error) {
thingMapList, err := excel2FakeJdThingMap(ctx, reader)
if err != nil {
return "", err
}
db := dao.GetDB()
txDB , _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, txDB)
panic(r)
}
}()
_, err = dao.ExecuteSQL(db, "DELETE t1 FROM fake_jd_thing_map t1")
if err != nil {
dao.Rollback(db, txDB)
return "", err
}
err = dao.CreateMultiEntities(db, thingMapList)
if err != nil {
dao.Rollback(db, txDB)
return "", err
}
dao.Commit(db, txDB)
if isSyncNow {
if storeMap, skuMap, err2 := getFakeThingMap(ctx, db); err2 == nil {
hint, err = SyncFakeJdStoreSku(ctx, nil, storeMap, skuMap, isAsync, isContinueWhenError)
}
} else {
hint = utils.Int2Str(len(thingMapList))
}
return hint, err
}

View File

@@ -1,30 +0,0 @@
package cms
import (
"os"
"testing"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
)
func TestSyncStoreSku4FakeJD(t *testing.T) {
skuMap := map[int]string{
22509: "2029937911",
}
err := SyncStoreSku4FakeJD(jxcontext.AdminCtx, nil, 100118, "11943257", skuMap, true)
if err != nil {
t.Fatal(err)
}
}
func TestUploadFakeJdThingMap(t *testing.T) {
file, err := os.Open("到家菜市门店与商品映射信息(1).xlsx")
if err != nil {
t.Fatal(err)
}
hint, err := UploadFakeJdThingMap(jxcontext.AdminCtx, file, true, false, true)
if err != nil {
t.Fatal(err)
}
t.Log(hint)
}

View File

@@ -1,44 +0,0 @@
package cms
import (
"fmt"
"testing"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/business/partner/putils"
)
func TestFreeBatchStoreSkuInfo(t *testing.T) {
var sku2Delete []*partner.StoreSkuInfo
for i := 0; i < 123; i++ {
sku2Delete = append(sku2Delete, &partner.StoreSkuInfo{
SkuID: i + 1,
})
}
ctx := jxcontext.AdminCtx
var parentTask tasksch.ITask
isContinueWhenError := true
handler, _ := partner.GetPurchasePlatformFromVendorID(model.VendorIDEBAI).(partner.ISingleStoreStoreSkuHandler)
_, err := putils.FreeBatchStoreSkuInfo("删除门店商品", func(task tasksch.ITask, batchedStoreSkuList []*partner.StoreSkuInfo) (result interface{}, successCount int, err error) {
t.Log(len(batchedStoreSkuList))
return nil, 0, err
}, ctx, parentTask, sku2Delete, handler.GetStoreSkusBatchSize(partner.FuncDeleteStoreSkus), isContinueWhenError)
if err != nil {
t.Fatal(err)
}
}
func TestGetTimeMixByInt(t *testing.T) {
const (
time1 = 1100
time2 = 2300
time3 = 1200
time4 = 2400
)
a, b := GetTimeMixByInt(time1, time2, time3, time4)
fmt.Println(a, b)
}

View File

@@ -1,210 +0,0 @@
package cms
// var (
// LoginTypeFieldMap = map[string]string{
// mobile.LoginType: "tel",
// weixin.LoginType: "openid",
// weixin.LoginTypeMiniProgram: "openid_mini",
// }
// )
// func GetStoreUsers(ctx *jxcontext.Context, storeID int) (storeUserInfos []*dao.StoreUserInfo, err error) {
// sql := `
// SELECT t1.id, t1.jxstoreid, t1.openid, t1.tel, t1.nickname, t1.parentid, t3.tel parent_mobile,
// CONCAT("[", GROUP_CONCAT(CONCAT('{"id":', t2.id, ',"parentID":', t2.parentid, ',"tel":"', t2.tel, '","nickname":"', IF(t2.nickname IS NULL, "", t2.nickname), '"}')), "]") members_str
// FROM weixins t1
// LEFT JOIN weixins t2 ON t2.parentid = t1.id
// LEFT JOIN weixins t3 ON t1.parentid = t3.id
// WHERE t1.parentid = -1 AND t1.jxstoreid = ?
// GROUP BY 1,2,3,4,5,6,7;
// `
// // globals.SugarLogger.Debug(sql)
// if err = dao.GetRows(nil, &storeUserInfos, sql, storeID); err == nil {
// for _, storeUserInfo := range storeUserInfos {
// if storeUserInfo.MembersStr != "" {
// err = utils.UnmarshalUseNumber([]byte(storeUserInfo.MembersStr), &storeUserInfo.Members)
// }
// }
// }
// return storeUserInfos, err
// }
// func GetUserInfo(ctx *jxcontext.Context, mobile string) (storeUserInfo *dao.StoreUserInfo, err error) {
// storeUserInfo, err = dao.GetUserStoreInfo(dao.GetDB(), "tel", mobile)
// globals.SugarLogger.Debugf("GetUserInfo:%s, token:%s, mobile:%s, storeUserInfo:%s, err:%v", ctx.GetTrackInfo(), ctx.GetToken(), mobile, utils.Format4Output(storeUserInfo, true), err)
// return storeUserInfo, err
// }
// func GetSelfInfo(ctx *jxcontext.Context) (storeUserInfo *dao.StoreUserInfo, err error) {
// loginInfo := ctx.GetLoginInfo()
// if loginInfo == nil {
// return nil, auth.ErrAPINeedRealLogin
// }
// fieldName := LoginTypeFieldMap[loginInfo.GetAuthType()]
// if fieldName == "" {
// return nil, auth.ErrIllegalLoginType
// }
// storeUserInfo, err = dao.GetUserStoreInfo(dao.GetDB(), fieldName, loginInfo.GetAuthID())
// globals.SugarLogger.Debugf("GetSelfInfo:%s, token:%s, storeUserInfo:%s, err:%v", ctx.GetTrackInfo(), ctx.GetToken(), utils.Format4Output(storeUserInfo, true), err)
// return storeUserInfo, err
// }
// func GetMyStoreList(ctx *jxcontext.Context) (storeList []*dao.StoreWithCityName, err error) {
// mobileNum, _ := ctx.GetMobileAndUserID()
// if mobileNum == "" {
// return nil, fmt.Errorf("不能得到用户手机号")
// }
// storeList, err = dao.GetStoreListByMobile(dao.GetDB(), mobileNum)
// return storeList, err
// }
// func UnbindMobile(ctx *jxcontext.Context, mobile string) (num int64, err error) {
// db := dao.GetDB()
// num, err = dao.UpdateEntityByKV(db, &legacymodel.WeiXins{}, map[string]interface{}{
// "JxStoreID": 0,
// "ParentID": -1,
// }, map[string]interface{}{
// "Tel": mobile,
// })
// if err == nil {
// jxutils.HandleUserWXRemark(db, mobile, false)
// TransferLegacyWeixins(mobile)
// }
// return num, err
// }
// func BindMobile2Store(ctx *jxcontext.Context, mobile string, storeID int) (num int64, err error) {
// db := dao.GetDB()
// user, err2 := verifyMobileIsBlank(db, mobile)
// if err = err2; err == nil || err == orm.ErrNoRows {
// user.JxStoreID = storeID
// if err == nil {
// txDB , _ := dao.Begin(db)
// defer func() {
// if r := recover(); r != nil {
// dao.Rollback(db, txDB)
// panic(r)
// }
// }()
// if num, err = dao.UpdateEntity(db, user, "JxStoreID"); err == nil {
// err = dao.SetWeiXinsEmpty2Null(db, user)
// }
// if err != nil {
// dao.Rollback(db, txDB)
// } else {
// dao.Commit(db, txDB)
// }
// } else {
// // globals.SugarLogger.Debug(utils.Format4Output(user, false))
// dao.WrapAddIDCULEntity(user, ctx.GetUserName())
// user.ParentID = -1
// if err = dao.CreateWeiXins(db, user); err == nil {
// num = 1
// }
// }
// }
// if err == nil {
// jxutils.HandleUserWXRemark(db, mobile, false)
// TransferLegacyWeixins(mobile)
// }
// return num, err
// }
// func AddMobile2Mobile(ctx *jxcontext.Context, parentMobile, mobile string) (num int64, err error) {
// db := dao.GetDB()
// parentUser := &legacymodel.WeiXins{}
// parentUser.Tel = parentMobile
// if err = dao.GetEntity(db, parentUser, "Tel"); err == nil {
// if parentUser.ParentID == -1 {
// globals.SugarLogger.Debug(parentUser)
// if err = verifyMobileHasNoMembers(db, mobile); err == nil {
// user, err2 := verifyMobileIsBlank(db, mobile)
// if err = err2; err == nil || err == orm.ErrNoRows {
// user.ParentID = parentUser.ID
// if err == nil {
// // todo transaction
// if num, err = dao.UpdateEntity(db, user, "ParentID"); err == nil {
// err = dao.SetWeiXinsEmpty2Null(db, user)
// }
// } else {
// dao.WrapAddIDCULEntity(user, ctx.GetUserName())
// if err = dao.CreateWeiXins(db, user); err == nil {
// num = 1
// }
// }
// }
// }
// } else {
// err = fmt.Errorf("%s本身是成员", parentMobile)
// }
// }
// if err == nil {
// jxutils.HandleUserWXRemark(db, mobile, false)
// TransferLegacyWeixins(mobile)
// }
// return num, err
// }
// func ChangeMobile(ctx *jxcontext.Context, curMobile, expectedMobile string) (num int64, err error) {
// num, err = dao.UpdateEntityByKV(nil, &legacymodel.WeiXins{}, map[string]interface{}{
// "Tel": expectedMobile,
// }, map[string]interface{}{
// "Tel": curMobile,
// })
// if err == nil {
// TransferLegacyWeixins(curMobile)
// TransferLegacyWeixins(expectedMobile)
// }
// return num, err
// }
// func verifyMobileIsBlank(db *dao.DaoDB, mobile string) (user *legacymodel.WeiXins, err error) {
// if !jxutils.IsStringLikeMobile(mobile) {
// return nil, fmt.Errorf("%s看起来不像是一个手机号", mobile)
// }
// user = &legacymodel.WeiXins{
// Tel: mobile,
// }
// if err = dao.GetEntity(db, user, "Tel"); err == nil {
// if user.ParentID != -1 && user.ParentID != 0 {
// userParent := &legacymodel.WeiXins{
// ID: user.ParentID,
// }
// if err = dao.GetEntity(db, userParent); err != nil && err != orm.ErrNoRows {
// return nil, err
// }
// if err != orm.ErrNoRows {
// err = fmt.Errorf("%s已经是组长%s门店%d的小组成员", mobile, userParent.Tel, userParent.JxStoreID)
// } else {
// err = nil
// }
// } else if user.JxStoreID != 0 {
// store := &model.Store{}
// store.ID = user.JxStoreID
// if err = dao.GetEntity(db, store); err == nil {
// err = fmt.Errorf("%s本身已经是门店%d的组长", mobile, user.JxStoreID)
// } else if dao.IsNoRowsError(err) {
// err = nil
// }
// }
// }
// return user, err
// }
// func verifyMobileHasNoMembers(db *dao.DaoDB, mobile string) (err error) {
// countInfo := &struct{ Ct int }{}
// if err = dao.GetRow(db, countInfo, `
// SELECT COUNT(*) ct
// FROM weixins t1
// JOIN weixins t2 ON t1.parentid = t2.id AND t2.tel = ?
// `, mobile); err == nil {
// if countInfo.Ct > 0 {
// user := &legacymodel.WeiXins{
// Tel: mobile,
// }
// dao.GetEntity(db, user, "Tel")
// err = fmt.Errorf("%s本身已经是门店%d组长", mobile, user.JxStoreID)
// }
// }
// return err
// }

File diff suppressed because it is too large Load Diff

View File

@@ -1,23 +0,0 @@
package cms
import (
"testing"
"git.rosy.net.cn/baseapi/utils"
_ "git.rosy.net.cn/jx-callback/globals/api/apimanager"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/model"
)
func TestTryAddStoreBossRole4User(t *testing.T) {
err := TryAddStoreBossRole4User(jxcontext.AdminCtx, &model.User{
Type: model.UserTypeStoreBoss,
UserID: "24058800CD3711E991B2525400E86DC0",
Mobile: utils.String2Pointer("91112345678"),
})
if err != nil {
t.Fatal(err)
}
}

View File

@@ -1,50 +0,0 @@
package cms
import (
"fmt"
"gopkg.in/go-playground/validator.v9"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/model"
)
var (
unitNamesMap map[string]int
specUnitNamesMap map[string]int
validate = validator.New()
)
func init() {
unitNamesMap = jxutils.MakeValidationMapFromSlice(model.UnitNames, 1)
specUnitNamesMap = jxutils.MakeValidationMapFromSlice(model.SpecUnitNames, 1)
}
func validateStringInMap(name string, value interface{}, flagMap map[string]int) (err error) {
if strValue, ok := value.(string); ok {
if flagMap[strValue] == 1 {
return nil
}
}
return fmt.Errorf("属性%s类型或取值不合法要求string", name)
}
func ValidateUnit(value interface{}) (err error) {
return validateStringInMap("Unit", value, unitNamesMap)
}
func ValidateSpecUnit(value interface{}) (err error) {
return validateStringInMap("SpecUnit", value, specUnitNamesMap)
}
func ValidateStruct(value interface{}) (err error) {
return validate.Struct(value)
}
func ValidateVar(value interface{}, tag string) (err error) {
return validate.Var(value, tag)
}
func ValidateStructPartial(value interface{}, fields ...string) (err error) {
return validate.StructPartial(value, fields...)
}

View File

@@ -6,10 +6,10 @@ import (
"git.rosy.net.cn/baseapi/platformapi/autonavi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/dao"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/globals/api"
)
@@ -67,7 +67,7 @@ func GetNearSupplyGoodsStoreByStoreID(ctx *jxcontext.Context, storeID int) (stor
stores []*model.Store
db = dao.GetDB()
)
store2, _ := dao.GetStoreDetail(db, storeID, model.VendorIDJX, "")
store2, _ := dao.GetStoreDetail(db, storeID, model.VendorIDJX)
if store2 == nil {
return nil, fmt.Errorf("该门店未绑定京西平台storeID: %v", storeID)
}
@@ -109,7 +109,7 @@ func GetNearSupplyGoodsStoreByStoreID(ctx *jxcontext.Context, storeID int) (stor
return store, err
}
func GetStoreListByLocation(ctx *jxcontext.Context, lng, lat float64, maxRadius int, needWalkDistance, isJds bool, brandID int) (storeList []*Store4User, err error) {
func GetStoreListByLocation(ctx *jxcontext.Context, lng, lat float64, maxRadius int, needWalkDistance, isJds bool) (storeList []*Store4User, err error) {
const (
maxStoreCount4User = 5
)
@@ -134,20 +134,14 @@ func GetStoreListByLocation(ctx *jxcontext.Context, lng, lat float64, maxRadius
WHERE t1.deleted_at = ? AND t1.status <> ? AND t1.lng > ? AND t1.lng < ? AND t1.lat > ? AND t1.lat < ?
AND sm.is_order <> ?
AND t1.id <> ?
ORDER BY t1.id
`
sqlParams = append(sqlParams,
sqlParams = []interface{}{
model.VendorIDJX, utils.DefaultTimeValue, model.StoreStatusDisabled,
utils.DefaultTimeValue, model.StoreStatusDisabled, jxutils.StandardCoordinate2Int(lng1), jxutils.StandardCoordinate2Int(lng2), jxutils.StandardCoordinate2Int(lat1), jxutils.StandardCoordinate2Int(lat2),
model.YES,
model.MatterStoreID,
)
if brandID != 0 {
sql += " AND t1.brand_id = ?"
sqlParams = append(sqlParams, brandID)
}
sql += `
ORDER BY t1.id
`
} else {
sql = `
SELECT t1.*,
@@ -185,12 +179,12 @@ func GetStoreListByLocation(ctx *jxcontext.Context, lng, lat float64, maxRadius
city.name city_name
FROM store t1
JOIN place city ON city.code = t1.city_code
WHERE t1.deleted_at = ? AND t1.id = ?
WHERE t1.deleted_at = ? AND t1.status <> ? AND t1.id = ?
`
sqlParams2 := []interface{}{
// model.VendorIDJX, utils.DefaultTimeValue, model.StoreStatusDisabled,
utils.DefaultTimeValue,
// model.StoreStatusDisabled,
model.StoreStatusDisabled,
// jxutils.StandardCoordinate2Int(0),
// jxutils.StandardCoordinate2Int(10000),
// jxutils.StandardCoordinate2Int(0),
@@ -230,60 +224,3 @@ func GetStoreListByLocation(ctx *jxcontext.Context, lng, lat float64, maxRadius
}
return storeList, err
}
func GetVendorOrgCode(ctx *jxcontext.Context, vendorID int, vendorOrgCode, vendorType string) (vendorOrgs []*model.VendorOrgCode, err error) {
return dao.GetVendorOrgCode(dao.GetDB(), vendorID, vendorOrgCode, vendorType)
}
func UpdateVendorOrgCode(ctx *jxcontext.Context, ID int, payload map[string]interface{}) (err error) {
var (
db = dao.GetDB()
vendorOrgCode = &model.VendorOrgCode{}
)
vendorOrgCode.ID = ID
err = dao.GetEntity(db, vendorOrgCode)
valid := dao.StrictMakeMapByStructObject(payload, vendorOrgCode, ctx.GetUserName())
if len(valid) > 0 {
if valid["key"] != nil {
valid["vendorOrgCode"] = valid["key"]
delete(valid, "key")
}
if valid["code"] != nil {
valid["vendorID"] = valid["code"]
delete(valid, "code")
}
if valid["name"] != nil {
valid["comment"] = valid["name"]
delete(valid, "name")
}
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, txDB)
panic(r)
}
}()
if _, err = dao.UpdateEntityLogically(db, vendorOrgCode, valid, ctx.GetUserName(), nil); err != nil {
dao.Rollback(db, txDB)
return err
}
dao.Commit(db, txDB)
}
return err
}
func AddVendorOrgCode(ctx *jxcontext.Context, vendorOrgCode *model.VendorOrgCode) (err error) {
var (
db = dao.GetDB()
)
list, err := dao.GetVendorOrgCode(db, vendorOrgCode.VendorID, vendorOrgCode.VendorOrgCode, model.VendorOrgTypePlatform)
if err != nil {
return err
}
if len(list) > 0 {
return fmt.Errorf("库里有这个账号了,[%v]", vendorOrgCode.VendorOrgCode)
}
dao.WrapAddIDCULDEntity(vendorOrgCode, ctx.GetUserName())
dao.CreateEntity(db, vendorOrgCode)
return err
}

View File

@@ -1,33 +1,29 @@
package event
import (
"fmt"
"regexp"
"strings"
"time"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/dao"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/globals/api"
)
var (
NoUseEventMap = map[string]string{
"CreateQrOrBarCode": "CreateQrOrBarCode",
"StatisticsReportForOrders": "StatisticsReportForOrders",
"UpdateUser": "UpdateUser",
}
regexpToken = regexp.MustCompile(`,"token":".*"`)
)
type CheckCookie struct {
VendorID int `json:"vendorID"`
VendorOrgCode string `json:"vendorOrgCode"`
Status string `json:"status"`
}
const (
sysMessageTitle = ""
)
func AddOperateEvent(ctx *jxcontext.Context, accessUUID, jsonData string, errCode, errMsg string, useTime int, apiFunctionSpec string) (err error) {
var (
@@ -67,7 +63,7 @@ func AddOperateEvent(ctx *jxcontext.Context, accessUUID, jsonData string, errCod
ErrMsg: errMsg,
UseTime: useTime,
}
txDB , _ := dao.Begin(db)
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, txDB)
@@ -80,7 +76,7 @@ func AddOperateEvent(ctx *jxcontext.Context, accessUUID, jsonData string, errCod
}
func AddOperateEventDetail(db *dao.DaoDB, operateEventDetail *model.OperateEventDetail) (err error) {
txDB , _ := dao.Begin(db)
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, txDB)
@@ -96,7 +92,7 @@ func AddOperateEventDetail(db *dao.DaoDB, operateEventDetail *model.OperateEvent
func DeleteOperateEventAndDetail(ctx *jxcontext.Context, deleteTime time.Time) (err error) {
db := dao.GetDB()
txDB , _ := dao.Begin(db)
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, txDB)
@@ -133,69 +129,3 @@ func GetOperateEvents(ctx *jxcontext.Context, name string, apiFunctions []string
}
return pageInfo, err
}
func GetCheckVendorCookie(ctx *jxcontext.Context, vendorIDs []int, isAuto bool) (ccList []*CheckCookie, err error) {
var (
ebaiOrderID = "1577329467196263592"
ebaiErr = "return not json"
ebaiErr2 = "系统错误"
mtStoreID = "7388603"
mtErr = "返回结果格式不正常"
jdUpcCode = "6952395700895"
jdErr = "请输入用户名"
// mtpsErr = "用户未登录"
errMsg = ""
)
for _, v := range vendorIDs {
cc := &CheckCookie{}
var flag = false
switch v {
case model.VendorIDEBAI:
resultMap, err := api.EbaiAPI.GetStoreOrderInfo(ebaiOrderID)
if len(resultMap) < 1 && err != nil {
if strings.Contains(err.Error(), ebaiErr) || strings.Contains(err.Error(), ebaiErr2) {
errMsg += fmt.Sprintf(" 饿百账号:[%v]的Cookie无效了")
flag = true
}
}
case model.VendorIDMTWM:
_, err := api.MtwmAPI.PackagePriceGet(mtStoreID)
if err != nil {
if strings.Contains(err.Error(), mtErr) {
errMsg += fmt.Sprintf(" 美团账号:[%v]的Cookie无效了")
flag = true
}
globals.SugarLogger.Debugf("cookieCheck", err)
}
case model.VendorIDJD:
result, err := api.JdAPI.GetJdUpcCodeByName("", jdUpcCode, 1, 5)
if len(result) < 1 && err != nil {
if strings.Contains(err.Error(), jdErr) {
errMsg += fmt.Sprintf(" 京东账号:[%v]的Cookie无效了")
flag = true
}
}
case model.VendorIDJDShop:
_, err := api.JdShopAPI.OrderDetail("124350112427")
if err != nil {
if strings.Contains(err.Error(), "登录") {
errMsg += fmt.Sprintf("京东商城:[%v]的Cookie无效了")
flag = true
}
globals.SugarLogger.Debugf("cookieCheck", err)
}
}
cc.VendorID = v
cc.VendorOrgCode = ""
if flag {
cc.Status = "无效"
} else {
cc.Status = "有效"
}
ccList = append(ccList, cc)
}
if isAuto && errMsg != "" {
globals.SugarLogger.Warnf("GetCheckVendorCookie[%v]", errMsg)
}
return ccList, err
}

View File

@@ -1,119 +0,0 @@
package financial
import (
"context"
"errors"
"fmt"
"mime/multipart"
"path"
"strings"
"time"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
"git.rosy.net.cn/jx-callback/business/jxutils/weixinmsg"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/business/model/legacymodel"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/globals/api"
"github.com/qiniu/api.v7/storage"
)
type tUploadFileInfo struct {
FileHeader *multipart.FileHeader
StoreID int
}
func SendFilesToStores(ctx *jxcontext.Context, files []*multipart.FileHeader, title, shopName string, isAsync bool, userName string) (hint string, err error) {
globals.SugarLogger.Debugf("SendFilesToStores, fileCount:%d isAsync:%t, userName:%s", len(files), isAsync, userName)
if len(files) == 0 {
return "", errors.New("没有文件上传!")
}
fileList := make([]*tUploadFileInfo, len(files))
for k, fileHeader := range files {
fileList[k] = &tUploadFileInfo{
FileHeader: fileHeader,
}
fileNameParts := strings.Split(fileHeader.Filename, "_")
if len(fileNameParts) < 3 {
return "", fmt.Errorf("文件名:%s不规范没有包含三个必要的部分", fileHeader.Filename)
}
fileList[k].StoreID = int(utils.Str2Int64WithDefault(fileNameParts[0], 0))
if fileList[k].StoreID < 100000 || fileList[k].StoreID > 1000000 {
return "", fmt.Errorf("文件名:%s不规范不以合法的京西门店ID开始", fileHeader.Filename)
}
}
putPolicy := storage.PutPolicy{
Scope: globals.QiniuBucket,
Expires: 10 * 60,
}
upToken := putPolicy.UploadToken(api.QiniuAPI)
cfg := &storage.Config{}
task := tasksch.NewParallelTask("SendFilesToStores", tasksch.NewParallelConfig().SetIsContinueWhenError(true), ctx,
func(t *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
fileInfo := batchItemList[0].(*tUploadFileInfo)
fileHeader := fileInfo.FileHeader
db := dao.GetDB()
storeID, _ := dao.GetRealLinkStoreID(db, fileInfo.StoreID)
file, err := fileHeader.Open()
globals.SugarLogger.Debugf("SendFilesToStores upload file:%s", fileHeader.Filename)
if err == nil {
ret := storage.PutRet{}
key := "storeBill/" + utils.Int2Str(storeID) + "_" + strings.ToLower(utils.GetUUID()) + path.Ext(fileHeader.Filename)
formUploader := storage.NewFormUploader(cfg)
for i := 0; i < 3; i++ {
if err = formUploader.Put(context.Background(), &ret, upToken, key, file, fileHeader.Size, &storage.PutExtra{}); err == nil {
break
}
}
file.Close()
if err == nil {
billRec := &legacymodel.StoreBill{
Date: time.Now(),
Url: strings.Replace(jxutils.ComposeQiniuResURL(ret.Key), "http://", "https://", -1),
StoreId: storeID,
BillName: fileHeader.Filename,
ShopName: shopName,
BillTitle: title,
}
if err = dao.CreateEntity(db, billRec); err == nil {
err = weixinmsg.NotifySaleBill(storeID, title, shopName, fmt.Sprintf("%s/billshow/?path=%s", globals.BackstageHost, billRec.Url))
if err != nil {
globals.SugarLogger.Infof("SendFilesToStores NotifySaleBill file:%s error:%v", fileHeader.Filename, err)
}
err = nil // 忽略微信发送错误
} else {
globals.SugarLogger.Warnf("SendFilesToStores CreateEntity file:%s error:%v", fileHeader.Filename, err)
}
} else {
globals.SugarLogger.Warnf("SendFilesToStores file:%s failed with error:%v", fileHeader.Filename, err)
}
} else {
globals.SugarLogger.Warnf("SendFilesToStores open file:%s failed with error:%v", fileHeader.Filename, err)
}
return retVal, err
}, fileList)
tasksch.HandleTask(task, nil, true).Run()
hint = task.ID
if !isAsync {
_, err = task.GetResult(0)
}
return task.ID, err
}
func GetStoreBills(ctx *jxcontext.Context, storeID int) (bills []*legacymodel.StoreBill, err error) {
db := dao.GetDB()
if err = dao.GetRows(db, &bills, `
SELECT *
FROM store_bill
WHERE store_id = ?
ORDER BY date DESC
LIMIT 10
`, storeID); err != nil {
return nil, err
}
return bills, err
}

View File

@@ -1,278 +0,0 @@
package initdata
import (
"fmt"
"git.rosy.net.cn/baseapi/platformapi/autonavi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/globals/api"
)
func TruncateTable(db *dao.DaoDB, tableName string) (err error) {
_, err = dao.ExecuteSQL(db, "TRUNCATE TABLE "+tableName)
return err
}
func insertPlace(ctx *jxcontext.Context, db *dao.DaoDB, parent *autonavi.District, placeList []*autonavi.District) (err error) {
for _, v := range placeList {
if v.Level <= autonavi.DistrictLevelDistrict {
place := &model.Place{
Code: int(utils.Str2Int64(v.Adcode)),
Name: v.Name,
Level: int8(v.Level),
TelCode: v.CityCode,
Enabled: 1,
}
if parent != nil {
place.ParentCode = int(utils.Str2Int64(parent.Adcode))
}
dao.WrapAddIDCULEntity(place, ctx.GetUserName())
if err = dao.CreateEntity(db, place); err != nil {
return err
}
if err = insertPlace(ctx, db, v, v.Districts); err != nil {
return err
}
}
}
return nil
}
func InitPlace(ctx *jxcontext.Context) (err error) {
placeList, err2 := api.AutonaviAPI.GetDistricts(autonavi.DistrictLevelDistrict, "")
if err = err2; err != nil {
return err
}
placeList = placeList[0].Districts
db := dao.GetDB()
txDB , _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil || err != nil {
dao.Rollback(db, txDB)
if r != nil {
panic(r)
}
}
}()
if _, err = dao.ExecuteSQL(db, `
DELETE t1
FROM place t1
WHERE code < 9000000;
`); err != nil {
return err
}
if err = insertPlace(ctx, db, nil, placeList); err != nil {
return err
}
updateSqls := []string{
`
UPDATE place t1
JOIN jde_city t2 ON t1.code = t2.col_tencentAddressCode
SET t1.jd_code = t2.col_areaCode;
`,
`
UPDATE place t1
JOIN place t2 ON t1.parent_code = t2.code AND t2.jd_code != 0
JOIN jde_district t3 ON t1.name = t3.col_areaName AND t2.jd_code = t3.col_cityCode
SET t1.jd_code = t3.col_areaCode
WHERE t1.level = 3;
`,
`
UPDATE
place t1
JOIN ebde_places t2 ON t1.name = t2.col_city_name
SET t1.ebai_code = t2.col_city_id
WHERE t1.level = 1 OR t1.level = 2;
`,
`
UPDATE
place t1
JOIN place t1p ON t1.parent_code = t1p.code
JOIN ebde_places t2 ON t1.name = t2.col_city_name
JOIN ebde_places t2p ON t2.col_parent_id = t2p.col_city_id AND t1p.ebai_code = t2p.col_city_id
SET t1.ebai_code = t2.col_city_id
WHERE t1.level = 3;
`,
`
UPDATE
place t1
JOIN mtpsdeliveryprice t2 ON t1.code = t2.citycode
SET t1.mtps_price = t2.price;
`,
`
UPDATE
place t1
JOIN mtpsdeliveryprice t2 ON t1.name LIKE CONCAT(t2.cityname, '%')
SET t1.mtps_price = t2.price
WHERE t1.level = 2 AND t1.mtps_price = 0;
`,
`
UPDATE place t1
LEFT JOIN (
SELECT DISTINCT city_code
FROM store
UNION DISTINCT
SELECT DISTINCT place_code city_code
FROM sku_name_place_bind
) t2 ON t1.code = t2.city_code
SET t1.enabled = 0
WHERE t1.level = 2 AND t2.city_code IS NULL;
`,
}
for _, v := range updateSqls {
if _, err = dao.ExecuteSQL(db, v); err != nil {
return err
}
}
dao.Commit(db, txDB)
return err
}
func InitVendorCategory(ctx *jxcontext.Context, vendorID int, isAsync bool) (hint string, err error) {
if handler := partner.GetPurchasePlatformFromVendorID(vendorID); handler != nil {
var cats []*model.SkuVendorCategory
rootTask := tasksch.NewSeqTask(fmt.Sprintf("创建%s的平台分类", model.VendorChineseNames[vendorID]), ctx,
func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
switch step {
case 0:
cats, err = handler.GetVendorCategories(ctx)
if err != nil {
return nil, err
}
case 1:
db := dao.GetDB()
txDB , _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil || err != nil {
dao.Rollback(db, txDB)
if r != nil {
panic(r)
}
}
}()
sql := `
DELETE
FROM sku_vendor_category
WHERE vendor_id = ?
`
if _, err = dao.ExecuteSQL(db, sql, vendorID); err != nil {
return nil, err
}
for _, cat := range cats {
dao.WrapAddIDCULEntity(cat, ctx.GetUserName())
}
if err = dao.CreateMultiEntities(db, cats); err != nil {
return nil, err
}
dao.Commit(db, txDB)
}
return nil, err
}, 2)
tasksch.HandleTask(rootTask, nil, true).Run()
if !isAsync {
if _, err = rootTask.GetResult(0); err == nil {
hint = utils.Int2Str(len(cats))
}
} else {
hint = rootTask.ID
}
} else {
err = fmt.Errorf("找不到平台:%d", vendorID)
}
return hint, err
}
func UploadImg4Vendors(ctx *jxcontext.Context, isAsync, isContinueWhenError bool) (hint string, err error) {
// db := dao.GetDB()
// rootTask := tasksch.NewSeqTask("合并SkuName图片至DataResource", ctx,
// func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
// switch step {
// case 0: // 计算SkuName中缺失的hashCode注意是DescImg不是Img
// var skuNameList []*model.SkuName
// if err = dao.GetRows(db, &skuNameList, `
// SELECT t1.*
// FROM sku_name t1
// WHERE t1.desc_img <> '' AND t1.img_hash_code = ''
// `); err == nil && len(skuNameList) > 0 {
// calcTask := tasksch.NewParallelTask("UploadImg4Vendors calc hashCode",
// tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError).SetParallelCount(5), ctx,
// func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
// skuName := batchItemList[0].(*model.SkuName)
// _, skuName.ImgHashCode, err = jxutils.DownloadFileByURL(skuName.DescImg)
// if err == nil {
// dao.UpdateEntity(db, skuName, "ImgHashCode")
// }
// return retVal, err
// }, skuNameList)
// tasksch.HandleTask(calcTask, task, false).Run()
// _, err = calcTask.GetResult(0)
// }
// case 1: // 从SkuName添加缺失的图片至DataResource
// _, err = dao.ExecuteSQL(db, `
// INSERT INTO data_resource(created_at, updated_at, last_operator, hash_code,
// resource_type, name, main_url, ebai_url, qiniu_url, use_type)
// SELECT t1.created_at, t1.created_at, t1.last_operator, t1.img_hash_code,
// CASE
// WHEN INSTR(t1.desc_img, ".jpg") > 0 OR INSTR(t1.desc_img, ".jpeg") > 0 THEN
// 'image/jpeg'
// WHEN INSTR(t1.desc_img, ".png") > 0 OR INSTR(t1.desc_img, ".peg") > 0 THEN
// 'image/png'
// WHEN INSTR(t1.desc_img, ".gif") THEN
// 'image/gif'
// ELSE
// ''
// END resource_type,
// CONCAT(t1.name, '_desc'), desc_img main_url, t1.desc_img_ebai ebai_url,
// IF(INSTR(t1.desc_img, "image.jxc4.com") > 0, t1.desc_img, '') qiniu_url, 2
// FROM sku_name t1
// JOIN (
// SELECT img_hash_code, MAX(id) id, COUNT(*) ct
// FROM sku_name
// WHERE img_hash_code <> '' AND desc_img <> ''
// GROUP BY 1
// ) t3 ON t3.id = t1.id
// LEFT JOIN data_resource t2 ON (t2.main_url <> '' AND t2.main_url = t1.desc_img)
// WHERE t1.desc_img <> '' AND t1.img_hash_code <> '' AND t2.id IS NULL;
// `)
// case 2: // 统一SkuName中同hashCode不同图片地址至同一地址
// _, err = dao.ExecuteSQL(db, `
// UPDATE sku_name t1
// JOIN data_resource t2 ON t2.hash_code = t1.img_hash_code AND t2.main_url <> ''
// SET t1.desc_img = t2.main_url
// WHERE t1.img_hash_code <> '' AND t1.desc_img <> t2.main_url;
// `)
// case 3: // 上传DataResource中缺失的平台图片
// dataResList, err2 := dao.GetNeedUploadDataResource(db)
// if err = err2; err == nil && len(dataResList) > 0 {
// uploadTask := tasksch.NewParallelTask("批量上传图片至平台",
// tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError).SetParallelCount(2), ctx,
// func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
// dataRes := batchItemList[0].(*model.DataResource)
// _, err = datares.UploadImage2Vendors(ctx, task, dataRes, nil, false)
// return nil, err
// }, dataResList)
// tasksch.HandleTask(uploadTask, task, true).Run()
// _, err = uploadTask.GetResult(0)
// }
// }
// return result, err
// }, 4)
// tasksch.HandleTask(rootTask, nil, true).Run()
// if !isAsync {
// if _, err = rootTask.GetResult(0); err == nil {
// hint = "1"
// }
// } else {
// hint = rootTask.ID
// }
return hint, err
}
func getSkuNameKey(prefix, name, comment, specUnit, unit string, specQuality float32) string {
return fmt.Sprintf("%s-%s-%f-%s-%s", prefix, name, specQuality, specUnit, unit)
}

View File

@@ -1,119 +0,0 @@
package knowledge
import (
"fmt"
"git.rosy.net.cn/baseapi/platformapi/weixinapi"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/jxutils/weixinmsg"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/globals/api"
"mime/multipart"
"net/http"
)
func GetKnowledgeDepot(ctx *jxcontext.Context, keyword string, offset, pageSize int) (page *model.PagedInfo, err error) {
return dao.GetKnowledgeDepot(dao.GetDB(), keyword, offset, pageSize)
}
func AddKnowledgeDepot(ctx *jxcontext.Context, title, content string) (err error) {
var (
db = dao.GetDB()
)
know := &model.KnowledgeDepot{
Title: title,
Content: content,
}
dao.WrapAddIDCULDEntity(know, ctx.GetUserName())
dao.CreateEntity(db, know)
return err
}
func UpdateKnowledgeDepot(ctx *jxcontext.Context, id int, content string, isDel bool) (err error) {
var (
db = dao.GetDB()
know = &model.KnowledgeDepot{}
)
know.ID = id
err = dao.GetEntity(db, know)
if isDel {
dao.DeleteEntity(db, know)
} else {
if content != know.Content {
know.Content = content
dao.UpdateEntity(db, know, "Content")
}
}
return err
}
type SNSUploadImgResult struct {
URL string `json:"url"`
MediaID string `json:"mediaID"`
}
func SNSUploadImg(ctx *jxcontext.Context, files []*multipart.FileHeader, isThumb bool) (snsUploadImgResult *SNSUploadImgResult, err error) {
var (
fileHeader = files[0]
fileName = fileHeader.Filename
data = make([]byte, fileHeader.Size)
)
snsUploadImgResult = &SNSUploadImgResult{}
file, err := fileHeader.Open()
file.Read(data)
if len(data) == 0 {
return snsUploadImgResult, fmt.Errorf("未读取到文件!")
}
//如果不是缩略图只会返url
//如果是封面缩略图则还会返mediaID
if !isThumb {
if url, err := api.WeixinAPI.CBUploadImg(data, fileName, http.DetectContentType(data)); err == nil && url != "" {
snsUploadImgResult.URL = url
}
} else {
if mediaID, url, err := api.WeixinAPI.CBUploadThumb(data, fileName, http.DetectContentType(data)); err == nil && url != "" && mediaID != "" {
snsUploadImgResult.URL = url
snsUploadImgResult.MediaID = mediaID
}
}
file.Close()
return snsUploadImgResult, err
}
func AddMaterial(ctx *jxcontext.Context, knowIDs []int, param *weixinapi.CBAddNewsParam) (err error) {
var (
db = dao.GetDB()
content = ""
)
if len(knowIDs) == 0 {
return fmt.Errorf("请至少勾选一条!")
}
knows, err := dao.GetKnowledgeDepotNoPage(db, knowIDs)
for k, v := range knows {
if k != 0 {
content += weixinapi.SNSCutLine
}
content += v.Content
}
if content != "" {
param.Content = content
api.WeixinAPI.CBAddNews(param)
} else {
return fmt.Errorf("读取内容错误!")
}
return err
}
func SendSNSMediaMsg(ctx *jxcontext.Context, storeIDs []int, mediaID string) (err error) {
var (
openIDs []string
)
for _, v := range storeIDs {
if results := weixinmsg.GetWeixinOpenIDsFromStoreID(v); len(results) > 0 {
openIDs = append(openIDs, results...)
}
}
if len(openIDs) > 0 {
return weixinmsg.MediaMessageSendGroup(openIDs, mediaID)
}
return err
}

View File

@@ -1,623 +1,15 @@
package misc
import (
"fmt"
"sync"
"time"
"git.rosy.net.cn/jx-callback/business/partner/purchase/jdshop"
"git.rosy.net.cn/baseapi/platformapi/jdapi"
"git.rosy.net.cn/jx-callback/business/partner/purchase/jx/localjx"
"git.rosy.net.cn/jx-callback/globals/api"
"git.rosy.net.cn/jx-callback/business/jxstore/report"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/baseapi/utils/errlist"
"git.rosy.net.cn/jx-callback/business/jxcallback/orderman"
"git.rosy.net.cn/jx-callback/business/jxcallback/scheduler/defsch"
"git.rosy.net.cn/jx-callback/business/jxstore/act"
"git.rosy.net.cn/jx-callback/business/jxstore/cms"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/jxutils/netprinter"
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/business/netspider"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/globals"
beego "github.com/astaxie/beego/server/web"
)
const (
SpecialTaskID = "Running"
TaskNameSyncStoreSku = "SyncStoreSku"
)
var (
dailyHeartbeat = []string{
"09:00:00",
}
dailyWorkTimeList = []string{
"21:30:00",
}
dailyWorkTimeList2 = []string{
"2:00:00",
}
priceReferTimeList = []string{
"03:00:00",
}
checkCookieList = []string{
"08:00:00",
"12:00:00",
"18:00:00",
}
createStorePriceTimeList = []string{
"04:00:00",
}
refreshPageActTimeList = []string{
"7:00:00",
"8:00:00",
"9:00:00",
"10:00:00",
"11:00:00",
"12:00:00",
"13:00:00",
"14:00:00",
"15:00:00",
"16:00:00",
"17:00:00",
"18:00:00",
"19:00:00",
"22:00:00",
}
ChangeStoreSkuSaleStatusList = []string{
"7:00:00",
"8:00:00",
"9:00:00",
"10:00:00",
"11:00:00",
"12:00:00",
"13:00:00",
"14:00:00",
"15:00:00",
"16:00:00",
"17:00:00",
"18:00:00",
"19:00:00",
"20:00:00",
}
openRemoteStoreTimeList = []string{
"04:30:00",
"23:30:00",
}
updateActStatusTimeList = []string{
"00:01:00",
}
sendSecKillWarnList = []string{
"9:00:00",
}
autoPayForPopluarManList = []string{
"10:30:00",
}
autoSaleStoreSkuTimeList = []string{
cms.AutoSaleAtStr,
}
backUpStoreSkuBindList = []string{
"23:30:00",
}
exSyncList = []string{
"11:30:00",
}
importantTaskMap = &sync.Map{}
cancelPayTimeOutOrderList = localjx.GetHalfHoursList()
discountActJxList = localjx.GetDiscountActHoursList()
//ebaiStorePageCookieExdTOKEN string
//ebaiStorePageCookieWMUSS2 string
//ebaiStorePageCookieWMSTOKEN2 string
ebaiStorePageCookie string
//ebaiStorePageCookieWMSTOKEN string
mtwmCookieStr string
mtpsStoreToken string
jd2StorePageCookie string
JdStorePageCookie string
yinbaoCookie string
feiePageCookie string
jdStorePageEarning string
//jdsCookie string
// jdsCookie2 string
)
func GetImportantTaskID(taskName string) string {
if value, ok := importantTaskMap.Load(taskName); ok {
return value.(string)
}
return ""
}
func SaveImportantTaskID(taskName, taskID string) {
importantTaskMap.Store(taskName, taskID)
}
func IsImportantTaskRunning(taskName string) bool {
taskID := GetImportantTaskID(taskName)
if taskID == "" {
return false
} else if taskID == SpecialTaskID {
return true
}
return tasksch.IsTaskRunning(taskID)
}
func Init() {
if globals.IsProductEnv() {
//ScheduleTimerFunc("doDailyWork2", doDailyWork2, dailyWorkTimeList2)
//京东的订单信息解密密钥获取
ScheduleTimerFuncByInterval(func() {
jdshop.InitKey()
}, 10*time.Second, 8*time.Hour)
ScheduleTimerFuncByInterval(func() {
RefreshRealMobile(jxcontext.AdminCtx, model.VendorIDEBAI, time.Now().Add(-24*time.Hour), utils.DefaultTimeValue, false, true)
report.RefreshStoreManageState(jxcontext.AdminCtx, nil, []int{model.VendorIDJD})
}, 5*time.Second, 1*time.Hour)
ScheduleTimerFuncByInterval(func() {
defsch.FixedScheduler.ConfirmSelfTakeOrders(jxcontext.AdminCtx, []int{model.VendorIDJD}, time.Now().Add(-48*time.Hour), time.Now().Add(-30*time.Minute), true, true)
}, 5*time.Second, 10*time.Minute)
ScheduleTimerFuncByInterval(func() {
report.RefreshStoreManageState(jxcontext.AdminCtx, nil, []int{model.VendorIDMTWM, model.VendorIDEBAI})
}, 5*time.Second, 40*time.Minute)
ScheduleTimerFuncByInterval(func() {
curDate := utils.Time2Date(time.Now())
orderman.FixedOrderManager.AmendMissingOrders(jxcontext.AdminCtx, []int{model.VendorIDJD, model.VendorIDMTWM, model.VendorIDEBAI}, 0, curDate, curDate, true, true)
orderman.SaveJdsOrders(jxcontext.AdminCtx, time.Now().Add(-30*time.Minute), time.Now())
}, 5*time.Second, 10*time.Minute)
ScheduleTimerFunc("RefreshJdShopOrdersEarningPrice", func() {
orderman.RefreshJdShopOrdersEarningPrice(jxcontext.AdminCtx, utils.Time2Str(time.Now().AddDate(0, 0, -2)), utils.Time2Str(time.Now().AddDate(0, 0, -2)))
orderman.RefreshJdShopOrdersEarningPrice(jxcontext.AdminCtx, utils.Time2Str(time.Now().AddDate(0, 0, -1)), utils.Time2Str(time.Now().AddDate(0, 0, -1)))
}, []string{
"05:00:00",
})
ScheduleTimerFunc("auto enable remote store", func() {
cms.EnableHaveRestStores(jxcontext.AdminCtx, false, true)
// cms.OpenRemoteStoreByJxStatus(jxcontext.AdminCtx, nil, nil, false, false, true)
}, openRemoteStoreTimeList)
// ScheduleTimerFunc("SaveAndSendAlarmVendorSnapshot", func() {
// cms.SaveAndSendAlarmVendorSnapshot(jxcontext.AdminCtx, nil, nil, false)
// }, cms.WatchVendorStoreTimeList)
ScheduleTimerFunc("RefreshPageActs", func() {
act.RefreshPageActs(jxcontext.AdminCtx, []int{model.VendorIDEBAI}, time.Now().Add(-30*24*time.Hour), false)
}, refreshPageActTimeList)
ScheduleTimerFunc("UpdateActStatusByTime", func() {
dao.UpdateActStatusByTime(dao.GetDB(), time.Now())
}, updateActStatusTimeList)
ScheduleScoreStore()
// ScheduleCheckStoreAlert()
ScheduleTimerFunc("ChangeStoreSkuSaleStatus", func() {
cms.CurVendorSync.ChangeStoreSkuSaleStatus(jxcontext.AdminCtx, 0, true, true)
}, ChangeStoreSkuSaleStatusList)
ScheduleTimerFunc("BeginSavePriceRefer", func() {
report.BeginSavePriceRefer(jxcontext.AdminCtx, nil, nil, true, true)
}, priceReferTimeList)
ScheduleTimerFunc("CreateStorePriceScore", func() {
cms.CreateStorePriceScore(jxcontext.AdminCtx)
}, createStorePriceTimeList)
ScheduleTimerFunc("AutoFocusStoreSkusForTopSkus", func() {
cms.AutoFocusStoreSkusForTopSkus(jxcontext.AdminCtx, true, true)
}, createStorePriceTimeList)
//ScheduleTimerFunc("GetCheckVendorCookie", func() {
// event.GetCheckVendorCookie(jxcontext.AdminCtx, []int{model.VendorIDEBAI, model.VendorIDJD, model.VendorIDMTWM, model.VendorIDMTPS, model.VendorIDJDShop}, true)
//}, checkCookieList)
//ScheduleTimerFunc("SendSeckillSkusCountMsg", func() {
// cms.SendSeckillSkusCountMsg(jxcontext.AdminCtx, []int{model.VendorIDEBAI, model.VendorIDJD, model.VendorIDMTWM}, false, true)
//}, sendSecKillWarnList)
// ScheduleTimerFunc("每日报警心跳", func() {
// globals.SugarLogger.Warnf("每日报警心跳,这不是报警。启动时间:%s", cms.GetServiceInfo(jxcontext.AdminCtx)["startupTime"])
// }, dailyHeartbeat)
ScheduleTimerFunc("AutoPayForPopluarMan", func() {
localjx.AutoPayForPopluarMan(jxcontext.AdminCtx)
}, autoPayForPopluarManList)
ScheduleTimerFunc("CancelPayTimeOutOrder", func() {
localjx.CancelPayTimeOutOrder(jxcontext.AdminCtx)
}, cancelPayTimeOutOrderList)
ScheduleTimerFunc("BackUpStoreSkuBind", func() {
cms.BackUpStoreSkuBind(jxcontext.AdminCtx, true, true)
}, backUpStoreSkuBindList)
// ScheduleTimerFunc("SendNoCatSkusToOperater", func() {
// cms.SendNoCatSkusToOperater(jxcontext.AdminCtx)
// }, autoPayForPopluarManList)
ScheduleTimerFunc("CleanStoreIsBoughtMatter", func() {
cms.CleanStoreIsBoughtMatter(jxcontext.AdminCtx)
}, priceReferTimeList)
ScheduleTimerFunc("CleanUserOrderSMSMark", func() {
cms.CleanUserOrderSMSMark(jxcontext.AdminCtx)
}, priceReferTimeList)
ScheduleTimerFunc("CreateOrderByPriceDefend", func() {
localjx.CreateOrderByPriceDefend(jxcontext.AdminCtx)
}, []string{
"22:00:00",
})
//ScheduleTimerFunc("ChangeJxPriceByDiscountAct", func() {
// act.ChangeJxPriceByDiscountAct(jxcontext.AdminCtx)
//}, discountActJxList)
ScheduleTimerFunc("RefreshUserMemberStatus", func() {
cms.RefreshUserMemberStatus(jxcontext.AdminCtx)
}, updateActStatusTimeList)
//刷优惠券状态
ScheduleTimerFunc("RefreshCouponsStatus", func() {
localjx.RefreshCouponsStatus(jxcontext.AdminCtx)
}, updateActStatusTimeList)
//刷新美团商超门店Token
ScheduleTimerFunc("RefreshMTWMToken", func() {
cms.RefreshMTWMToken(jxcontext.AdminCtx)
}, updateActStatusTimeList)
//获取最新平台流量活动
ScheduleTimerFunc("GetNewVendorPopActs", func() {
act.GetNewVendorPopActs(jxcontext.AdminCtx)
}, dailyHeartbeat)
//企业微信群人数通告
ScheduleTimerFunc("SendQywxPeopleCount", func() {
cms.SendQywxPeopleCount(jxcontext.AdminCtx)
}, dailyHeartbeat)
//刷新京东售后单结算价
ScheduleTimerFunc("RefreshJdAfsOrderTotalShopMoney", func() {
orderman.RefreshJdAfsOrderTotalShopMoney()
}, openRemoteStoreTimeList)
ScheduleTimerFunc("doDailyWork1", func() {
//同步商品额外前缀和水印图(打标记)
cms.SyncSkuExperfixAndWatermark(jxcontext.AdminCtx)
}, dailyWorkTimeList)
ScheduleTimerFunc("BuildFakeMatterOrder", func() {
orderman.BuildFakeMatterOrder()
}, []string{
"09:00:00",
"15:00:00",
"23:00:00",
})
ScheduleTimerFunc("doDailyWork2", func() {
//刷新京东会员
//report.RefreshJDMembers(jxcontext.AdminCtx)
cms.SetSingleStoreSkuSyncModifyStatus(dao.GetDB(), []int{1, 3})
cms.CurVendorSync.SyncStoresSkus2(jxcontext.AdminCtx, nil, 0, dao.GetDB(), []int{1, 3}, nil, false, nil, nil, model.SyncFlagSaleMask, true, true)
}, dailyWorkTimeList)
ScheduleTimerFunc("doDailyWork3", func() {
dao.SetStoresMapSyncStatus(dao.GetDB(), nil, nil, model.SyncFlagStoreStatus)
cms.CurVendorSync.SyncStore2(jxcontext.AdminCtx, dao.GetDB(), []int{model.VendorIDMTWM, model.VendorIDJD, model.VendorIDEBAI}, nil, true, true)
syncStoreSku()
InitEx()
cms.SyncStoresCourierInfo(jxcontext.AdminCtx, nil, false, true)
netprinter.RebindAllPrinters(jxcontext.AdminCtx, false, true)
}, dailyWorkTimeList)
ScheduleTimerFunc("doDailyWork4", func() {
curDate := utils.Time2Date(time.Now())
orderman.FixedOrderManager.AmendMissingOrders(jxcontext.AdminCtx, []int{model.VendorIDJD, model.VendorIDMTWM, model.VendorIDEBAI}, 0, curDate.Add(-72*time.Hour), curDate, true, true)
//只传toDate默认刷新toDate到5天以前的订单
orderman.RefreshOrdersWithoutJxStoreID(jxcontext.AdminCtx, "", "", true, true)
//禁用没有绑定的门店
cms.DisabledStoreWithoutVendor(jxcontext.AdminCtx, true, true)
}, dailyWorkTimeList)
ScheduleTimerFunc("doDailyWork5", func() {
//刷新物料订单状态
localjx.RefreshAllMatterOrderStatus(jxcontext.AdminCtx)
//同步美团配送与否状态及美团门店是否存在
//cms.SetMTPSStatus(jxcontext.AdminCtx, 0, 0)
cms.SetMTPSStatus2(0)
//售后单如果超过12小时没有审核就自动通过
RefreshAfsOrderStatusAccess(jxcontext.AdminCtx)
//刷新门店分组管理
cms.RefreshStoreBind(jxcontext.AdminCtx)
}, dailyWorkTimeList)
ScheduleTimerFunc("RrefreshMtwmVendorAct", func() {
//刷新美团平台活动
act.RrefreshMtwmVendorAct()
//刷新饿百平台活动
act.RrefreshEbaiVendorAct()
}, dailyWorkTimeList2)
}
ScheduleTimerFunc("AutoSaleStoreSku", func() {
cms.AutoSaleStoreSku(jxcontext.AdminCtx, nil, false)
}, autoSaleStoreSkuTimeList)
if beego.BConfig.RunMode == "jxgy" {
ScheduleTimerFunc("SyncMatterC4ToGy", func() {
cms.SyncMatterC4ToGy(jxcontext.AdminCtx, true, true)
}, dailyWorkTimeList)
}
if beego.BConfig.RunMode == "beta" {
//ScheduleTimerFunc("CancelPayTimeOutOrder", func() {
// localjx.CancelPayTimeOutOrder(jxcontext.AdminCtx)
//}, cancelPayTimeOutOrderList)
ScheduleTimerFunc("GetAndStoreCitiesShops", func() {
netspider.GetAndStoreCitiesShops(jxcontext.AdminCtx, nil, nil, 0, 0, false, false)
}, []string{
"04:05:06",
})
//京东的订单信息解密密钥获取
//ScheduleTimerFuncByInterval(func() {
// jdshop.InitKey()
//}, 10*time.Second, 8*time.Hour)
ScheduleTimerFunc("ChangeJxPriceByDiscountAct", func() {
act.ChangeJxPriceByDiscountAct(jxcontext.AdminCtx)
}, discountActJxList)
//ScheduleTimerFunc("CreateOrderByPriceDefend", func() {
// localjx.CreateOrderByPriceDefend(jxcontext.AdminCtx)
//}, []string{
// "22:00:00",
//})
//刷新门店数据坐标等
ScheduleTimerFunc("RefreshPageStore", func() {
cms.RefreshPageStore()
}, []string{
"20:00:00",
})
}
if configs, err := dao.QueryConfigs(dao.GetDB(), "ebaiStorePageCookie", model.ConfigTypeCookie, ""); err == nil {
ebaiStorePageCookie = configs[0].Value
}
if configs, err := dao.QueryConfigs(dao.GetDB(), "mtwmCookieStr", model.ConfigTypeCookie, ""); err == nil {
mtwmCookieStr = configs[0].Value
}
if configs, err := dao.QueryConfigs(dao.GetDB(), "mtpsStoreToken", model.ConfigTypeCookie, ""); err == nil {
mtpsStoreToken = configs[0].Value
}
if configs, err := dao.QueryConfigs(dao.GetDB(), "jdStorePageCookie", model.ConfigTypeCookie, ""); err == nil {
JdStorePageCookie = configs[0].Value
}
if configs, err := dao.QueryConfigs(dao.GetDB(), "jdStorePageEarning", model.ConfigTypeCookie, ""); err == nil {
jdStorePageEarning = configs[0].Value
}
if configs, err := dao.QueryConfigs(dao.GetDB(), "jd2StorePageCookie", model.ConfigTypeCookie, ""); err == nil {
jd2StorePageCookie = configs[0].Value
}
if configs, err := dao.QueryConfigs(dao.GetDB(), "feiePageCookie", model.ConfigTypeCookie, ""); err == nil {
feiePageCookie = configs[0].Value
}
//if configs, err := dao.QueryConfigs(dao.GetDB(), "jdsCookie", model.ConfigTypeCookie, ""); err == nil {
// jdsCookie = configs[0].Value
// api.JdShopAPI.SetCookieWithStr(jdsCookie)
//}
//if configs, err := dao.QueryConfigs(dao.GetDB(), "yinbaoCookie", model.ConfigTypeCookie, ""); err == nil {
// yinbaoCookie := configs[0].Value
// api.YinBaoAPI.SetCookie(".POSPALAUTH30220", yinbaoCookie)
//}
if globals.Jd2OrgCode != "" {
api.Jd2API.SetJdCookie(jd2StorePageCookie)
}
//api.EbaiAPI.SetCookie("PASSPORT_DELIMONT_TOKEN", ebaiStorePageCookieExdTOKEN)
//api.EbaiAPI.SetCookie("WMUSS", ebaiStorePageCookieWMUSS)
//api.EbaiAPI.SetCookie("WMSTOKEN", ebaiStorePageCookieWMSTOKEN)
//api.Ebai2API.SetCookie("PASSPORT_DELIMONT_TOKEN", ebaiStorePageCookieExdTOKEN)
//api.Ebai2API.SetCookie("WMUSS", ebaiStorePageCookieWMUSS2)
//api.Ebai2API.SetCookie("WMSTOKEN", ebaiStorePageCookieWMSTOKEN2)
api.EbaiAPI.SetCookieWithStr(ebaiStorePageCookie)
api.MtwmAPI.SetCookieWithStr(mtwmCookieStr)
api.MtpsAPI.SetCookie("token", mtpsStoreToken)
//api.JdAPI.SetJdCookie(JdStorePageCookie)
api.JdAPI.SetCookieWithStr(JdStorePageCookie)
api.JdAPI.SetCookie("user", jdStorePageEarning)
api.JdPageAPI.SetCookie(jdapi.AccessStorePageCookieName, JdStorePageCookie)
api.JdPageAPI.SetCookie(jdapi.AccessStorePageCookieName2, JdStorePageCookie)
api.FeieAPI.SetCookieWithStr(feiePageCookie)
}
func syncStoreSku() {
syncFlag := 0
if beego.BConfig.RunMode == "jxgy" {
//syncFlag = model.SyncFlagPriceMask
if true {
syncFlag |= model.SyncFlagSaleMask
}
} else {
syncFlag |= model.SyncFlagSaleMask
}
task := tasksch.NewParallelTask("同步京西与平台数据", nil, jxcontext.AdminCtx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
step := batchItemList[0].(int)
errList := errlist.New()
db := dao.GetDB()
switch step {
case 0:
if beego.BConfig.RunMode != "jxgy" {
errList.AddErr(cms.DeleteSkuNameExPrefixOverdue(db))
errList.AddErr(cms.SetMultiStoreSkuSyncModifyStatus(db, partner.GetMultiStoreVendorIDs()))
_, err = cms.CurVendorSync.LoopMultiStoresVendors(jxcontext.AdminCtx, db, "同步多门店平台商品库", false, true,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
vendorInfo := batchItemList[0].(*cms.MultiStoreVendorInfo)
_, err = cms.FullSyncVendorStuff(jxcontext.AdminCtx, task, 0, vendorInfo.VendorID, vendorInfo.OrgCode, false, true)
return retVal, err
})
errList.AddErr(err)
_, err = cms.CurVendorSync.SyncStoresSkus2(jxcontext.AdminCtx, nil, 0, db, []int{0}, nil, false, nil, []int{27379}, syncFlag, true, true)
//_, err = cms.CurVendorSync.FullSyncStoresSkus(jxcontext.AdminCtx, db, partner.GetMultiStoreVendorIDs(), nil, false, []int{27379}, true, true)
errList.AddErr(err)
}
case 1:
//TODO 暂时不同步银豹可能要从银豹到京西2020-04-27
//errList.AddErr(cms.SetSingleStoreSkuSyncModifyStatus(db, []int{1, 3}))
// errList.AddErr(cms.SetSingleStoreSkuSyncModifyStatus(db, partner.GetSingleStoreVendorIDs()))
// _, err = cms.CurVendorSync.AmendAndPruneStoreStuff(jxcontext.AdminCtx, []int{1, 3}, nil, false, true, cms.AmendPruneAll, false)
// _, err = cms.CurVendorSync.AmendAndPruneStoreStuff(jxcontext.AdminCtx, partner.GetSingleStoreVendorIDs(), nil, false, true, cms.AmendPruneAll, false)
errList.AddErr(err)
SaveImportantTaskID(TaskNameSyncStoreSku, SpecialTaskID)
//taskID, err2 := cms.CurVendorSync.SyncStoresSkus2(jxcontext.AdminCtx, nil, 0, db, []int{1, 3}, nil, false, nil, nil, syncFlag, true, true)
// taskID, err2 := cms.CurVendorSync.SyncStoresSkus2(jxcontext.AdminCtx, nil, 0, db, partner.GetSingleStoreVendorIDs(), nil, false, nil, nil, syncFlag, true, true)
//errList.AddErr(err2)
//SaveImportantTaskID(TaskNameSyncStoreSku, taskID)
}
err = errList.GetErrListAsOne()
return retVal, err
}, []int{0, 1})
tasksch.HandleTask(task, nil, true).Run()
}
func doDailyWork2() {
globals.SugarLogger.Debug("doDailyWork2")
if beego.BConfig.RunMode == "jxgy" {
syncStoreSku()
refreshPointOrderNewEarningPrice()
}
//同步京东商城门店的商品
// cms.CurVendorSync.SyncJdsStoresSkus(jxcontext.AdminCtx, nil, true, true)
//刷新京东商城的门店库存
// cms.SyncJdsStoreStock(jxcontext.AdminCtx, true, true)
}
func doDailyWork() {
globals.SugarLogger.Debug("doDailyWork")
//同步商品额外前缀和水印图(打标记)
cms.SyncSkuExperfixAndWatermark(jxcontext.AdminCtx)
dao.SetStoresMapSyncStatus(dao.GetDB(), nil, nil, model.SyncFlagStoreStatus)
cms.CurVendorSync.SyncStore2(jxcontext.AdminCtx, dao.GetDB(), []int{model.VendorIDMTWM, model.VendorIDJD, model.VendorIDEBAI}, nil, true, true)
if beego.BConfig.RunMode == "prod" {
syncStoreSku()
}
InitEx()
cms.SyncStoresCourierInfo(jxcontext.AdminCtx, nil, false, true)
netprinter.RebindAllPrinters(jxcontext.AdminCtx, false, true)
// 每天补全前一天与当天的订单
// curDate := utils.Time2Date(time.Now())
// orderman.FixedOrderManager.AmendMissingOrders(jxcontext.AdminCtx, nil, 0, curDate.Add(-72*time.Hour), curDate, true, true)
//订单门店归属补漏
//fromDate, toDate都不传默认刷新当前天5天以前的订单只传fromDate默认刷新fromDate到当天的订单
//只传toDate默认刷新toDate到5天以前的订单
orderman.RefreshOrdersWithoutJxStoreID(jxcontext.AdminCtx, "", "", true, true)
//刷新京东门店的等级
// cms.RefreshJdLevel(jxcontext.AdminCtx)
//删除操作日志
// event.DeleteOperateEventAndDetail(jxcontext.AdminCtx, time.Now().AddDate(0, -3, 0))
//禁用没有绑定的门店
cms.DisabledStoreWithoutVendor(jxcontext.AdminCtx, true, true)
//刷新物料订单状态
localjx.RefreshAllMatterOrderStatus(jxcontext.AdminCtx)
//同步银豹到京西
// cms.CurVendorSync.SyncStoreSkusFromYb(jxcontext.AdminCtx, nil, true, true)
//同步上架京东商城待售商品
// cms.RefreshJdsSkusStatus(jxcontext.AdminCtx)
//同步美团配送与否状态及美团门店是否存在
cms.SetMTPSStatus(jxcontext.AdminCtx, 0, 0)
//售后单如果超过12小时没有审核就自动通过
RefreshAfsOrderStatusAccess(jxcontext.AdminCtx)
//刷新京东商城订单结算价
orderman.RefreshJdShopOrdersEarningPrice(jxcontext.AdminCtx, utils.Time2Str(time.Now().AddDate(0, 0, -2)), utils.Time2Str(time.Now()))
//刷新门店分组管理
cms.RefreshStoreBind(jxcontext.AdminCtx)
//刷新京东会员
report.RefreshJDMembers(jxcontext.AdminCtx)
}
func refreshPointOrderNewEarningPrice() {
var (
db = dao.GetDB()
orders []*model.GoodsOrder
)
sql := `
SELECT * FROM goods_order WHERE earning_type = 2 AND status = 110 AND order_created_at > ?
`
sqlParams := []interface{}{time.Now().AddDate(0, 0, -1)}
dao.GetRows(db, &orders, sql, sqlParams)
if len(orders) > 0 {
for _, v := range orders {
if v.NewEarningPrice == 0 {
v.NewEarningPrice = int64(int(v.TotalShopMoney) * (100 - v.OrderPayPercentage/2) / 100)
dao.UpdateEntity(db, v, "NewEarningPrice")
}
}
}
}
func RefreshAfsOrderStatusAccess(ctx *jxcontext.Context) {
var (
offset = 0
pageSize = 9999
db = dao.GetDB()
)
afsOrderList, _, err := dao.GetAfsOrdersByPage(db, "", "", "", time.Now().AddDate(0, 0, -7), time.Now(), offset, pageSize)
if err != nil {
return
}
for _, v := range afsOrderList {
if v.Status == model.AfsOrderStatusWait4Approve && time.Now().Sub(v.AfsCreatedAt).Hours() > 12 {
defsch.FixedScheduler.AgreeOrRefuseRefund(ctx, v.AfsOrderID, v.VendorID, model.AfsTypePartRefund, "超时系统同意")
}
}
}
func RefreshRealMobile(ctx *jxcontext.Context, vendorID int, fromTime, toTime time.Time, isAsync, isContinueWhenError bool) (hint string, err error) {
globals.SugarLogger.Debug("RefreshRealMobile")
handler := partner.GetPurchasePlatformFromVendorID(vendorID)
if handler == nil {
return "", fmt.Errorf("不合法的vendorID:%d", vendorID)
}
sql := `
SELECT *
FROM goods_order
WHERE vendor_id = ? AND consignee_mobile2 = ''
`
sqlParams := []interface{}{
vendorID,
}
if !utils.IsTimeZero(fromTime) {
sql += " AND order_created_at >= ?"
sqlParams = append(sqlParams, fromTime)
}
if !utils.IsTimeZero(toTime) {
sql += " AND order_created_at <= ?"
sqlParams = append(sqlParams, toTime)
}
var orderList []*model.GoodsOrder
db := dao.GetDB()
if err = dao.GetRows(db, &orderList, sql, sqlParams...); err == nil && len(orderList) > 0 {
task := tasksch.NewParallelTask("misc RefreshRealMobile", tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError), ctx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
order := batchItemList[0].(*model.GoodsOrder)
mobile, err2 := handler.GetOrderRealMobile(ctx, order)
if err = err2; err == nil {
//mobile = jxutils.FormalizeMobile(mobile)
//if jxutils.IsStringLikeMobile(mobile) && strings.Index(order.ConsigneeMobile, mobile) == -1 {
order.ConsigneeMobile2 = mobile
_, err = dao.UpdateEntity(db, order, "ConsigneeMobile2")
//}
} else {
globals.SugarLogger.Infof("RefreshRealMobile orderID:%s failed with error:%v", order.VendorOrderID, err)
}
return nil, err
}, orderList)
tasksch.HandleTask(task, nil, true).Run()
hint = task.ID
if !isAsync {
_, err = task.GetResult(0)
}
}
return hint, err
}
// 按时间序列循环

View File

@@ -1,396 +0,0 @@
package misc
import (
"strings"
"sync"
"time"
"git.rosy.net.cn/baseapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxstore/cms"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/business/partner/putils"
"git.rosy.net.cn/jx-callback/globals"
)
const (
enableScheduleRefreshStore = true
taskParallelCount = 4
specialSkuNameKeyWord = "温馨提示"
startOpStoreStockNumber = 0
endOpStoreStockNumber = model.MaxStoreSkuStockQty
)
var (
isDaemonRunning = false
vendorList = map[int]bool{
model.VendorIDMTWM: true,
model.VendorIDEBAI: true,
}
storeListQueueData = map[bool]*StoreListQueueData{
true: &StoreListQueueData{},
false: &StoreListQueueData{},
}
// vendorStoreRefreshTimeList = map[int][]string {
// model.VendorIDMTWM: []string {
// //start and end time for JXGY
// "22:00:00",
// "00:00:00",
// //start and end time for JXCS
// "22:10:00",
// "00:10:00",
// },
// model.VendorIDEBAI: []string {
// "22:20:00",
// "06:00:00",
// "22:30:00",
// "06:10:00",
// },
// }
// vendorStartEndStoreTime = map[int][]int16 {
// model.VendorIDMTWM: []int16 {
// int16(2200),//start time
// int16(2355),//end time
// },
// model.VendorIDEBAI: []int16 {
// int16(5),
// int16(2355),
// },
// }
)
type StoreListQueueData struct {
waitQueue []*cms.StoreExt
processQueue []*cms.StoreExt
locker sync.RWMutex
}
func (s *StoreListQueueData) GetProcessQueue() (outQueue []*cms.StoreExt) {
s.locker.RLock()
defer s.locker.RUnlock()
outQueue = append(outQueue, s.processQueue...)
return outQueue
}
func (s *StoreListQueueData) InsertToWaitQueue(storeInfo *cms.StoreExt) {
s.locker.Lock()
defer s.locker.Unlock()
s.waitQueue = append(s.waitQueue, storeInfo)
}
func (s *StoreListQueueData) ClearProcessQueue() {
s.locker.Lock()
defer s.locker.Unlock()
if len(s.processQueue) > 0 {
s.processQueue = []*cms.StoreExt{}
}
}
func (s *StoreListQueueData) TransferWaitQueueToProcessQueue() {
s.locker.Lock()
defer s.locker.Unlock()
if len(s.processQueue) == 0 && len(s.waitQueue) > 0 {
for _, value := range s.waitQueue {
s.processQueue = append(s.processQueue, value)
}
s.waitQueue = []*cms.StoreExt{}
}
}
func AddOrDelExtraStoreOptime(ctx *jxcontext.Context, vendorID int, vendorOrgCode string, storeID int, vendorStoreID string, storeInfo *model.Store, startOpStoreTime, endOpStoreTime int16, needAddTime bool) bool {
opTimeList := storeInfo.GetOpTimeList()
if needAddTime {
opTimeList = []int16{startOpStoreTime, endOpStoreTime}
}
handler := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.IStoreHandler)
return handler.UpdateStoreOpTime(ctx, vendorOrgCode, storeID, vendorStoreID, opTimeList) == nil
}
func GetStockValue(isStart bool) int {
if isStart {
return startOpStoreStockNumber
} else {
return endOpStoreStockNumber
}
}
// func GetOpStoreTime(vendorID int) (startTime, endTime int16) {
// startTime = vendorStartEndStoreTime[vendorID][0]
// endTime = vendorStartEndStoreTime[vendorID][1]
// return startTime, endTime
// }
func IsSpecialSku(name string) bool {
return strings.Contains(name, specialSkuNameKeyWord)
}
func SetSkuStock(isStart bool, storeSkuNameList []*partner.SkuNameInfo) {
for _, skuNameInfo := range storeSkuNameList {
for _, skuInfo := range skuNameInfo.SkuList {
if IsSpecialSku(skuNameInfo.Name) || IsSpecialSku(skuInfo.SkuName) {
skuInfo.Stock = endOpStoreStockNumber
} else {
skuInfo.Stock = GetStockValue(isStart)
}
}
}
}
func SetSpecialSkuStatus(ctx *jxcontext.Context, vendorID int, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuNameList []*partner.SkuNameInfo) {
singleStoreHandler := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.ISingleStoreStoreSkuHandler)
for _, skuNameInfo := range storeSkuNameList {
for _, skuInfo := range skuNameInfo.SkuList {
if IsSpecialSku(skuNameInfo.Name) || IsSpecialSku(skuInfo.SkuName) {
storeSkuList := []*partner.StoreSkuInfo{&skuInfo.StoreSkuInfo}
singleStoreHandler.UpdateStoreSkusStatus(ctx, vendorOrgCode, storeID, vendorStoreID, storeSkuList, model.SkuStatusNormal)
}
}
}
}
func GetFilterStoreSkuList(storeSkuList []*partner.StoreSkuInfo) (storeSkuListOut []*partner.StoreSkuInfo) {
for _, value := range storeSkuList {
if value.SkuID != 0 {
storeSkuListOut = append(storeSkuListOut, value)
}
}
return storeSkuListOut
}
func GetStoreList(ctx *jxcontext.Context) (storeList []*cms.StoreExt, err error) {
storeInfo, err := cms.GetStores(ctx, "", map[string]interface{}{}, 0, -1, utils.DefaultTimeValue, utils.DefaultTimeValue, 0, 0)
storeList = storeInfo.Stores
return storeList, err
}
func GetFilterStoreList(storeList []*cms.StoreExt, vendorMap, storeIDMap map[int]bool) (outStoreList []*cms.StoreExt) {
for _, storeInfo := range storeList {
storeID := storeInfo.ID
//filter for storeID
if len(storeIDMap) > 0 {
if _, ok := storeIDMap[storeID]; !ok {
continue
}
}
for _, vendorStoreInfo := range storeInfo.StoreMaps {
vendorID := vendorStoreInfo.VendorID
//filter for vendorID
if len(vendorMap) > 0 {
if _, ok := vendorMap[vendorID]; !ok {
continue
}
}
if _, ok := vendorList[vendorID]; !ok {
continue
}
temp := *storeInfo
newStoreInfo := &temp
newStoreInfo.StoreMaps = []*model.StoreMap{vendorStoreInfo}
outStoreList = append(outStoreList, newStoreInfo)
}
}
return outStoreList
}
func StartOrEndOpStore(ctx *jxcontext.Context, isStart bool, vendorIDList []int, storeIDList []int, startTime, endTime int16, isAsync, isContinueWhenError bool) (retVal interface{}, err error) {
storeList, err := GetStoreList(ctx)
vendorMap := make(map[int]bool)
for _, vendorID := range vendorIDList {
vendorMap[vendorID] = true
}
storeIDMap := make(map[int]bool)
for _, storeID := range storeIDList {
storeIDMap[storeID] = true
}
storeList = GetFilterStoreList(storeList, vendorMap, storeIDMap)
return StartOrEndOpStoreEx(ctx, isStart, startTime, endTime, isAsync, isContinueWhenError, storeList)
}
func StartOrEndOpStoreEx(ctx *jxcontext.Context, isStart bool, startTime, endTime int16, isAsync, isContinueWhenError bool, storeList []*cms.StoreExt) (retVal interface{}, err error) {
startProcessTime := time.Now().Unix()
baseapi.SugarLogger.Debugf("StartOrEndOpStore start time: %v", time.Now())
if len(storeList) > 0 {
taskFunc := func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
storeListValue := batchItemList[0].(*cms.StoreExt)
storeID := storeListValue.ID
for _, vendorListValue := range storeListValue.StoreMaps {
vendorID := vendorListValue.VendorID
startOpStoreTime := vendorListValue.FakeOpenStart
endOpStoreTime := vendorListValue.FakeOpenStop
//startOpStoreTime, endOpStoreTime := GetOpStoreTime(vendorID)
if startTime != 0 && endTime != 0 {
startOpStoreTime = startTime
endOpStoreTime = endTime
baseapi.SugarLogger.Debugf("StartOrEndOpStore SetStoreOptime:%d do:%d", startTime, endTime)
}
if isStart && (startOpStoreTime == 0 || endOpStoreTime == 0) {
continue
}
vendorStoreID := vendorListValue.VendorStoreID
baseapi.SugarLogger.Debugf("StartOrEndOpStore storeID:%d vendorID:%d vendorStoreID:%s", storeID, vendorID, vendorStoreID)
singleStoreHandler := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.ISingleStoreStoreSkuHandler)
storeSkuNameList, err := singleStoreHandler.GetStoreSkusFullInfo(ctx, task, storeID, vendorStoreID, nil)
if err != nil {
baseapi.SugarLogger.Errorf("StartOrEndOpStore GetStoreSkusFullInfo error:%v storeID:%d vendorID:%d vendorStoreID:%s", err, storeID, vendorID, vendorStoreID)
} else {
SetSkuStock(isStart, storeSkuNameList)
SetSpecialSkuStatus(ctx, vendorID, vendorListValue.VendorOrgCode, storeID, vendorStoreID, storeSkuNameList)
storeSkuList := putils.StoreSkuFullList2Bare(storeSkuNameList)
if vendorID == model.VendorIDMTWM {
storeSkuList = GetFilterStoreSkuList(storeSkuList)
}
if len(storeSkuList) > 0 {
if !isStart {
AddOrDelExtraStoreOptime(ctx, vendorID, vendorListValue.VendorOrgCode, storeID, vendorStoreID, &storeListValue.Store, startOpStoreTime, endOpStoreTime, false)
}
_, err = putils.FreeBatchStoreSkuInfo("更新门店商品库存", func(task tasksch.ITask, batchedStoreSkuList []*partner.StoreSkuInfo) (result interface{}, successCount int, err error) {
_, err = singleStoreHandler.UpdateStoreSkusStock(ctx, vendorListValue.VendorOrgCode, storeID, vendorStoreID, batchedStoreSkuList)
return nil, 0, err
}, ctx, task, storeSkuList, singleStoreHandler.GetStoreSkusBatchSize(partner.FuncUpdateStoreSkusStock), true)
if isStart {
AddOrDelExtraStoreOptime(ctx, vendorID, vendorListValue.VendorOrgCode, storeID, vendorStoreID, &storeListValue.Store, startOpStoreTime, endOpStoreTime, true)
}
}
}
}
return retVal, err
}
taskName := ""
if isStart {
taskName = "开启平台商店的额外营业时间"
} else {
taskName = "结束平台商店的额外营业时间"
}
task := tasksch.NewParallelTask(taskName, tasksch.NewParallelConfig().SetParallelCount(taskParallelCount), ctx, taskFunc, storeList)
tasksch.HandleTask(task, nil, true).Run()
if isAsync {
retVal = task.ID
} else {
_, err = task.GetResult(0)
if err != nil {
baseapi.SugarLogger.Debugf("StartOrEndOpStore tasksch error:%v", err)
}
retVal = "1"
}
}
endProcessTime := time.Now().Unix()
diff := endProcessTime - startProcessTime
baseapi.SugarLogger.Debugf("StartOrEndOpStore end time: %v", time.Now())
baseapi.SugarLogger.Debugf("StartOrEndOpStore cost time: %d sec", diff)
return retVal, err
}
func IsJXCS() bool {
return globals.IsMainProductEnv()
}
// func GetVendorStoreRefreshTime(vendorID int) (startTimeList, stopTimeList []string) {
// isJXCS := globals.IsMainProductEnv()
// refreshTimeList := vendorStoreRefreshTimeList[vendorID]
// if isJXCS {
// startTimeList = []string{refreshTimeList[2]}
// stopTimeList = []string{refreshTimeList[3]}
// } else {
// startTimeList = []string{refreshTimeList[0]}
// stopTimeList = []string{refreshTimeList[1]}
// }
// return startTimeList, stopTimeList
// }
// func RefreshStore(vendorID int) {
// ctx := jxcontext.AdminCtx
// startTimeList, stopTimeList := GetVendorStoreRefreshTime(vendorID)
// vendorIDList := []int{vendorID}
// storeIDList := []int{}
// ScheduleTimerFunc("StartOpStore", func() {
// if !IsImportantTaskRunning(TaskNameSyncStoreSku) {
// StartOrEndOpStore(ctx, true, vendorIDList, storeIDList, 0, 0, false, true)
// }
// }, startTimeList)
// ScheduleTimerFunc("EndOpStore", func() {
// if !IsImportantTaskRunning(TaskNameSyncStoreSku) {
// StartOrEndOpStore(ctx, false, vendorIDList, storeIDList, 0, 0, false, true)
// }
// }, stopTimeList)
// }
func InitEx() {
// for index, value := range vendorList {
// if value {
// RefreshStore(index)
// }
// }
if enableScheduleRefreshStore && IsJXCS() {
ctx := jxcontext.AdminCtx
storeList, err := GetStoreList(ctx)
storeList = GetFilterStoreList(storeList, map[int]bool{}, map[int]bool{})
if err == nil {
for _, storeInfo := range storeList {
for _, vendorStoreInfo := range storeInfo.StoreMaps {
startOpStoreTime := vendorStoreInfo.FakeOpenStart
endOpStoreTime := vendorStoreInfo.FakeOpenStop
if startOpStoreTime == 0 || endOpStoreTime == 0 {
continue
}
startTime := jxutils.OperationTime2StrWithSecond(startOpStoreTime)
ScheduleTimerFuncOnce("StartOpStore", func(param interface{}) {
if !IsImportantTaskRunning(TaskNameSyncStoreSku) {
storeInfo := param.(*cms.StoreExt)
storeListQueueData[true].InsertToWaitQueue(storeInfo)
}
}, startTime, storeInfo)
stopTime := jxutils.OperationTime2StrWithSecond(endOpStoreTime)
ScheduleTimerFuncOnce("EndOpStore", func(param interface{}) {
storeInfo := param.(*cms.StoreExt)
storeListQueueData[false].InsertToWaitQueue(storeInfo)
}, stopTime, storeInfo)
}
}
if !isDaemonRunning {
isDaemonRunning = true
taskSeqFunc := func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
switch step {
case 0:
periodlyFunc := func() {
for isStart, value := range storeListQueueData {
storeList := value.GetProcessQueue()
if len(storeList) > 0 {
StartOrEndOpStoreEx(ctx, isStart, 0, 0, false, true, storeList)
}
}
for _, value := range storeListQueueData {
value.ClearProcessQueue()
value.TransferWaitQueueToProcessQueue()
}
}
PeriodlyCall(60*time.Second, periodlyFunc)
}
return result, err
}
taskSeq := tasksch.NewSeqTask("启动监听-定时刷新平台商店的额外营业时间", ctx, taskSeqFunc, 1)
tasksch.HandleTask(taskSeq, nil, true).Run()
}
}
}
}
func PeriodlyCall(d time.Duration, handler func()) {
ticker := time.NewTicker(d)
for _ = range ticker.C {
handler()
}
}

View File

@@ -1,11 +0,0 @@
package misc
import (
"testing"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
)
func TestStartOrEndOpStore(t *testing.T) {
StartOrEndOpStore(jxcontext.AdminCtx, true, nil, nil, 0, 0, false, true)
}

View File

@@ -1,509 +0,0 @@
package misc
import (
"fmt"
"math"
"time"
"git.rosy.net.cn/baseapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxstore/cms"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/jxutils/weixinmsg"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/globals/refutil"
)
const (
EnableCheckStoreAlert = true
EnableSendStoreAlert = true
IncludeToday = true
CheckStoreAlertOneMonthDayNum = 30
CheckStoreAlertOneDayNum = 1
CheckStoreAlertOneWeekDayNum = 7
MonthCheckOnWeekDay = 1
AlertTypePickTimeOrderDaDa = 0
AlertTypeBadCommentOrder = 1
AlertTypeAbsentGoodsOrder = 2
AlertTypeStandardFinishTimeOrderSelfDelivery = 3
AlertTypeStandardPickUpTimeOrderDaDa = 4
ColorRed = "red"
ColorYellow = "yellow"
ColorUnknown = "unknown"
AlertLevelExtraRed = 1
AlertLevelRed = 2
AlertLevelYellow = 3
OneDayName = "单日"
OneWeekDayName = "七日"
OneMonthDayName = "三十日"
YellowAlertInfo = "您的店铺-%s由于%s%s%s%d%%,可能会被系统下线,请及时补救。"
RedAlertInfo = "您的店铺-%s由于%s%s%s%d%%,会被系统下线,需要马上补救。"
ExtraRedAlertInfo = "您的店铺-%s由于%s%s%s%d%%,会被系统下线,需要马上补救。"
NoOrderAlertInfo = "您的店铺-%s由于近%s无订单会被系统下线需要马上补救。"
RiskOrderAlertInfo = "您的店铺-%s可能有虚假定单定单号为:%s可能会被罚款请及时与运营联系"
)
var (
checkStoreAlertTimeList = []string{
"18:30:00",
}
AlertTypeNameMap = map[int]string{
AlertTypePickTimeOrderDaDa: "拣货履约率(达达)",
AlertTypeBadCommentOrder: "差评率",
AlertTypeAbsentGoodsOrder: "缺货率",
AlertTypeStandardFinishTimeOrderSelfDelivery: "按时履约率(商家自送)",
AlertTypeStandardPickUpTimeOrderDaDa: "10分钟取货完成率(达达)",
}
AlertTypeExtraNameMap = map[int]string{
AlertTypePickTimeOrderDaDa: "拣货超时订单(达达)",
AlertTypeBadCommentOrder: "差评订单",
AlertTypeAbsentGoodsOrder: "缺货订单",
}
storeAlertDataWrapper StoreAlertDataWrapper
)
type StoreAlertDataWrapper struct {
storeAlertList map[int]*model.StoreAlert
}
func (s *StoreAlertDataWrapper) InitData() {
s.storeAlertList = make(map[int]*model.StoreAlert)
}
func (s *StoreAlertDataWrapper) ClearData() {
s.storeAlertList = nil
}
func (s *StoreAlertDataWrapper) IsStatusField(valueName string) bool {
return valueName == model.FieldYellowStatus || valueName == model.FieldRedStatus || valueName == model.FieldExtraRedStatus
}
func (s *StoreAlertDataWrapper) SetData(storeID int, valueName string, value int) {
data := s.storeAlertList[storeID]
if data == nil {
data = &model.StoreAlert{}
data.StoreID = storeID
data.AlertDate = utils.GetCurDate()
s.storeAlertList[storeID] = data
}
if s.IsStatusField(valueName) {
srcFieldValue := refutil.GetObjFieldByName(data, valueName).(int)
value |= srcFieldValue
}
refutil.SetObjFieldByName(data, valueName, value)
}
func (s StoreAlertDataWrapper) InsertStoreAlertList() {
for _, value := range s.storeAlertList {
dao.InsertStoreAlert(value)
}
}
func ConvertListToMap(listData []*model.StoreCount) (mapData map[int]int) {
mapData = make(map[int]int)
for _, value := range listData {
mapData[value.StoreID] = value.Count
}
return mapData
}
func ConvertListToMapEx(listData []*model.StoreOrder) (mapData map[int][]string) {
mapData = make(map[int][]string)
for _, value := range listData {
if mapData[value.StoreID] == nil {
mapData[value.StoreID] = []string{}
}
mapData[value.StoreID] = append(mapData[value.StoreID], value.VendorOrderID)
}
return mapData
}
func GetAlertInfo(dayNum, alertLevel int, storeName string, alertType int, logicCondition string, value int) (info string) {
if dayNum == CheckStoreAlertOneDayNum {
if alertLevel == AlertLevelExtraRed {
info = fmt.Sprintf(ExtraRedAlertInfo, storeName, OneDayName, AlertTypeExtraNameMap[alertType], logicCondition, value)
} else if alertLevel == AlertLevelRed {
info = fmt.Sprintf(RedAlertInfo, storeName, OneDayName, AlertTypeNameMap[alertType], logicCondition, value)
} else if alertLevel == AlertLevelYellow {
info = fmt.Sprintf(YellowAlertInfo, storeName, OneDayName, AlertTypeNameMap[alertType], logicCondition, value)
}
} else if dayNum == CheckStoreAlertOneWeekDayNum {
if alertLevel == AlertLevelExtraRed {
info = fmt.Sprintf(ExtraRedAlertInfo, storeName, OneWeekDayName, AlertTypeExtraNameMap[alertType], logicCondition, value)
} else if alertLevel == AlertLevelRed {
info = fmt.Sprintf(RedAlertInfo, storeName, OneWeekDayName, AlertTypeNameMap[alertType], logicCondition, value)
} else if alertLevel == AlertLevelYellow {
info = fmt.Sprintf(YellowAlertInfo, storeName, OneWeekDayName, AlertTypeNameMap[alertType], logicCondition, value)
}
} else if dayNum == CheckStoreAlertOneMonthDayNum {
info = fmt.Sprintf(NoOrderAlertInfo, storeName, OneMonthDayName)
}
return info
}
func CheckAlert(alertType int, dayNum int, ratio int, count int) (alertLevel int, logicCondtion string, outValue int) {
yellowRatio := -1
redRatio := -1
extraCount := -1
conditionLessEqual := false
switch alertType {
case AlertTypePickTimeOrderDaDa:
if dayNum == CheckStoreAlertOneDayNum {
redRatio = 0
} else if dayNum == CheckStoreAlertOneWeekDayNum {
yellowRatio = 70
redRatio = 50
extraCount = 5
}
conditionLessEqual = true
case AlertTypeBadCommentOrder:
if dayNum == CheckStoreAlertOneDayNum {
redRatio = 100
} else if dayNum == CheckStoreAlertOneWeekDayNum {
yellowRatio = 1
redRatio = 3
extraCount = 5
}
conditionLessEqual = false
case AlertTypeAbsentGoodsOrder:
if dayNum == CheckStoreAlertOneDayNum {
redRatio = 100
} else if dayNum == CheckStoreAlertOneWeekDayNum {
yellowRatio = 3
redRatio = 5
extraCount = 5
}
conditionLessEqual = false
case AlertTypeStandardFinishTimeOrderSelfDelivery:
yellowRatio = 85
redRatio = 70
conditionLessEqual = true
case AlertTypeStandardPickUpTimeOrderDaDa:
yellowRatio = 85
redRatio = 70
conditionLessEqual = true
}
if conditionLessEqual {
logicCondtion = "<="
if extraCount != -1 && count >= extraCount {
alertLevel = AlertLevelExtraRed
outValue = extraCount
} else if redRatio != -1 && ratio <= redRatio {
alertLevel = AlertLevelRed
outValue = redRatio
} else if yellowRatio != -1 && ratio <= yellowRatio {
alertLevel = AlertLevelYellow
outValue = yellowRatio
}
} else {
logicCondtion = ">="
if extraCount != -1 && count >= extraCount {
alertLevel = AlertLevelExtraRed
outValue = extraCount
} else if redRatio != -1 && ratio >= redRatio {
alertLevel = AlertLevelRed
outValue = redRatio
} else if yellowRatio != -1 && ratio >= yellowRatio {
alertLevel = AlertLevelYellow
outValue = yellowRatio
}
}
return alertLevel, logicCondtion, outValue
}
func SendAlertInfo(storeID int, storeName, alertInfo string) {
if EnableSendStoreAlert {
baseapi.SugarLogger.Debugf("SendAlertInfo: %d, %s", storeID, alertInfo)
weixinmsg.NotifyStoreAlertMessage(storeID, storeName, "门店警告", alertInfo)
}
}
func GetFieldNameByAlertType(alertType, dayNum int) (fieldName string, fieldFlag int) {
switch alertType {
case AlertTypePickTimeOrderDaDa:
if dayNum == CheckStoreAlertOneDayNum {
fieldName = model.FieldPickTimeDaDa
fieldFlag = model.FlagPickTimeDaDa
} else if dayNum == CheckStoreAlertOneWeekDayNum {
fieldName = model.FieldPickTimeDaDaOneWeek
fieldFlag = model.FlagPickTimeDaDaOneWeek
}
case AlertTypeBadCommentOrder:
if dayNum == CheckStoreAlertOneDayNum {
fieldName = model.FieldBadComment
fieldFlag = model.FlagBadComment
} else if dayNum == CheckStoreAlertOneWeekDayNum {
fieldName = model.FieldBadCommentOneWeek
fieldFlag = model.FlagBadCommentOneWeek
}
case AlertTypeAbsentGoodsOrder:
if dayNum == CheckStoreAlertOneDayNum {
fieldName = model.FieldAbsentGoods
fieldFlag = model.FlagAbsentGoods
} else if dayNum == CheckStoreAlertOneWeekDayNum {
fieldName = model.FieldAbsentGoodsOneWeek
fieldFlag = model.FlagAbsentGoodsOneWeek
}
case AlertTypeStandardFinishTimeOrderSelfDelivery:
fieldName = model.FieldStandardFinishTimeSelfDelivery
fieldFlag = model.FlagStandardFinishTimeSelfDelivery
case AlertTypeStandardPickUpTimeOrderDaDa:
fieldName = model.FieldStandardPickUpTimeDaDa
fieldFlag = model.FlagStandardPickUpTimeDaDa
}
return fieldName, fieldFlag
}
func SendAlertInfoWrapper(storeID int, storeName string, dayNum, alertType, count, totalCount int) {
if totalCount > 0 {
ratio := int(math.Round(float64(count) * 100 / float64(totalCount)))
alertLevel, logicCondtion, outValue := CheckAlert(alertType, dayNum, ratio, count)
if alertLevel != 0 {
alertInfo := GetAlertInfo(dayNum, alertLevel, storeName, alertType, logicCondtion, outValue)
SendAlertInfo(storeID, storeName, alertInfo)
fieldName, fieldFlag := GetFieldNameByAlertType(alertType, dayNum)
storeAlertDataWrapper.SetData(storeID, fieldName, ratio)
if alertLevel == AlertLevelExtraRed {
storeAlertDataWrapper.SetData(storeID, model.FieldExtraRedStatus, fieldFlag)
} else if alertLevel == AlertLevelRed {
storeAlertDataWrapper.SetData(storeID, model.FieldRedStatus, fieldFlag)
} else if alertLevel == AlertLevelYellow {
storeAlertDataWrapper.SetData(storeID, model.FieldYellowStatus, fieldFlag)
}
}
}
}
func CheckStoreDayAlert(storeList []*cms.StoreExt, dayNum int) {
db := dao.GetDB()
//拣货履约订单(达达)
pickTimeOrderCountDaDaList, _ := dao.GetStandardPickTimeOrderCountByDaDa(db, dayNum, IncludeToday)
pickTimeOrderCountDaDaMapData := ConvertListToMap(pickTimeOrderCountDaDaList)
//完成订单(达达)
finishOrderCountDaDaList, _ := dao.GetFinishOrderCountByDaDa(db, dayNum, IncludeToday)
finishOrderCountDaDaMapData := ConvertListToMap(finishOrderCountDaDaList)
//差评订单
badCommentOrderCountList, _ := dao.GetBadCommentOrderCountByDayNum(db, dayNum, IncludeToday)
badCommentOrderCountMapData := ConvertListToMap(badCommentOrderCountList)
//缺货订单
absentGoodsOrderCountList, _ := dao.GetAbsentGoodsOrderCountByDayNum(db, dayNum, IncludeToday)
absentGoodsOrderCountMapData := ConvertListToMap(absentGoodsOrderCountList)
//完成订单
finishOrderCountList, _ := dao.GetFinishOrderCountByDayNum(db, dayNum, IncludeToday)
finishOrderCountMapData := ConvertListToMap(finishOrderCountList)
var standardFinishTimeOrderCountSelfDeliveryList []*model.StoreCount
var standardFinishTimeOrderCountSelfDeliveryMapData map[int]int
var finishOrderCountSelfDeliveryList []*model.StoreCount
var finishOrderCountSelfDeliveryMapData map[int]int
var standardPickUpTimeOrderCountDaDaList []*model.StoreCount
var standardPickUpTimeOrderCountDaDaMapData map[int]int
isOneWeekDay := dayNum == CheckStoreAlertOneWeekDayNum
if isOneWeekDay {
//按时履约订单(商家自送)
standardFinishTimeOrderCountSelfDeliveryList, _ = dao.GetStandardFinishTimeOrderCountBySelfDelivery(db, dayNum, IncludeToday)
standardFinishTimeOrderCountSelfDeliveryMapData = ConvertListToMap(standardFinishTimeOrderCountSelfDeliveryList)
//完成订单(商家自送)
finishOrderCountSelfDeliveryList, _ = dao.GetFinishOrderCountBySelfDelivery(db, dayNum, IncludeToday)
finishOrderCountSelfDeliveryMapData = ConvertListToMap(finishOrderCountSelfDeliveryList)
//10分钟取货完成订单(达达)
standardPickUpTimeOrderCountDaDaList, _ = dao.GetStandardPickUpTimeOrderCountByDaDa(db, dayNum, IncludeToday)
standardPickUpTimeOrderCountDaDaMapData = ConvertListToMap(standardPickUpTimeOrderCountDaDaList)
}
for _, storeInfo := range storeList {
storeID := storeInfo.ID
storeName := storeInfo.Name
count := pickTimeOrderCountDaDaMapData[storeID]
totalCount := finishOrderCountDaDaMapData[storeID]
SendAlertInfoWrapper(storeID, storeName, dayNum, AlertTypePickTimeOrderDaDa, count, totalCount)
count = badCommentOrderCountMapData[storeID]
totalCount = finishOrderCountMapData[storeID]
SendAlertInfoWrapper(storeID, storeName, dayNum, AlertTypeBadCommentOrder, count, totalCount)
count = absentGoodsOrderCountMapData[storeID]
SendAlertInfoWrapper(storeID, storeName, dayNum, AlertTypeAbsentGoodsOrder, count, totalCount)
if isOneWeekDay {
count = standardFinishTimeOrderCountSelfDeliveryMapData[storeID]
totalCount = finishOrderCountSelfDeliveryMapData[storeID]
SendAlertInfoWrapper(storeID, storeName, dayNum, AlertTypeStandardFinishTimeOrderSelfDelivery, count, totalCount)
count = standardPickUpTimeOrderCountDaDaMapData[storeID]
totalCount = finishOrderCountDaDaMapData[storeID]
SendAlertInfoWrapper(storeID, storeName, dayNum, AlertTypeStandardPickUpTimeOrderDaDa, count, totalCount)
}
}
}
func CheckStoreMonthAlert(storeList []*cms.StoreExt) {
db := dao.GetDB()
storeCountList, _ := dao.GetFinishOrderCountByDayNum(db, CheckStoreAlertOneMonthDayNum, IncludeToday)
storeCountMapData := make(map[int]int)
for _, value := range storeCountList {
storeCountMapData[value.StoreID] = value.Count
}
for _, storeInfo := range storeList {
storeID := storeInfo.ID
storeName := storeInfo.Name
if _, ok := storeCountMapData[storeID]; !ok {
alertInfo := GetAlertInfo(CheckStoreAlertOneMonthDayNum, AlertLevelRed, storeName, -1, "", -1)
SendAlertInfo(storeID, storeName, alertInfo)
storeAlertDataWrapper.SetData(storeID, model.FieldNoOrderInMonth, 1)
storeAlertDataWrapper.SetData(storeID, model.FieldRedStatus, model.FlagNoOrderInMonth)
}
}
}
func CheckStoreRiskOrderAlert(storeList []*cms.StoreExt, dayNum int) {
db := dao.GetDB()
storeOrderList, _ := dao.GetRiskOrderCount(db, dayNum, IncludeToday)
storeOrderMapData := ConvertListToMapEx(storeOrderList)
for _, storeInfo := range storeList {
storeID := storeInfo.ID
storeName := storeInfo.Name
vendorOrderIDList := storeOrderMapData[storeID]
if vendorOrderIDList != nil {
vendorOrderIDStr := ""
for index, vendorOrderID := range vendorOrderIDList {
if index == 0 {
vendorOrderIDStr += vendorOrderID
} else {
vendorOrderIDStr += "," + vendorOrderID
}
}
alertInfo := fmt.Sprintf(RiskOrderAlertInfo, storeName, vendorOrderIDStr)
SendAlertInfo(storeID, storeName, alertInfo)
storeAlertDataWrapper.SetData(storeID, model.FieldRiskOrderCount, len(vendorOrderIDList))
storeAlertDataWrapper.SetData(storeID, model.FieldRedStatus, model.FlagRiskOrderCount)
}
}
}
func GetWeekDay() int {
return int(time.Now().Weekday())
}
func CheckStoreAlert(ctx *jxcontext.Context, storeIDList []int) {
storeAlertDataWrapper.InitData()
storeList, _ := GetStoreList(ctx)
storeIDMap := jxutils.IntList2Map(storeIDList)
storeList = GetFilterStoreListEx(storeList, storeIDMap)
if GetWeekDay() == MonthCheckOnWeekDay {
CheckStoreMonthAlert(storeList)
}
CheckStoreDayAlert(storeList, CheckStoreAlertOneDayNum)
CheckStoreDayAlert(storeList, CheckStoreAlertOneWeekDayNum)
CheckStoreRiskOrderAlert(storeList, CheckStoreAlertOneDayNum)
storeAlertDataWrapper.InsertStoreAlertList()
storeAlertDataWrapper.ClearData()
}
func ScheduleCheckStoreAlert() {
if EnableCheckStoreAlert {
ScheduleTimerFunc("ScheduleCheckStoreAlert", func() {
CheckStoreAlert(jxcontext.AdminCtx, nil)
}, checkStoreAlertTimeList)
}
}
func GetValueColorByStatus(extraRedStatus, redStatus, yellowStatus, flag int) (color string) {
if (extraRedStatus&flag != 0) || (redStatus&flag != 0) {
color = ColorRed
} else if yellowStatus&flag != 0 {
color = ColorYellow
} else {
color = ColorUnknown
}
return color
}
func GetStoreAlertList(storeIDList []int, cityCode int, keyWord string, dateTime time.Time, offset, pageSize int) (storeAlertData model.StoreAlertData, err error) {
db := dao.GetDB()
storeAlertList, err := dao.GetStoreAlertList(db, storeIDList, cityCode, keyWord, dateTime)
if err == nil && len(storeAlertList) > 0 {
offset = jxutils.FormalizePageOffset(offset)
pageSize = jxutils.FormalizePageSize(pageSize)
var pagedStoreAlertList []*model.StoreAlertEx
for i := offset; i < offset+pageSize && i < len(storeAlertList); i++ {
pagedStoreAlertList = append(pagedStoreAlertList, storeAlertList[i])
}
var storeAlertAdvancedList []*model.StoreAlertAdvanced
for _, value := range pagedStoreAlertList {
storeAlertAdvanced := &model.StoreAlertAdvanced{}
storeAlertAdvanced.ID = value.ID
storeAlertAdvanced.CreatedTime = value.CreatedTime
storeAlertAdvanced.AlertDate = value.AlertDate
storeAlertAdvanced.StoreID = value.StoreID
storeAlertAdvanced.StoreName = value.StoreName
storeAlertAdvanced.CityName = value.CityName
storeAlertAdvanced.PickTimeDaDa.Value = fmt.Sprintf("%d%%", value.PickTimeDaDa)
storeAlertAdvanced.PickTimeDaDa.Color = GetValueColorByStatus(value.ExtraRedStatus, value.RedStatus, value.YellowStatus, model.FlagPickTimeDaDa)
storeAlertAdvanced.BadComment.Value = fmt.Sprintf("%d%%", value.BadComment)
storeAlertAdvanced.BadComment.Color = GetValueColorByStatus(value.ExtraRedStatus, value.RedStatus, value.YellowStatus, model.FlagBadComment)
storeAlertAdvanced.AbsentGoods.Value = fmt.Sprintf("%d%%", value.AbsentGoods)
storeAlertAdvanced.AbsentGoods.Color = GetValueColorByStatus(value.ExtraRedStatus, value.RedStatus, value.YellowStatus, model.FlagAbsentGoods)
storeAlertAdvanced.PickTimeDaDaOneWeek.Value = fmt.Sprintf("%d%%", value.PickTimeDaDaOneWeek)
storeAlertAdvanced.PickTimeDaDaOneWeek.Color = GetValueColorByStatus(value.ExtraRedStatus, value.RedStatus, value.YellowStatus, model.FlagPickTimeDaDaOneWeek)
storeAlertAdvanced.BadCommentOneWeek.Value = fmt.Sprintf("%d%%", value.BadCommentOneWeek)
storeAlertAdvanced.BadCommentOneWeek.Color = GetValueColorByStatus(value.ExtraRedStatus, value.RedStatus, value.YellowStatus, model.FlagBadCommentOneWeek)
storeAlertAdvanced.AbsentGoodsOneWeek.Value = fmt.Sprintf("%d%%", value.AbsentGoodsOneWeek)
storeAlertAdvanced.AbsentGoodsOneWeek.Color = GetValueColorByStatus(value.ExtraRedStatus, value.RedStatus, value.YellowStatus, model.FlagAbsentGoodsOneWeek)
storeAlertAdvanced.StandardFinishTimeSelfDelivery.Value = fmt.Sprintf("%d%%", value.StandardFinishTimeSelfDelivery)
storeAlertAdvanced.StandardFinishTimeSelfDelivery.Color = GetValueColorByStatus(value.ExtraRedStatus, value.RedStatus, value.YellowStatus, model.FlagStandardFinishTimeSelfDelivery)
storeAlertAdvanced.StandardPickUpTimeDaDa.Value = fmt.Sprintf("%d%%", value.StandardPickUpTimeDaDa)
storeAlertAdvanced.StandardPickUpTimeDaDa.Color = GetValueColorByStatus(value.ExtraRedStatus, value.RedStatus, value.YellowStatus, model.FlagStandardPickUpTimeDaDa)
if value.NoOrderInMonth == 1 {
storeAlertAdvanced.NoOrderInMonth.Value = "是"
} else {
storeAlertAdvanced.NoOrderInMonth.Value = "否"
}
storeAlertAdvanced.NoOrderInMonth.Color = GetValueColorByStatus(value.ExtraRedStatus, value.RedStatus, value.YellowStatus, model.FlagNoOrderInMonth)
storeAlertAdvanced.RiskOrderCount.Value = utils.Int2Str(value.RiskOrderCount)
storeAlertAdvanced.RiskOrderCount.Color = GetValueColorByStatus(value.ExtraRedStatus, value.RedStatus, value.YellowStatus, model.FlagRiskOrderCount)
storeAlertAdvancedList = append(storeAlertAdvancedList, storeAlertAdvanced)
}
storeAlertData.TotalCount = len(storeAlertList)
storeAlertData.StoreAlertList = storeAlertAdvancedList
}
return storeAlertData, err
}

View File

@@ -1,905 +0,0 @@
package misc
import (
"fmt"
"math"
"reflect"
"sort"
"sync"
"time"
"git.rosy.net.cn/baseapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxstore/cms"
"git.rosy.net.cn/jx-callback/business/jxstore/permission"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/globals/refutil"
)
const (
EnableScheduleScoreStore = true
ParallelCount = 1
GoldMedalScore = 90
SilverMedalScore = 80
BronzeMedalScore = 70
GoldMedalLevel = 1
SilverMedalLevel = 2
BronzeMedalLevel = 3
ItemTotalScore = 10
StoreOpenTimeNormalTime = 12.0 //小时
SaleSkuNormalCount = 1000 //数量
SaleSkuScorePerUnit = float64(ItemTotalScore) / SaleSkuNormalCount //分数
PromotionSkuNormalCount = 20 //数量
AveragePickupTimeNormalTime = 10.0 //分钟
BadCommentOrderNormalRatio = 0.2 //百分比
UnfinishOrderNormalRatio = 1.0 //百分比
AbsentGoodsOrderNormalRatio = 1.0 //百分比
StoreRangeGoodRadius = 2.0 //千米
StoreRangeBadRadius = 1.0 //千米
SaleSkuPriceRatio = 90 //千米
SaleSkuCheckRange = 5.0 //千米
WeekNum = 5 //得到门店近期周的数量
)
var (
scoreStoreTimeList = []string{
"23:00:00",
}
scoreStoreCheckTimeEnd = "23:30:00"
fullVendorList = map[int]bool{
model.VendorIDJD: true,
model.VendorIDMTWM: true,
model.VendorIDEBAI: true,
}
storeScoreFieldName = []string{
model.FieldStoreOpenTime,
model.FieldSaleSkuCount,
model.FieldAveragePickupTime,
model.FieldBadCommentOrder,
model.FieldUnfinishOrder,
model.FieldAbsentGoodsOrder,
model.FieldPromotionSku,
model.FieldFullVendor,
model.FieldStoreRange,
model.FieldSaleSkuPrice,
}
storeScoreDataWrapper StoreScoreDataWrapper
allStoreSkusWrapper AllStoreSkusWrapper
scoreDate time.Time
isScoring bool
)
type AllStoreSkusWrapper struct {
allStoreSkus map[int]map[int]int
locker sync.RWMutex
}
func (a *AllStoreSkusWrapper) InitData() {
a.allStoreSkus = make(map[int]map[int]int)
}
func (a *AllStoreSkusWrapper) ClearData() {
a.allStoreSkus = nil
}
func (a *AllStoreSkusWrapper) SetData(storeID int, skuMapData map[int]int) {
a.locker.Lock()
defer a.locker.Unlock()
a.allStoreSkus[storeID] = skuMapData
}
func (a *AllStoreSkusWrapper) GetData(storeID int) map[int]int {
a.locker.RLock()
defer a.locker.RUnlock()
return a.allStoreSkus[storeID]
}
type StoreScoreDataWrapper struct {
storeScoreData map[int]*model.StoreScore
dailyBadCommentOrderCount map[int]int
dailyUnFinishOrderCount map[int]int
dailyFinishOrderCount map[int]int
dailyAbsentGoodsOrderCount map[int]int
locker sync.RWMutex
}
func (s *StoreScoreDataWrapper) InitData() {
s.storeScoreData = make(map[int]*model.StoreScore)
s.dailyBadCommentOrderCount = make(map[int]int)
s.dailyUnFinishOrderCount = make(map[int]int)
s.dailyFinishOrderCount = make(map[int]int)
s.dailyAbsentGoodsOrderCount = make(map[int]int)
}
func (s *StoreScoreDataWrapper) ClearData() {
s.storeScoreData = nil
s.dailyBadCommentOrderCount = nil
s.dailyUnFinishOrderCount = nil
s.dailyFinishOrderCount = nil
s.dailyAbsentGoodsOrderCount = nil
}
func (s *StoreScoreDataWrapper) SetData(storeID int, valueName string, value int) {
s.locker.Lock()
defer s.locker.Unlock()
data := s.storeScoreData[storeID]
if data == nil {
data = &model.StoreScore{}
data.StoreID = storeID
data.ScoreDate = scoreDate
s.storeScoreData[storeID] = data
}
valueInfo := reflect.ValueOf(data).Elem()
valueInfo.FieldByName(valueName).SetInt(int64(value))
}
func (s *StoreScoreDataWrapper) SetDailyBadCommentOrderCount(storeCountList []*model.StoreCount) {
s.locker.Lock()
defer s.locker.Unlock()
for _, value := range storeCountList {
s.dailyBadCommentOrderCount[value.StoreID] = value.Count
}
}
func (s *StoreScoreDataWrapper) GetDailyBadCommentOrderCount(storeID int) int {
s.locker.RLock()
defer s.locker.RUnlock()
if count, ok := s.dailyBadCommentOrderCount[storeID]; ok {
return count
}
return 0
}
func (s *StoreScoreDataWrapper) SetDailyUnFinishOrderCount(storeCountList []*model.StoreCount) {
for _, value := range storeCountList {
s.dailyUnFinishOrderCount[value.StoreID] = value.Count
}
}
func (s *StoreScoreDataWrapper) GetDailyUnFinishOrderCount(storeID int) int {
s.locker.RLock()
defer s.locker.RUnlock()
if count, ok := s.dailyUnFinishOrderCount[storeID]; ok {
return count
}
return 0
}
func (s *StoreScoreDataWrapper) SetDailyFinishOrderCount(storeCountList []*model.StoreCount) {
for _, value := range storeCountList {
s.dailyFinishOrderCount[value.StoreID] = value.Count
}
}
func (s *StoreScoreDataWrapper) GetDailyFinishOrderCount(storeID int) int {
s.locker.RLock()
defer s.locker.RUnlock()
if count, ok := s.dailyFinishOrderCount[storeID]; ok {
return count
}
return 0
}
func (s *StoreScoreDataWrapper) SetDailyAbsentGoodsOrderCount(storeCountList []*model.StoreCount) {
for _, value := range storeCountList {
s.dailyAbsentGoodsOrderCount[value.StoreID] = value.Count
}
}
func (s *StoreScoreDataWrapper) GetDailyAbsentGoodsOrderCount(storeID int) int {
s.locker.RLock()
defer s.locker.RUnlock()
if count, ok := s.dailyAbsentGoodsOrderCount[storeID]; ok {
return count
}
return 0
}
func (s *StoreScoreDataWrapper) InsertStoreScore() {
for _, value := range s.storeScoreData {
dao.InsertStoreScore(value)
}
}
//得到所有门店的可售商品(优化内存,只存商品的价格)
func GetAllStoreSkus(ctx *jxcontext.Context, parentTask tasksch.ITask, storeList []*cms.StoreExt) {
allStoreSkusWrapper.InitData()
taskFunc := func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
storeInfo := batchItemList[0].(*cms.StoreExt)
storeID := storeInfo.ID
if jxSkuInfoData, err2 := cms.GetStoreSkus(ctx, storeID, []int{}, true, "", true, false, map[string]interface{}{}, 0, -1); jxSkuInfoData != nil {
jxSkuPriceMapData := make(map[int]int)
for _, value := range jxSkuInfoData.SkuNames {
for _, skuInfo := range value.Skus {
saleStatus := jxutils.MergeSkuStatus(skuInfo.SkuStatus, skuInfo.StoreSkuStatus)
if saleStatus == model.SkuStatusNormal {
jxSkuPriceMapData[skuInfo.SkuID] = skuInfo.BindPrice
}
}
}
allStoreSkusWrapper.SetData(storeID, jxSkuPriceMapData)
} else {
globals.SugarLogger.Warnf("store_score.GetAllStoreSkus %d return empty, err:%v", storeID, err2)
}
return retVal, err
}
taskParallel := tasksch.NewParallelTask("得到所有门店商品", tasksch.NewParallelConfig().SetParallelCount(ParallelCount), ctx, taskFunc, storeList)
tasksch.HandleTask(taskParallel, parentTask, true).Run()
taskParallel.GetResult(0)
}
func GetOpenTime(opTimeList []int16) (opTime float64) {
opTime = 0
for index, _ := range opTimeList {
if index%2 == 1 {
endTime := opTimeList[index]
startTime := opTimeList[index-1]
diffHour := float64(endTime/100 - startTime/100)
diffMin := float64(endTime%100-startTime%100) / 60
opTime += diffHour + diffMin
}
}
return opTime
}
//营业时间12小时及以上满分总分10分每少一个小时扣1分
func ScoreStoreOpenTime(storeInfo *cms.StoreExt) {
storeID := storeInfo.ID
storeStatus := storeInfo.Status
isStoreOpen := storeStatus == model.StoreStatusOpened
finalScore := 0
if isStoreOpen {
for _, storeMap := range storeInfo.StoreMaps {
isSyncStoreSku := storeMap.IsSync
vendorStoreStatus := storeMap.Status
isVendorStoreOpen := vendorStoreStatus == model.StoreStatusOpened
opTimeList := storeInfo.GetOpTimeList()
if len(opTimeList) > 0 && isStoreOpen && isVendorStoreOpen && isSyncStoreSku != 0 {
opTime := GetOpenTime(opTimeList)
if opTime >= StoreOpenTimeNormalTime {
finalScore = ItemTotalScore
} else {
decScore := int(math.Round(StoreOpenTimeNormalTime - opTime))
finalScore = ItemTotalScore - decScore
if finalScore < 0 {
finalScore = 0
}
}
}
}
}
storeScoreDataWrapper.SetData(storeID, model.FieldStoreOpenTime, finalScore)
}
//可售商品数量大于1000总分10分按比例扣
func ScoreSaleSkuCount(storeInfo *cms.StoreExt) {
storeID := storeInfo.ID
skusMapData := allStoreSkusWrapper.GetData(storeID)
finalScore := 0
if len(skusMapData) > 0 {
saleSkuCount := len(skusMapData)
finalScore = int(math.Round(float64(saleSkuCount) * SaleSkuScorePerUnit))
if finalScore > ItemTotalScore {
finalScore = ItemTotalScore
}
}
storeScoreDataWrapper.SetData(storeID, model.FieldSaleSkuCount, finalScore)
}
//平均捡货时间小于等于拣货截止时间为10分满分每超出1分钟减1分
func ScoreAveragePickupTime(storeInfo *cms.StoreExt) {
storeID := storeInfo.ID
db := dao.GetDB()
orderList, err := dao.GetDailyFinishOrderList(db, storeID, scoreDate)
orderListCount := len(orderList)
finalScore := 0
if err == nil && orderListCount > 0 {
totalScore := 0
for _, value := range orderList {
statusTime := value.StatusTime.Unix()
pickDeadline := value.PickDeadline.Unix()
if statusTime <= pickDeadline {
totalScore += ItemTotalScore
} else {
decScore := int(math.Round(float64(statusTime-pickDeadline) / 60))
tempScore := ItemTotalScore - decScore
if tempScore < 0 {
tempScore = 0
}
totalScore += tempScore
}
}
finalScore = totalScore / orderListCount
}
storeScoreDataWrapper.SetData(storeID, model.FieldAveragePickupTime, finalScore)
}
//差评订单和完成订单比例小于0.2%,得满分10分每增加0.1%减1分
func ScoreBadCommentOrder(storeInfo *cms.StoreExt) {
storeID := storeInfo.ID
badCommentOrderCount := storeScoreDataWrapper.GetDailyBadCommentOrderCount(storeID)
finishOrderCount := storeScoreDataWrapper.GetDailyFinishOrderCount(storeID)
finalScore := 0
if finishOrderCount > 0 {
badCommentOrderRatio := float64(badCommentOrderCount) * 100 / float64(finishOrderCount)
if badCommentOrderRatio <= BadCommentOrderNormalRatio {
finalScore = ItemTotalScore
} else {
decScore := int(math.Round((badCommentOrderRatio - BadCommentOrderNormalRatio) / 0.1))
finalScore = ItemTotalScore - decScore
if finalScore < 0 {
finalScore = 0
}
}
}
storeScoreDataWrapper.SetData(storeID, model.FieldBadCommentOrder, finalScore)
}
//未完成订单和完成订单比小于1%得满分10分比例每增加5%分数减1
func ScoreUnfinishOrder(storeInfo *cms.StoreExt) {
storeID := storeInfo.ID
unFinishOrderCount := storeScoreDataWrapper.GetDailyUnFinishOrderCount(storeID)
finishOrderCount := storeScoreDataWrapper.GetDailyFinishOrderCount(storeID)
finalScore := 0
if finishOrderCount > 0 {
unfinishOrderRatio := float64(unFinishOrderCount) * 100 / float64(finishOrderCount)
if unfinishOrderRatio <= UnfinishOrderNormalRatio {
finalScore = ItemTotalScore
} else {
decScore := int(math.Round((unfinishOrderRatio - UnfinishOrderNormalRatio) / 5))
finalScore = ItemTotalScore - decScore
if finalScore < 0 {
finalScore = 0
}
}
}
storeScoreDataWrapper.SetData(storeID, model.FieldUnfinishOrder, finalScore)
}
//缺货订单和完成订单比小于1%得10分比例每增加0.1%减1分
func ScoreAbsentGoodsOrder(storeInfo *cms.StoreExt) {
storeID := storeInfo.ID
absentGoodsOrderCount := storeScoreDataWrapper.GetDailyAbsentGoodsOrderCount(storeID)
finishOrderCount := storeScoreDataWrapper.GetDailyFinishOrderCount(storeID)
finalScore := 0
if finishOrderCount > 0 {
absentGoodsOrderRatio := float64(absentGoodsOrderCount) * 100 / float64(finishOrderCount)
if absentGoodsOrderRatio <= AbsentGoodsOrderNormalRatio {
finalScore = ItemTotalScore
} else {
decScore := int(math.Round((absentGoodsOrderRatio - AbsentGoodsOrderNormalRatio) / 0.1))
finalScore = ItemTotalScore - decScore
if finalScore < 0 {
finalScore = 0
}
}
}
storeScoreDataWrapper.SetData(storeID, model.FieldAbsentGoodsOrder, finalScore)
}
//促销品数量20个以上为满分10分每少2个扣1分
func ScorePromotionSku(storeInfo *cms.StoreExt) {
storeID := storeInfo.ID
db := dao.GetDB()
beginTime := time.Now()
endTime := time.Now()
actStoreSkuList, err := dao.GetEffectiveActStoreSkuInfo(db, -1, nil, model.ActTypeAll, []int{storeID}, nil, beginTime, endTime)
finalScore := 0
if err == nil && len(actStoreSkuList) > 0 {
actStoreSkuMap := make(map[int]int)
for _, value := range actStoreSkuList {
if value.Type != model.ActSkuFake {
actStoreSkuMap[value.SkuID] = 1
}
}
promotionSkuCount := len(actStoreSkuMap)
if promotionSkuCount >= PromotionSkuNormalCount {
finalScore = ItemTotalScore
} else {
decScore := (PromotionSkuNormalCount - promotionSkuCount) / 2
finalScore = ItemTotalScore - decScore
if finalScore < 0 {
finalScore = 0
}
}
}
storeScoreDataWrapper.SetData(storeID, model.FieldPromotionSku, finalScore)
}
//经营全平台满分10分每少一个平台扣2分(一个平台没有得0分)
func ScoreFullVendor(storeInfo *cms.StoreExt) {
fullVendorCount := len(fullVendorList)
finalScore := 0
storeID := storeInfo.ID
storeStatus := storeInfo.Status
isStoreOpen := storeStatus == model.StoreStatusOpened
count := 0
for _, storeMap := range storeInfo.StoreMaps {
isSyncStoreSku := storeMap.IsSync
vendorStoreStatus := storeMap.Status
isVendorStoreOpen := vendorStoreStatus == model.StoreStatusOpened
opTimeList := storeInfo.GetOpTimeList()
if len(opTimeList) > 0 && isStoreOpen && isVendorStoreOpen && isSyncStoreSku != 0 {
count++
}
}
if count > 0 {
if count == fullVendorCount {
finalScore = ItemTotalScore
} else {
decScore := (fullVendorCount - count) * 2
finalScore = ItemTotalScore - decScore
}
}
storeScoreDataWrapper.SetData(storeID, model.FieldFullVendor, finalScore)
}
//经营范围面积大于半径2km的圆得满分10分低于1km得分0
func ScoreStoreRange(storeInfo *cms.StoreExt) {
finalScore := 0
storeID := storeInfo.ID
if storeInfo.DeliveryRangeType == model.DeliveryRangeTypePolygon {
if storeInfo.DeliveryRange != "" {
points := jxutils.CoordinateStr2Points(storeInfo.DeliveryRange)
area := jxutils.CalcPolygonAreaAutonavi(points)
goodArea := math.Pi * StoreRangeGoodRadius * StoreRangeGoodRadius
badArea := math.Pi * StoreRangeBadRadius * StoreRangeBadRadius
if area >= goodArea {
finalScore = ItemTotalScore
} else if area <= badArea {
finalScore = 0
} else {
diff := goodArea - area
ratio := float64(ItemTotalScore) / (goodArea - badArea)
finalScore = ItemTotalScore - int(math.Round(diff*ratio))
}
}
} else if storeInfo.DeliveryRangeType == model.DeliveryRangeTypeRadius {
deliveryRadius := utils.Str2Float64WithDefault(storeInfo.DeliveryRange, 0) / 1000
if deliveryRadius >= StoreRangeGoodRadius {
finalScore = ItemTotalScore
} else if deliveryRadius <= StoreRangeBadRadius {
finalScore = 0
} else {
diff := StoreRangeGoodRadius - deliveryRadius
ratio := float64(ItemTotalScore) / (StoreRangeGoodRadius - StoreRangeBadRadius)
finalScore = ItemTotalScore - int(math.Round(diff*ratio))
}
}
if finalScore < 0 {
globals.SugarLogger.Infof("ScoreStoreRange abnormal finalScore:%d, storeInfo:%s", finalScore, utils.Format4Output(storeInfo, true))
finalScore = 0
} else if finalScore > ItemTotalScore {
globals.SugarLogger.Infof("ScoreStoreRange abnormal finalScore:%d, storeInfo:%s", finalScore, utils.Format4Output(storeInfo, true))
finalScore = ItemTotalScore
}
storeScoreDataWrapper.SetData(storeID, model.FieldStoreRange, finalScore)
}
//得到距离某个门店多少KM内的所有门店信息
func GetRangeStoreList(storeID int, lng, lat, checkRange float64, storeList []*cms.StoreExt) (outStoreList []*cms.StoreExt) {
for _, storeInfo := range storeList {
if storeInfo.ID == storeID {
outStoreList = append(outStoreList, storeInfo)
} else {
distance := jxutils.EarthDistance(lng, lat, storeInfo.FloatLng, storeInfo.FloatLat)
if distance <= checkRange {
outStoreList = append(outStoreList, storeInfo)
}
}
}
return outStoreList
}
//得到给定门店列表里的同一SkuID商品的平均价格
func GetStoreSkusAveragePrice(storeList []*cms.StoreExt) map[int]int {
skusTotalPrice := make(map[int]int)
skusCount := make(map[int]int)
skusAveragePrice := make(map[int]int)
for _, storeInfo := range storeList {
storeID := storeInfo.ID
storeSkuMapData := allStoreSkusWrapper.GetData(storeID)
for skuID, skuPrice := range storeSkuMapData {
skusTotalPrice[skuID] += skuPrice
skusCount[skuID]++
}
}
for id, totalPrice := range skusTotalPrice {
skusAveragePrice[id] = int(math.Round(float64(totalPrice) / float64(skusCount[id])))
}
return skusAveragePrice
}
func GetSkusCountLessEqualAvgPrice(storeID int, skusAveragePrice map[int]int) (count int) {
storeSkuMapData := allStoreSkusWrapper.GetData(storeID)
for skuID, skuPrice := range storeSkuMapData {
skuAvgPrice := skusAveragePrice[skuID]
if skuPrice <= skuAvgPrice {
count++
}
}
return count
}
//可售商品价格在附近5km内门店比较价格低于等于平均值的商品数占90%以上满分10分比例每降低10%减1分100%超标得0分
func ScoreSaleSkuPrice(storeInfo *cms.StoreExt, storeList []*cms.StoreExt) {
finalScore := 0
storeID := storeInfo.ID
totalCount := len(allStoreSkusWrapper.GetData(storeID))
if totalCount > 0 {
rangeStoreList := GetRangeStoreList(storeID, storeInfo.FloatLng, storeInfo.FloatLat, SaleSkuCheckRange, storeList)
skusAveragePrice := GetStoreSkusAveragePrice(rangeStoreList)
count := GetSkusCountLessEqualAvgPrice(storeID, skusAveragePrice)
if count > 0 {
ratio := int(math.Round(float64(count) * 100 / float64(totalCount)))
if ratio >= SaleSkuPriceRatio {
finalScore = ItemTotalScore
} else {
decScore := (SaleSkuPriceRatio - ratio) / 10
finalScore = ItemTotalScore - decScore
if finalScore < 0 {
finalScore = 0
}
}
}
}
storeScoreDataWrapper.SetData(storeID, model.FieldSaleSkuPrice, finalScore)
}
func GetFilterStoreListEx(storeList []*cms.StoreExt, storeIDMap map[int]int) (outStoreList []*cms.StoreExt) {
for _, storeInfo := range storeList {
storeID := storeInfo.ID
if len(storeIDMap) > 0 {
if _, ok := storeIDMap[storeID]; !ok {
continue
}
}
var tempStoreMaps []*model.StoreMap
for _, vendorStoreInfo := range storeInfo.StoreMaps {
vendorID := vendorStoreInfo.VendorID
if _, ok := fullVendorList[vendorID]; !ok {
continue
}
tempStoreMaps = append(tempStoreMaps, vendorStoreInfo)
}
if len(tempStoreMaps) > 0 {
storeInfo.StoreMaps = tempStoreMaps
outStoreList = append(outStoreList, storeInfo)
}
}
return outStoreList
}
func ScoreStore(ctx *jxcontext.Context, storeIDList []int) (retVal interface{}, err error) {
isScoring = true
scoreDate = utils.GetCurDate()
var storeList []*cms.StoreExt
taskCount := 5
taskSeqFunc := func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
switch step {
case 0:
baseapi.SugarLogger.Debugf("ScoreStore step0 begin")
storeScoreDataWrapper.InitData()
storeList, err = GetStoreList(ctx)
storeIDMap := jxutils.IntList2Map(storeIDList)
storeList = GetFilterStoreListEx(storeList, storeIDMap)
baseapi.SugarLogger.Debugf("ScoreStore step0 end")
case 1:
baseapi.SugarLogger.Debugf("ScoreStore step1 begin")
GetAllStoreSkus(ctx, task, storeList)
baseapi.SugarLogger.Debugf("ScoreStore step1 end")
case 2:
baseapi.SugarLogger.Debugf("ScoreStore step2 begin")
db := dao.GetDB()
storeCountList, err := dao.GetDailyBadCommentOrderCount(db, scoreDate)
if err == nil {
storeScoreDataWrapper.SetDailyBadCommentOrderCount(storeCountList)
} else {
baseapi.SugarLogger.Debugf("ScoreStore GetDailyBadCommentOrderCount %v", err)
}
storeCountList, err = dao.GetDailyUnFinishOrderCount(db, scoreDate)
if err == nil {
storeScoreDataWrapper.SetDailyUnFinishOrderCount(storeCountList)
} else {
baseapi.SugarLogger.Debugf("ScoreStore GetDailyUnFinishOrderCount %v", err)
}
storeCountList, err = dao.GetDailyFinishOrderCount(db, scoreDate)
if err == nil {
storeScoreDataWrapper.SetDailyFinishOrderCount(storeCountList)
} else {
baseapi.SugarLogger.Debugf("ScoreStore GetDailyFinishOrderCount %v", err)
}
storeCountList, err = dao.GetDailyAbsentGoodsOrderCount(db, scoreDate)
if err == nil {
storeScoreDataWrapper.SetDailyAbsentGoodsOrderCount(storeCountList)
} else {
baseapi.SugarLogger.Debugf("ScoreStore GetDailyAbsentGoodsOrderCount %v", err)
}
baseapi.SugarLogger.Debugf("ScoreStore step2 end")
case 3:
baseapi.SugarLogger.Debugf("ScoreStore step3 begin")
taskFunc := func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
storeInfo := batchItemList[0].(*cms.StoreExt)
storeID := storeInfo.ID
baseapi.SugarLogger.Debugf("Begin store id:%d", storeID)
ScoreStoreOpenTime(storeInfo)
ScoreSaleSkuCount(storeInfo)
ScoreAveragePickupTime(storeInfo)
ScoreBadCommentOrder(storeInfo)
ScoreUnfinishOrder(storeInfo)
ScoreAbsentGoodsOrder(storeInfo)
ScorePromotionSku(storeInfo)
ScoreFullVendor(storeInfo)
ScoreStoreRange(storeInfo)
ScoreSaleSkuPrice(storeInfo, storeList)
baseapi.SugarLogger.Debugf("End store id:%d", storeID)
return retVal, err
}
taskParallel := tasksch.NewParallelTask("计算门店得分", tasksch.NewParallelConfig().SetParallelCount(ParallelCount), ctx, taskFunc, storeList)
tasksch.HandleTask(taskParallel, task, true).Run()
taskParallel.GetResult(0)
_, err = taskParallel.GetResult(0)
if err != nil {
baseapi.SugarLogger.Debugf("ScoreStore taskParallel error:%v", err)
}
baseapi.SugarLogger.Debugf("ScoreStore step3 end")
case 4:
baseapi.SugarLogger.Debugf("ScoreStore step4 begin")
storeScoreDataWrapper.InsertStoreScore()
storeScoreDataWrapper.ClearData()
allStoreSkusWrapper.ClearData()
baseapi.SugarLogger.Debugf("ScoreStore step4 end")
isScoring = false
}
return result, err
}
taskSeq := tasksch.NewSeqTask("门店评分-序列任务", ctx, taskSeqFunc, taskCount)
tasksch.HandleTask(taskSeq, nil, true).Run()
return retVal, err
}
func ScheduleScoreStore() {
if EnableScheduleScoreStore {
ScheduleTimerFunc("ScheduleScoreStore", func() {
if !isScoring {
ScoreStore(jxcontext.AdminCtx, nil)
}
}, scoreStoreTimeList)
CheckScoreStore()
}
}
func CheckScoreStore() {
if !isScoring {
curTime := time.Now()
checkTimeStr1 := fmt.Sprintf("%s %s", utils.Time2DateStr(curTime), scoreStoreTimeList[0])
checkTime1 := utils.Str2Time(checkTimeStr1)
checkTimeStr2 := fmt.Sprintf("%s %s", utils.Time2DateStr(curTime), scoreStoreCheckTimeEnd)
checkTime2 := utils.Str2Time(checkTimeStr2)
if curTime.Unix() >= checkTime1.Unix() && curTime.Unix() <= checkTime2.Unix() {
db := dao.GetDB()
hasStoreScoreData, err := dao.CheckHasStoreScoreData(db, curTime)
if err == nil && !hasStoreScoreData {
ScoreStore(jxcontext.AdminCtx, nil)
}
}
}
}
func Time2Week(t time.Time) int {
yearDay := t.YearDay()
yearFirstDay := t.AddDate(0, 0, -yearDay+1)
firstDayInWeek := int(yearFirstDay.Weekday())
firstWeekDays := 1
if firstDayInWeek != 0 {
firstWeekDays = 7 - firstDayInWeek + 1
}
var week int
if yearDay <= firstWeekDays {
week = 1
} else {
tempWeek := (float64(yearDay) - float64(firstWeekDays)) / float64(7)
week = int(math.Ceil(tempWeek)) + 1
}
return week
}
func SplitToSingleWeekDataList(storeScoreList []*model.StoreScoreEx) (weekDataList [][]*model.StoreScoreEx) {
singleWeekData := []*model.StoreScoreEx{}
weekIndex := 0
for _, value := range storeScoreList {
if weekIndex == 0 {
weekIndex = Time2Week(value.ScoreDate)
}
if weekIndex == Time2Week(value.ScoreDate) {
singleWeekData = append(singleWeekData, value)
} else {
weekDataList = append(weekDataList, singleWeekData)
singleWeekData = []*model.StoreScoreEx{}
weekIndex = 0
singleWeekData = append(singleWeekData, value)
}
}
if len(singleWeekData) > 0 {
weekDataList = append(weekDataList, singleWeekData)
}
return weekDataList
}
func GetStoreScoreLevel(score int) int {
level := 0
if score >= GoldMedalScore {
level = GoldMedalLevel
} else if score >= SilverMedalScore {
level = SilverMedalLevel
} else if score >= BronzeMedalScore {
level = BronzeMedalLevel
}
return level
}
func GetWeeklyStoreScore(storeID, weekIndexParam int) (outWeeklyStoreScoreDataList []*model.WeeklyStoreScore, err error) {
db := dao.GetDB()
storeScoreList, err := dao.GetWeeklyStoreScoreList(db, storeID, WeekNum)
if err == nil && len(storeScoreList) > 0 {
weeklyStoreScoreDataList := []*model.WeeklyStoreScore{}
weekDataList := SplitToSingleWeekDataList(storeScoreList)
for weekIndex, weekData := range weekDataList {
weeklyData := &model.WeeklyStoreScore{}
weeklyData.ID = weekIndex
weeklyData.ItemTotalScore = ItemTotalScore
weeklyData.StoreID = storeID
weeklyStoreScoreDataList = append(weeklyStoreScoreDataList, weeklyData)
weekDataCount := len(weekData)
for dayIndex, dayData := range weekData {
for _, fieldName := range storeScoreFieldName {
srcFieldValue := refutil.GetObjFieldByName(dayData, fieldName).(int)
destFieldValue := refutil.GetObjFieldByName(weeklyData, fieldName).(int)
refutil.SetObjFieldByName(weeklyData, fieldName, destFieldValue+srcFieldValue)
}
if weekDataCount == 1 {
weeklyData.BeginTime = dayData.ScoreDate
weeklyData.EndTime = dayData.ScoreDate
} else {
if dayIndex == 0 {
weeklyData.EndTime = dayData.ScoreDate
} else if dayIndex == weekDataCount-1 {
weeklyData.BeginTime = dayData.ScoreDate
}
}
weeklyData.StoreName = dayData.StoreName
}
for _, fieldName := range storeScoreFieldName {
destFieldValue := refutil.GetObjFieldByName(weeklyData, fieldName).(int)
refutil.SetObjFieldByName(weeklyData, fieldName, int(math.Round(float64(destFieldValue)/float64(weekDataCount))))
}
for _, fieldName := range storeScoreFieldName {
srcFieldValue := refutil.GetObjFieldByName(weeklyData, fieldName).(int)
destFieldValue := refutil.GetObjFieldByName(weeklyData, model.FieldTotalScore).(int)
refutil.SetObjFieldByName(weeklyData, model.FieldTotalScore, destFieldValue+srcFieldValue)
}
weeklyData.Level = GetStoreScoreLevel(weeklyData.TotalScore)
}
if weekIndexParam == -1 {
outWeeklyStoreScoreDataList = weeklyStoreScoreDataList
} else {
fmt.Println("testss", utils.Format4Output(weeklyStoreScoreDataList, false))
outWeeklyStoreScoreDataList = []*model.WeeklyStoreScore{weeklyStoreScoreDataList[weekIndexParam]}
}
}
return outWeeklyStoreScoreDataList, err
}
func GetStoreTotalScoreList(ctx *jxcontext.Context, storeIDList []int, cityCode int, keyWord string, beginTime, endTime time.Time, isDesc bool, checkScoreLow, checkScoreHigh, offset, pageSize int) (storeTotalScoreEx model.StoreTotalScoreEx, err error) {
db := dao.GetDB()
//权限
if permission.IsRoled(ctx) {
if storeIDsMap, err := permission.GetUserStoresResultMap(ctx.GetUserID()); err == nil {
var storeIDs2 []int
if len(storeIDList) > 0 {
for _, v := range storeIDList {
if storeIDsMap[v] != 0 {
storeIDs2 = append(storeIDs2, v)
}
}
if len(storeIDs2) == 0 {
storeIDs2 = append(storeIDs2, -1)
}
} else {
for k, _ := range storeIDsMap {
storeIDs2 = append(storeIDs2, k)
}
}
storeIDList = nil
storeIDList = storeIDs2
}
}
storeTotalScoreMapData := make(map[int]*model.StoreTotalScore)
storeTotalScoreList, err := dao.GetStoreTotalScoreList(db, storeIDList, cityCode, keyWord, beginTime, endTime)
var filterStoreTotalScoreList []*model.StoreTotalScore
if err == nil && len(storeTotalScoreList) > 0 {
countDayNum := make(map[int]int)
for _, value := range storeTotalScoreList {
storeID := value.StoreID
if storeTotalScoreMapData[storeID] == nil {
storeTotalScore := &model.StoreTotalScore{}
storeTotalScore.StoreID = value.StoreID
storeTotalScore.StoreName = value.StoreName
storeTotalScore.CityName = value.CityName
storeTotalScoreMapData[storeID] = storeTotalScore
}
storeTotalScore := storeTotalScoreMapData[storeID]
storeTotalScore.StoreScore += value.StoreScore
countDayNum[storeID]++
}
for storeID, value := range storeTotalScoreMapData {
value.StoreScore = int(math.Round(float64(value.StoreScore) / float64(countDayNum[storeID])))
needAdd := true
if checkScoreLow > 0 && value.StoreScore < checkScoreLow {
needAdd = false
}
if checkScoreHigh > 0 && value.StoreScore > checkScoreHigh {
needAdd = false
}
if needAdd {
filterStoreTotalScoreList = append(filterStoreTotalScoreList, value)
}
}
if isDesc {
sort.Slice(filterStoreTotalScoreList, func(i, j int) bool {
data1 := filterStoreTotalScoreList[i]
data2 := filterStoreTotalScoreList[j]
if data1.StoreScore == data2.StoreScore {
return data1.StoreID < data2.StoreID
} else {
return data1.StoreScore > data2.StoreScore
}
})
} else {
sort.Slice(filterStoreTotalScoreList, func(i, j int) bool {
data1 := filterStoreTotalScoreList[i]
data2 := filterStoreTotalScoreList[j]
if data1.StoreScore == data2.StoreScore {
return data1.StoreID < data2.StoreID
} else {
return data1.StoreScore < data2.StoreScore
}
})
}
}
offset = jxutils.FormalizePageOffset(offset)
pageSize = jxutils.FormalizePageSize(pageSize)
var pagedStoreTotalScoreList []*model.StoreTotalScore
for i := offset; i < offset+pageSize && i < len(filterStoreTotalScoreList); i++ {
pagedStoreTotalScoreList = append(pagedStoreTotalScoreList, filterStoreTotalScoreList[i])
}
storeTotalScoreEx.TotalCount = len(filterStoreTotalScoreList)
storeTotalScoreEx.StoreTotalScoreList = pagedStoreTotalScoreList
return storeTotalScoreEx, err
}

View File

@@ -1,24 +0,0 @@
package misc
import (
"testing"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/globals/api2"
"git.rosy.net.cn/jx-callback/globals/testinit"
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/ebai"
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/elm"
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/jd"
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/mtwm"
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/weimob/wsc"
)
func init() {
testinit.Init()
api2.Init()
}
func TestScoreStore(t *testing.T) {
ScoreStore(jxcontext.AdminCtx, []int{})
}

View File

@@ -1,176 +0,0 @@
package misc
import (
"errors"
"fmt"
"math"
"sync"
"git.rosy.net.cn/jx-callback/business/jxstore/cms"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
)
const (
DayNum = 30 //请求天数
LimitNum = 100 //最大数据限制
)
func GetStoreSkuSalesInfo(ctx *jxcontext.Context, storeID int) (outStoreSkuSales []*model.StoreSkuSales, err error) {
db := dao.GetDB()
//得到所有门店
storeList, err := GetStoreList(ctx)
if err == nil {
storeList = GetFilterStoreListEx(storeList, nil)
} else {
return nil, err
}
storeMapData := make(map[int]*cms.StoreExt)
for _, value := range storeList {
storeMapData[value.ID] = value
}
curStoreInfo := storeMapData[storeID]
if curStoreInfo == nil {
return nil, errors.New(fmt.Sprintf("未找到商店:[%d]", storeID))
}
cityCode := curStoreInfo.CityCode
//获取本市商品总销量
citySkuSalesCntMap := make(map[int]int)
citySkuSalesCntList, err := dao.GetSkuSalesCntList(db, -1, cityCode, DayNum, LimitNum, nil)
citySkuIDs := []int{}
if err == nil {
for _, value := range citySkuSalesCntList {
citySkuSalesCntMap[value.SkuID] = value.Count
citySkuIDs = append(citySkuIDs, value.SkuID)
}
} else {
return nil, err
}
//获取本店商品总销量
storeSkuSalesCntMap := make(map[int]int)
storeSkuSalesCntList, err := dao.GetSkuSalesCntList(db, storeID, cityCode, DayNum, -1, citySkuIDs)
if err == nil {
for _, value := range storeSkuSalesCntList {
storeSkuSalesCntMap[value.SkuID] = value.Count
}
} else {
return nil, err
}
//获取本店商品差评数量
storeSkuBadCommentCntMap := make(map[int]int)
storeSkuBadCommentCntList, err := dao.GetSkuBadCommentCntList(db, storeID, DayNum)
if err == nil {
for _, value := range storeSkuBadCommentCntList {
storeSkuBadCommentCntMap[value.SkuID] = value.Count
}
} else {
return nil, err
}
//得到当前门店商品数据
storeSkuMapData := make(map[int]*dao.StoreSkuNameExt)
storeSkuData, err := cms.GetStoreSkus(ctx, storeID, citySkuIDs, true, "", true, false, map[string]interface{}{}, 0, -1)
if err == nil {
for _, value := range storeSkuData.SkuNames {
for _, skuInfo := range value.Skus {
storeSkuMapData[skuInfo.SkuID] = value
}
}
} else {
return nil, err
}
//得到5KM内的所有门店
rangeStoreList := GetRangeStoreList(storeID, curStoreInfo.FloatLng, curStoreInfo.FloatLat, SaleSkuCheckRange, storeList)
//得到5KM内的所有门店的商品的价格
allStoreSkus := make(map[int]map[int]int)
var locker sync.RWMutex
taskFunc := func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
storeInfo := batchItemList[0].(*cms.StoreExt)
storeID := storeInfo.ID
jxSkuInfoData, err := cms.GetStoreSkus(ctx, storeID, citySkuIDs, true, "", true, false, map[string]interface{}{}, 0, -1)
jxSkuPriceMapData := make(map[int]int)
for _, value := range jxSkuInfoData.SkuNames {
for _, skuInfo := range value.Skus {
jxSkuPriceMapData[skuInfo.SkuID] = skuInfo.BindPrice
}
}
locker.Lock()
defer locker.Unlock()
allStoreSkus[storeID] = jxSkuPriceMapData
return retVal, err
}
taskParallel := tasksch.NewParallelTask("得到所有门店商品", nil, ctx, taskFunc, rangeStoreList)
taskParallel.Run()
_, err = taskParallel.GetResult(0)
if err != nil {
return nil, err
}
//计算商品的平均价格
skusTotalPrice := make(map[int]int)
skusCount := make(map[int]int)
skusAveragePrice := make(map[int]int)
for _, storeInfo := range rangeStoreList {
storeID := storeInfo.ID
storeSkuMapData := allStoreSkus[storeID]
for skuID, skuPrice := range storeSkuMapData {
skusTotalPrice[skuID] += skuPrice
skusCount[skuID]++
}
}
for id, totalPrice := range skusTotalPrice {
skusAveragePrice[id] = int(math.Round(float64(totalPrice) / float64(skusCount[id])))
}
//输出商品销量统计结果
skuAndNameMapData := make(map[int]*model.SkuAndName)
if len(storeSkuMapData) < len(citySkuIDs) {
skuAndNameList, err := dao.GetSkus(db, citySkuIDs, nil, nil, nil, nil)
if err == nil {
for _, value := range skuAndNameList {
skuAndNameMapData[value.ID] = value
}
}
}
for _, value := range citySkuSalesCntList {
skuID := value.SkuID
storeSkuSales := &model.StoreSkuSales{}
storeSkuSales.SkuID = skuID
storeSkuInfo := storeSkuMapData[skuID]
skuAndNameInfo := skuAndNameMapData[skuID]
if storeSkuInfo != nil {
skuName := storeSkuInfo.SkuName
skuInfo := storeSkuInfo.Skus[0]
storeSkuSales.SkuName = jxutils.ComposeSkuName(skuName.Prefix, skuName.Name, skuInfo.Comment, skuName.Unit, skuInfo.SkuSpecQuality, skuInfo.SkuSpecUnit, 0, skuName.ExPrefix, skuName.ExPrefixBegin, skuName.ExPrefixEnd)
storeSkuSales.SkuImage = storeSkuInfo.Img
storeSkuSales.SkuPrice = jxutils.IntPrice2StandardCurrencyString(int64(storeSkuInfo.Skus[0].BindPrice))
} else if skuAndNameInfo != nil {
skuNameList, err := dao.GetSkuNames(db, []int{skuAndNameInfo.NameID}, nil, "", false)
prefix := ""
if err == nil && len(skuNameList) > 0 {
storeSkuSales.SkuImage = skuNameList[0].Img
prefix = skuNameList[0].Prefix
}
storeSkuSales.SkuName = jxutils.ComposeSkuName(prefix, skuAndNameInfo.Name, skuAndNameInfo.Comment, skuAndNameInfo.Unit, skuAndNameInfo.SpecQuality, skuAndNameInfo.SpecUnit, 0, skuAndNameInfo.ExPrefix, skuAndNameInfo.ExPrefixBegin, skuAndNameInfo.ExPrefixEnd)
storeSkuSales.SkuPrice = "N/A"
} else {
storeSkuSales.SkuName = "N/A"
storeSkuSales.SkuPrice = "N/A"
}
storeSkuSales.SkuAvgPrice = jxutils.IntPrice2StandardCurrencyString(int64(skusAveragePrice[skuID]))
storeSkuSales.BadCommentCnt = storeSkuBadCommentCntMap[skuID]
storeSkuSales.StoreSkuSalesCnt = storeSkuSalesCntMap[skuID]
storeSkuSales.CitySkuSalesCnt = citySkuSalesCntMap[skuID]
outStoreSkuSales = append(outStoreSkuSales, storeSkuSales)
}
return outStoreSkuSales, err
}

View File

@@ -1,431 +0,0 @@
package permission
import (
"fmt"
"strings"
"time"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
)
func GetMenu(ctx *jxcontext.Context, userID string) (menus []*model.Menu, err error) {
if userID == "" {
return dao.GetMenu(dao.GetDB(), "", 0, 0, userID)
} else {
if user, err := dao.GetUserByID(dao.GetDB(), "user_id", userID); err == nil {
if user.Type&model.UserTypeRole != 0 {
return dao.GetMenuWithUser(dao.GetDB(), "", 0, 0, userID)
} else {
return dao.GetMenu(dao.GetDB(), "", 0, 0, "")
}
}
}
return dao.GetMenu(dao.GetDB(), "", 0, 0, userID)
}
func AddMenu(ctx *jxcontext.Context, menu *model.Menu) (err error) {
var (
db = dao.GetDB()
)
if menu == nil {
return fmt.Errorf("添加失败menu nil")
}
if menu.Name == "" || menu.Level == 0 {
return fmt.Errorf("添加失败menu 名称和等级必须有值!")
}
menus, err := dao.GetMenu(db, menu.Name, menu.Level, 0, "")
if len(menus) > 0 {
return fmt.Errorf("添加失败!已存在相同名称的 menu name : %v", menu.Name)
}
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, txDB)
panic(r)
}
}()
dao.WrapAddIDCULDEntity(menu, ctx.GetUserName())
err = dao.CreateEntity(db, menu)
dao.Commit(db, txDB)
return err
}
func UpdateMenu(ctx *jxcontext.Context, menuID int, payload map[string]interface{}, isDelete bool) (num int64, err error) {
var (
db = dao.GetDB()
)
menu := &model.Menu{}
menu.ID = menuID
err = dao.GetEntity(db, menu)
if err != nil {
return 0, err
}
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, txDB)
panic(r)
}
}()
if !isDelete {
valid := dao.StrictMakeMapByStructObject(payload, menu, ctx.GetUserName())
if len(valid) > 0 {
if num, err = dao.UpdateEntityLogically(db, menu, valid, ctx.GetUserName(), nil); err != nil {
dao.Rollback(db, txDB)
return 0, err
}
}
} else {
menu.DeletedAt = time.Now()
num, err = dao.UpdateEntity(db, menu, "DeletedAt")
}
dao.Commit(db, txDB)
return num, err
}
func GetRole(ctx *jxcontext.Context, name string) (roles []*model.Role, err error) {
var (
db = dao.GetDB()
)
roles, err = dao.GetRole(db, name, "")
for _, v := range roles {
if v.CityCodes != "" {
if cityInfos, err := dao.GetPlaces(db, jxutils.StrListToIntList(strings.Split(v.CityCodes, ","))); err == nil {
v.CityInfo = cityInfos
}
}
if v.StoreIDs != "" {
if stores, err := dao.GetStoreList(db, jxutils.StrListToIntList(strings.Split(v.StoreIDs, ",")), nil, nil, nil, nil, ""); err == nil {
v.Stores = stores
}
}
}
return roles, err
}
func AddRole(ctx *jxcontext.Context, name string) (err error) {
var (
db = dao.GetDB()
)
roles, err := dao.GetRole(db, "", name)
if len(roles) > 0 {
return fmt.Errorf("添加失败!已存在相同名称的 role name : %v", name)
}
role := &model.Role{
Name: name,
}
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, txDB)
panic(r)
}
}()
dao.WrapAddIDCULDEntity(role, ctx.GetUserName())
err = dao.CreateEntity(db, role)
dao.Commit(db, txDB)
return err
}
func UpdateRole(ctx *jxcontext.Context, roleID int, name string, isDelete bool, brandID int, cityCodes, storeIDs []int) (num int64, err error) {
var (
db = dao.GetDB()
cityCodesStr []string
storeIDsStr []string
)
for _, v := range cityCodes {
cityCodesStr = append(cityCodesStr, utils.Int2Str(v))
}
for _, v := range storeIDs {
storeIDsStr = append(storeIDsStr, utils.Int2Str(v))
}
if roleID == 1 {
return 0, fmt.Errorf("管理员不允许修改!")
}
role := &model.Role{}
role.ID = roleID
err = dao.GetEntity(db, role)
if err != nil {
return 0, err
}
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, txDB)
panic(r)
}
}()
if !isDelete {
role.Name = name
role.UpdatedAt = time.Now()
role.LastOperator = ctx.GetUserName()
role.BrandID = brandID
role.CityCodes = strings.Join(cityCodesStr, ",")
role.StoreIDs = strings.Join(storeIDsStr, ",")
num, err = dao.UpdateEntity(db, role, "Name", "UpdatedAt", "LastOperator", "BrandID", "CityCodes", "StoreIDs")
} else {
role.DeletedAt = time.Now()
num, err = dao.UpdateEntity(db, role, "DeletedAt")
}
dao.Commit(db, txDB)
return num, err
}
func GetUserRole(ctx *jxcontext.Context, userID string) (userRoles []*model.UserRole, err error) {
return dao.GetUserRole(dao.GetDB(), []string{userID}, nil)
}
func UpdateUserRole(ctx *jxcontext.Context, userIDs []string, roleIDs []int) (err error) {
var (
db = dao.GetDB()
roleIDMap = make(map[int]int)
nowRoleIDMap = make(map[int]int)
userRoleMap = make(map[string][]int)
addUserRoleMap = make(map[string][]int)
deleteUserRoleMap = make(map[string][]int)
)
for _, v := range roleIDs {
roleIDMap[v] = 1
}
userRoles, err := dao.GetUserRole(db, userIDs, nil)
if err != nil {
return err
}
if len(userRoles) > 0 {
for _, v := range userRoles {
userRoleMap[v.UserID] = append(userRoleMap[v.UserID], v.RoleID)
}
}
for _, userID := range userIDs {
nowRoleIDs := userRoleMap[userID]
for _, nowRoleID := range nowRoleIDs {
if roleIDMap[nowRoleID] == 0 {
deleteUserRoleMap[userID] = append(deleteUserRoleMap[userID], nowRoleID)
}
nowRoleIDMap[nowRoleID] = 1
}
for roleID, _ := range roleIDMap {
if nowRoleIDMap[roleID] == 0 {
addUserRoleMap[userID] = append(addUserRoleMap[userID], roleID)
}
}
}
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, txDB)
panic(r)
}
}()
if len(addUserRoleMap) > 0 {
for userID, roleIDs := range addUserRoleMap {
for _, roleID := range roleIDs {
userRole := &model.UserRole{
UserID: userID,
RoleID: roleID,
}
dao.WrapAddIDCULDEntity(userRole, ctx.GetUserName())
err = dao.CreateEntity(db, userRole)
}
}
}
if len(deleteUserRoleMap) > 0 {
for userID, roleIDs := range deleteUserRoleMap {
for _, roleID := range roleIDs {
userRoles, _ := dao.GetUserRole(db, []string{userID}, []int{roleID})
if len(userRoles) > 0 {
userRoles[0].DeletedAt = time.Now()
userRoles[0].LastOperator = ctx.GetUserName()
_, err = dao.UpdateEntity(db, userRoles[0], "DeletedAt", "LastOperator")
}
}
}
}
for _, v := range userIDs {
if user, err := dao.GetUserByID(db, "user_id", v); err == nil {
user.Type = user.Type | model.UserTypeRole
dao.UpdateEntity(db, user, "Type")
}
}
dao.Commit(db, txDB)
return err
}
func GetRoleMenu(ctx *jxcontext.Context, roleID int) (roleMenus []*model.RoleMenu, err error) {
return dao.GetRoleMenu(dao.GetDB(), []int{roleID}, nil)
}
func UpdateRoleMenu(ctx *jxcontext.Context, roleIDs, menuIDs []int) (err error) {
var (
db = dao.GetDB()
menuIDMap = make(map[int]int)
nowMenuIDMap = make(map[int]int)
roleMenuMap = make(map[int][]int)
addRoleMenuMap = make(map[int][]int)
deleteRoleMenuMap = make(map[int][]int)
)
for _, v := range menuIDs {
menuIDMap[v] = 1
}
roleMenus, err := dao.GetRoleMenu(db, roleIDs, nil)
if err != nil {
return err
}
if len(roleMenus) > 0 {
for _, v := range roleMenus {
roleMenuMap[v.RoleID] = append(roleMenuMap[v.RoleID], v.MenuID)
}
}
for _, roleID := range roleIDs {
nowMenuIDs := roleMenuMap[roleID]
for _, nowMenuID := range nowMenuIDs {
if menuIDMap[nowMenuID] == 0 {
deleteRoleMenuMap[roleID] = append(deleteRoleMenuMap[roleID], nowMenuID)
}
nowMenuIDMap[nowMenuID] = 1
}
for menuID, _ := range menuIDMap {
if nowMenuIDMap[menuID] == 0 {
addRoleMenuMap[roleID] = append(addRoleMenuMap[roleID], menuID)
}
}
}
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, txDB)
panic(r)
}
}()
if len(addRoleMenuMap) > 0 {
for roleID, menuIDs := range addRoleMenuMap {
for _, menuID := range menuIDs {
roleMenu := &model.RoleMenu{
RoleID: roleID,
MenuID: menuID,
}
dao.WrapAddIDCULDEntity(roleMenu, ctx.GetUserName())
err = dao.CreateEntity(db, roleMenu)
}
}
}
if len(deleteRoleMenuMap) > 0 {
for roleID, menuIDs := range deleteRoleMenuMap {
for _, menuID := range menuIDs {
roleMenus, _ := dao.GetRoleMenu(db, []int{roleID}, []int{menuID})
if len(roleMenus) > 0 {
roleMenus[0].DeletedAt = time.Now()
roleMenus[0].LastOperator = ctx.GetUserName()
_, err = dao.UpdateEntity(db, roleMenus[0], "DeletedAt", "LastOperator")
}
}
}
}
dao.Commit(db, txDB)
return err
}
func GetUserStoresResultMap(userID string) (resultMap map[int]int, err error) {
var (
db = dao.GetDB()
// brandIDMap = make(map[int]int)
// cityCodeMap = make(map[int]int)
// storeIDMap = make(map[int]int)
)
resultMap = make(map[int]int)
user, _ := dao.GetUserByID(db, "user_id", userID)
if user != nil {
if user.BindStoreID != "" {
for _, v := range strings.Split(user.BindStoreID, ",") {
resultMap[utils.Str2Int(v)] = utils.Str2Int(v)
}
return resultMap, err
}
}
userRoles, err2 := dao.GetUserRole2(db, []string{userID}, nil)
err = err2
for _, v := range userRoles {
var (
brandIDs, cityCodes, storeIDs []int
)
// if _, ok := brandIDMap[v.BrandID]; !ok {
// brandIDMap[v.BrandID] = 1
// }
// if v.CityCodes != "" {
// for _, cityCode := range jxutils.StrListToIntList(strings.Split(v.CityCodes, ",")) {
// if _, ok := cityCodeMap[cityCode]; !ok {
// cityCodeMap[cityCode] = 1
// }
// }
// }
// if v.StoreIDs != "" {
// for _, storeID := range jxutils.StrListToIntList(strings.Split(v.StoreIDs, ",")) {
// if _, ok := storeIDMap[storeID]; !ok {
// storeIDMap[storeID] = 1
// }
// }
// }
if v.CityCodes == "" && v.StoreIDs == "" {
continue
}
if v.BrandID != 0 {
brandIDs = append(brandIDs, v.BrandID)
}
if v.CityCodes != "0" && v.CityCodes != "" {
cityCodes = append(cityCodes, jxutils.StrListToIntList(strings.Split(v.CityCodes, ","))...)
}
if v.StoreIDs != "" {
storeIDs = append(storeIDs, jxutils.StrListToIntList(strings.Split(v.StoreIDs, ","))...)
}
if stores, err := dao.GetStoreList(db, storeIDs, cityCodes, nil, brandIDs, nil, ""); len(stores) > 0 && err == nil {
for _, v := range stores {
resultMap[v.ID] = v.ID
}
}
}
// for k, _ := range brandIDMap {
// brandIDs = append(brandIDs, k)
// }
// for k, _ := range cityCodeMap {
// cityCodes = append(cityCodes, k)
// }
// for k, _ := range storeIDMap {
// storeIDs = append(storeIDs, k)
// }
// if stores1, err := dao.GetStoreList(db, nil, nil, brandIDs, nil, nil, ""); len(stores1) > 0 && err == nil {
// stores = append(stores, stores1...)
// }
// if stores2, err := dao.GetStoreList(db, nil, cityCodes, nil, nil, nil, ""); len(stores2) > 0 && err == nil {
// stores = append(stores, stores2...)
// }
// if stores3, err := dao.GetStoreList(db, storeIDs, nil, nil, nil, nil, ""); len(stores3) > 0 && err == nil {
// stores = append(stores, stores3...)
// }
return resultMap, err
}
func IsRoled(ctx *jxcontext.Context) bool {
if ctx.GetUserName() != "jxadmin" {
if user, err := dao.GetUserByID(dao.GetDB(), "user_id", ctx.GetUserID()); err == nil {
if user.Type&model.UserTypeRole != 0 {
return true
}
}
}
return false
}
func IsRoledByUserID(userID string) bool {
if user, err := dao.GetUserByID(dao.GetDB(), "user_id", userID); err == nil {
if user.Type&model.UserTypeRole != 0 {
return true
}
}
return false
}

View File

@@ -1,772 +0,0 @@
package report
import (
"errors"
"fmt"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/globals/api"
"math"
"sort"
"strings"
"time"
"git.rosy.net.cn/jx-callback/business/jxutils/ddmsg"
"git.rosy.net.cn/baseapi/platformapi/dingdingapi"
"git.rosy.net.cn/baseapi/platformapi/mtwmapi"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/business/jxstore/permission"
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
)
type tStoreSkuBindAndSkuName struct {
CityCode int
StoreID int `orm:"column(store_id)"`
NameID int `orm:"column(name_id)"`
UnitPrice int
UnitPriceList []int
}
func GetStatisticsReportForOrders(ctx *jxcontext.Context, storeIDs, vendorIDs []int, fromDate, toDate, marketPhone, jdPhone, mtPhone, ebaiPhone string) (statisticsReportForOrdersList []*dao.StatisticsReportForOrdersList, err error) {
db := dao.GetDB()
fromDateParm := utils.Str2Time(fromDate)
toDateParm := utils.Str2Time(toDate)
//若时间间隔大于3个月则不允许查询
if math.Ceil(toDateParm.Sub(fromDateParm).Hours()/24) > 92 {
return nil, errors.New(fmt.Sprintf("查询间隔时间不允许大于3个月: 时间范围:[%v] 至 [%v]", fromDate, toDate))
}
statisticsReportForOrdersList, err = dao.GetStatisticsReportForOrders(db, storeIDs, vendorIDs, fromDateParm, toDateParm, marketPhone, jdPhone, mtPhone, ebaiPhone)
return statisticsReportForOrdersList, err
}
func GetStatisticsReportForAfsOrders(ctx *jxcontext.Context, storeIDs []int, fromDate string, toDate string) (statisticsReportForOrdersList []*dao.StatisticsReportForOrdersList, err error) {
db := dao.GetDB()
fromDateParm := utils.Str2Time(fromDate)
toDateParm := utils.Str2Time(toDate)
//若时间间隔大于3个月则不允许查询
if math.Ceil(toDateParm.Sub(fromDateParm).Hours()/24) > 92 {
return nil, errors.New(fmt.Sprintf("查询间隔时间不允许大于3个月: 时间范围:[%v] 至 [%v]", fromDate, toDate))
}
statisticsReportForOrdersList, err = dao.GetGetStatisticsReportForAfsOrders(db, storeIDs, fromDateParm, toDateParm)
return statisticsReportForOrdersList, err
}
func StatisticsReportForStoreSkusPrice(ctx *jxcontext.Context, cityCodes, skuIDs []int, snapDate string, offset, pageSize int) (pagedInfo *model.PagedInfo, err error) {
var snapDateParam time.Time
db := dao.GetDB()
if snapDate != "" {
snapDateParam = utils.Str2Time(snapDate)
}
priceReferSnapshot, totalCount, err := dao.GetPriceReferSnapshot(db, cityCodes, skuIDs, 0, snapDateParam, offset, pageSize)
pagedInfo = &model.PagedInfo{
Data: priceReferSnapshot,
TotalCount: totalCount,
}
return
}
func BeginSavePriceRefer(ctx *jxcontext.Context, cityCodes, skuIDs []int, isAsync, isContinueWhenError bool) (hint string, err error) {
var priceReferSnapshotList []*model.PriceReferSnapshot
db := dao.GetDB()
snapshotAt := utils.Time2Date(time.Now().AddDate(0, 0, -1))
dao.DeletePriceReferHistory(db, utils.Time2Date(snapshotAt.AddDate(0, 0, -7)))
priceReferSnapshotDelete := &model.PriceReferSnapshot{SnapshotAt: snapshotAt}
dao.DeleteEntity(db, priceReferSnapshotDelete, "SnapshotAt")
taskSeqFunc := func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
switch step {
case 0:
priceReferSnapshot, err := dao.GetStatisticsReportForStoreSkusPrice(db, cityCodes, skuIDs)
if len(priceReferSnapshot) > 0 {
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil || err != nil {
dao.Rollback(db, txDB)
if r != nil {
panic(r)
}
}
}()
for _, v := range priceReferSnapshot {
dao.WrapAddIDCULDEntity(v, ctx.GetUserName())
v.SnapshotAt = snapshotAt
}
dao.CreateMultiEntities(db, priceReferSnapshot)
dao.Commit(db, txDB)
}
case 1:
priceReferSnapshotList, err = dao.GetPriceReferSnapshotNoPage(db, nil, nil, nil, snapshotAt)
var (
citySkuMap = make(map[int]map[int][]int)
countryMap = make(map[int][]int)
resultMap = make(map[int]map[int]*model.PriceReferSnapshot)
resultCountryMap = make(map[int]*model.PriceReferSnapshot)
)
storeList, err := dao.GetStoreList(db, nil, nil, nil, nil, nil, "")
if err != nil {
return result, err
}
for _, v := range storeList {
if v.PayPercentage < 50 {
continue
}
var tList []*tStoreSkuBindAndSkuName
sql := `
SELECT DISTINCT b.city_code, a.store_id, Round(a.unit_price * IF(b.pay_percentage < 50 , 70, b.pay_percentage) / 100) AS unit_price, c.name_id
FROM store_sku_bind a
JOIN store b ON b.id = a.store_id AND b.deleted_at = ? AND b.status != ?
JOIN sku c ON c.id = a.sku_id
WHERE a.store_id = ?
AND c.name_id NOT IN(
SELECT b.name_id
FROM store_sku_bind a
JOIN sku b ON a.sku_id = b.id AND b.deleted_at = ?
WHERE a.deleted_at = ?
AND a.store_id = ?
AND b.name_id NOT IN(SELECT DISTINCT b.name_id
FROM store_sku_bind a
JOIN sku b ON a.sku_id = b.id AND b.deleted_at = ?
WHERE a.deleted_at = ?
AND a.store_id = ?
AND a.status = ?)
)
AND a.deleted_at = ?
`
sqlParams := []interface{}{
utils.DefaultTimeValue,
model.StoreStatusDisabled,
v.ID,
utils.DefaultTimeValue,
utils.DefaultTimeValue,
v.ID,
utils.DefaultTimeValue,
utils.DefaultTimeValue,
v.ID,
model.StoreSkuBindStatusNormal,
utils.DefaultTimeValue,
}
dao.GetRows(db, &tList, sql, sqlParams...)
skuNameMap := make(map[int][]int)
if len(tList) > 0 {
for _, vv := range tList {
skuNameMap[vv.NameID] = append(skuNameMap[vv.NameID], vv.UnitPrice)
countryMap[vv.NameID] = append(countryMap[vv.NameID], vv.UnitPrice)
}
if citySkuMap[v.CityCode] != nil {
for nameID, unitPriceList := range skuNameMap {
if citySkuMap[v.CityCode][nameID] != nil {
citySkuMap[v.CityCode][nameID] = append(citySkuMap[v.CityCode][nameID], unitPriceList...)
} else {
citySkuMap[v.CityCode][nameID] = unitPriceList
}
}
} else {
citySkuMap[v.CityCode] = skuNameMap
}
}
}
for k, v := range countryMap {
var midUnitPrice int
var avgUnitPrice int
sort.Ints(v)
if len(v)%2 == 0 {
midUnitPrice = v[len(v)/2-1]
} else {
midUnitPrice = v[len(v)/2]
}
for _, vv := range v {
avgUnitPrice += vv
}
priceRefer := &model.PriceReferSnapshot{
MidUnitPrice: midUnitPrice,
MaxUnitPrice: v[len(v)-1],
MinUnitPrice: v[0],
AvgUnitPrice: avgUnitPrice / len(v),
}
resultCountryMap[k] = priceRefer
}
for k1, v := range citySkuMap {
skuNameMap := make(map[int]*model.PriceReferSnapshot)
for k2, _ := range v {
var midUnitPrice int
var avgUnitPrice int
sort.Ints(v[k2])
if len(v[k2])%2 == 0 {
midUnitPrice = v[k2][len(v[k2])/2-1]
} else {
midUnitPrice = v[k2][len(v[k2])/2]
}
for _, vv := range v[k2] {
avgUnitPrice += vv
}
skuNameMap[k2] = &model.PriceReferSnapshot{
MidUnitPrice: midUnitPrice,
MaxUnitPrice: v[k2][len(v[k2])-1],
MinUnitPrice: v[k2][0],
AvgUnitPrice: avgUnitPrice / len(v[k2]),
}
}
resultMap[k1] = skuNameMap
}
if len(priceReferSnapshotList) > 0 {
for _, v := range priceReferSnapshotList {
if v.CityCode == 0 {
if resultCountryMap[v.NameID] != nil {
v.MidUnitPrice = resultCountryMap[v.NameID].MidUnitPrice
v.MaxUnitPrice = resultCountryMap[v.NameID].MaxUnitPrice
v.AvgUnitPrice = resultCountryMap[v.NameID].AvgUnitPrice
v.MinUnitPrice = resultCountryMap[v.NameID].MinUnitPrice
dao.UpdateEntity(db, v, "MidUnitPrice", "MaxUnitPrice", "MinUnitPrice", "AvgUnitPrice")
}
continue
}
if resultMap[v.CityCode][v.NameID] != nil {
v.MidUnitPrice = resultMap[v.CityCode][v.NameID].MidUnitPrice
v.MaxUnitPrice = resultMap[v.CityCode][v.NameID].MaxUnitPrice
v.AvgUnitPrice = resultMap[v.CityCode][v.NameID].AvgUnitPrice
v.MinUnitPrice = resultMap[v.CityCode][v.NameID].MinUnitPrice
dao.UpdateEntity(db, v, "MidUnitPrice", "MaxUnitPrice", "MinUnitPrice", "AvgUnitPrice")
}
}
}
case 2:
if len(priceReferSnapshotList) > 0 {
for _, v := range priceReferSnapshotList {
result, _ := dao.GetPriceReferPrice(db, v.CityCode, v.SkuID, snapshotAt)
if result != nil {
v.MaxPrice = result.MaxPrice
v.MinPrice = result.MinPrice
v.AvgPrice = result.AvgPrice
v.MidPrice = result.MidPrice
dao.UpdateEntity(db, v, "MidPrice", "MaxPrice", "MinPrice", "AvgPrice")
}
}
}
//TODO 京东查询接口报错,暂时屏蔽了
// case 3:
// priceReferSnapshotList, err = dao.GetPriceReferSnapshotNoPage(db, []int{0}, nil, nil, snapshotAt)
// taskFunc := func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
// v := batchItemList[0].(*model.PriceReferSnapshot)
// for _, appOrg := range apimanager.CurAPIManager.GetAppOrgCodeList(model.VendorIDJD) {
// directPrice, _ := jd.GetAPI(appOrg).GetJdSkuDirectPrice(v.SkuID)
// v.JdDirectPrice = int(directPrice)
// dao.UpdateEntity(db, v, "JdDirectPrice")
// }
// return retVal, err
// }
// taskParallel := tasksch.NewParallelTask("获取并更新京东指导价格", tasksch.NewParallelConfig(), ctx, taskFunc, priceReferSnapshotList)
// tasksch.HandleTask(taskParallel, task, true).Run()
// _, err = taskParallel.GetResult(0)
}
return result, err
}
taskSeq := tasksch.NewSeqTask2("生成每日价格统计", ctx, isContinueWhenError, taskSeqFunc, 3)
tasksch.HandleTask(taskSeq, nil, true).Run()
if !isAsync {
_, err = taskSeq.GetResult(0)
hint = "1"
} else {
hint = taskSeq.GetID()
}
return hint, err
}
type GetManageStateResult struct {
OpenStoreCount int `json:"openStoreCount"` //营业店铺数
HaveRestStoreCount int `json:"haveRestStoreCount"` //临时休息店铺数
RestStoreCount int `json:"restStoreCount"` //休息店铺数
FinishOrderState *GetManageStateOrderInfo //完成订单情况
IngOrderState *GetManageStateOrderInfo //进行中订单情况
CancelOrderState *GetManageStateOrderInfo //取消订单情况
}
type GetManageStateOrderInfo struct {
ActualPayPrice int `json:"actualPayPrice"` //支付总额
TotalShopMoney int `json:"totalShopMoney"` //平台结算
DesiredFee int `json:"desiredFee"` //配送费
Yhld string `json:"yhld"` //优惠力度(支付总额-平台结算-配送支出)/支付总额*100%
}
func getStoreStatusCount(db *dao.DaoDB, cityCodes []int, vendorID, status int) (count int, err error) {
countType := &struct{ Count int }{}
sqlParams := []interface{}{}
sql := `
SELECT COUNT(DISTINCT a.id) count
FROM store a
LEFT JOIN store_map b ON a.id = b.store_id AND b.deleted_at = ?
WHERE a.deleted_at = ?
`
sqlParams = append(sqlParams, utils.DefaultTimeValue, utils.DefaultTimeValue)
if len(cityCodes) > 0 {
sql += " AND a.city_code IN (" + dao.GenQuestionMarks(len(cityCodes)) + ")"
sqlParams = append(sqlParams, cityCodes)
}
if vendorID != -1 {
sql += " AND b.vendor_id = ? AND b.status = ?"
sqlParams = append(sqlParams, vendorID, status)
} else {
sql += " AND a.status = ?"
sqlParams = append(sqlParams, status)
}
err = dao.GetRow(db, &countType, sql, sqlParams)
return countType.Count, err
}
func getOrderStateCount(db *dao.DaoDB, cityCodes []int, vendorID, status int) (getManageStateOrderInfo *GetManageStateOrderInfo, err error) {
sqlParams := []interface{}{}
getManageStateOrderInfo = &GetManageStateOrderInfo{}
endTime := time.Now().AddDate(0, -3, 0)
sql := `
SELECT SUM(b.actual_pay_price) actual_pay_price, SUM(b.total_shop_money) total_shop_money, SUM(IFNULL(c.desired_fee, 0)) desired_fee
FROM store a
LEFT JOIN goods_order b ON a.id = IF(b.jx_store_id = 0, b.store_id, b.jx_store_id)
LEFT JOIN waybill c ON IF(b.waybill_vendor_id = -1,b.vendor_order_id,b.vendor_waybill_id) = c.vendor_waybill_id
WHERE a.deleted_at = ? AND a.status <> ?
AND b.order_created_at < ? AND b.order_created_at > ?
`
sqlParams = append(sqlParams, utils.DefaultTimeValue, model.StoreStatusDisabled, time.Now(), endTime)
if len(cityCodes) > 0 {
sql += " AND a.city_code IN (" + dao.GenQuestionMarks(len(cityCodes)) + ")"
sqlParams = append(sqlParams, cityCodes)
}
if vendorID != -1 {
sql += " AND b.vendor_id = ?"
sqlParams = append(sqlParams, vendorID)
}
if status != model.OrderStatusDelivering {
sql += " AND b.status = ?"
sqlParams = append(sqlParams, status)
} else {
sql += " AND b.status < ? AND b.status >= ?"
sqlParams = append(sqlParams, model.OrderStatusEndBegin, model.OrderStatusWait4Pay)
}
err = dao.GetRow(db, &getManageStateOrderInfo, sql, sqlParams)
getManageStateOrderInfo.Yhld = utils.Float64ToStr(math.Round((float64(getManageStateOrderInfo.ActualPayPrice-getManageStateOrderInfo.TotalShopMoney-getManageStateOrderInfo.DesiredFee) / float64(getManageStateOrderInfo.ActualPayPrice) * 100))) + "%"
return getManageStateOrderInfo, err
}
func GetManageState(ctx *jxcontext.Context, cityCodes []int, vendorID int) (getManageStateResult *GetManageStateResult, err error) {
var (
db = dao.GetDB()
)
getManageStateResult = &GetManageStateResult{}
if openCount, err := getStoreStatusCount(db, cityCodes, vendorID, model.StoreStatusOpened); err == nil {
getManageStateResult.OpenStoreCount = openCount
}
if haveRestCount, err := getStoreStatusCount(db, cityCodes, vendorID, model.StoreStatusHaveRest); err == nil {
getManageStateResult.HaveRestStoreCount = haveRestCount
}
if restCount, err := getStoreStatusCount(db, cityCodes, vendorID, model.StoreStatusClosed); err == nil {
getManageStateResult.RestStoreCount = restCount
}
if finishCount, err := getOrderStateCount(db, cityCodes, vendorID, model.OrderStatusFinished); err == nil {
getManageStateResult.FinishOrderState = finishCount
}
if ingCount, err := getOrderStateCount(db, cityCodes, vendorID, model.OrderStatusDelivering); err == nil {
getManageStateResult.IngOrderState = ingCount
}
if cancelCount, err := getOrderStateCount(db, cityCodes, vendorID, model.OrderStatusCanceled); err == nil {
getManageStateResult.CancelOrderState = cancelCount
}
return getManageStateResult, err
}
func RefreshStoreManageState(ctx *jxcontext.Context, storeIDs []int, vendorIDs []int) {
var (
db = dao.GetDB()
//vendorIDs = []int{model.VendorIDJD, model.VendorIDMTWM, model.VendorIDEBAI}
messageFlag = time.Now().Hour() == 10 && time.Now().Minute() > 0 && time.Now().Minute() < 12
)
task := tasksch.NewParallelTask("RefreshStoreManageState", tasksch.NewParallelConfig().SetParallelCount(3).SetIsContinueWhenError(true), ctx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
vendorID := batchItemList[0].(int)
storeMaps, err := dao.GetStoresMapList(db, []int{vendorID}, storeIDs, []int{model.StoreStatusOpened, model.StoreStatusClosed, model.StoreStatusHaveRest}, model.StoreStatusAll, model.StoreIsSyncAll, "", "", "")
storeManageStates, err := dao.GetStoreManageStateSimple(db, storeIDs, nil, vendorID)
var (
storeMapsMap = make(map[int]*model.StoreMap)
storeManagesMap = make(map[int]*model.StoreManageState)
deleteList []int
createList, updateList []*model.StoreMap
)
for _, v := range storeMaps {
storeMapsMap[v.StoreID] = v
}
for _, v := range storeManageStates {
storeManagesMap[v.StoreID] = v
if storeMapsMap[v.StoreID] != nil {
updateList = append(updateList, storeMapsMap[v.StoreID])
} else {
deleteList = append(deleteList, v.StoreID)
}
}
for _, v := range storeMapsMap {
if storeManagesMap[v.StoreID] == nil {
createList = append(createList, v)
}
}
task2 := tasksch.NewParallelTask("deleteList", tasksch.NewParallelConfig().SetIsContinueWhenError(true), ctx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
storeID := batchItemList[0].(int)
storeManage := &model.StoreManageState{
StoreID: storeID,
VendorID: vendorID,
}
dao.DeleteEntity(db, storeManage, "StoreID", "VendorID")
return retVal, err
}, deleteList)
tasksch.HandleTask(task2, task, true).Run()
task2.GetResult(0)
task3 := tasksch.NewParallelTask("createList", tasksch.NewParallelConfig().SetParallelCount(20).SetIsContinueWhenError(true), ctx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
storeMap := batchItemList[0].(*model.StoreMap)
if storeMap.VendorOrgCode == "" || storeMap.VendorStoreID == "" {
return retVal, err
}
storeDetail, _ := dao.GetStoreDetail(db, storeMap.StoreID, vendorID, storeMap.VendorOrgCode)
storeManage := buildStoreManageState(ctx, db, storeMap, storeDetail, messageFlag)
if storeManage == nil {
return retVal, err
}
dao.CreateEntity(db, storeManage)
return retVal, err
}, createList)
tasksch.HandleTask(task3, task, true).Run()
task3.GetResult(0)
task4 := tasksch.NewParallelTask("updateList", tasksch.NewParallelConfig().SetParallelCount(1).SetIsContinueWhenError(true), ctx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
storeMap := batchItemList[0].(*model.StoreMap)
if storeMap.VendorOrgCode == "" || storeMap.VendorStoreID == "" {
return retVal, err
}
storeDetail, _ := dao.GetStoreDetail(db, storeMap.StoreID, vendorID, storeMap.VendorOrgCode)
storeManage := buildStoreManageState(ctx, db, storeMap, storeDetail, messageFlag)
if storeManage == nil {
return retVal, err
}
if storeManageStates, err := dao.GetStoreManageStateSimple(db, []int{storeDetail.ID}, nil, vendorID); err == nil && len(storeManageStates) > 0 {
storeManage.ID = storeManageStates[0].ID
dao.UpdateEntity(db, storeManage)
}
return retVal, err
}, updateList)
tasksch.HandleTask(task4, task, true).Run()
task4.GetResult(0)
return retVal, err
}, vendorIDs)
tasksch.HandleTask(task, nil, true).Run()
task.GetID()
}
func buildStoreManageState(ctx *jxcontext.Context, db *dao.DaoDB, storeMap *model.StoreMap, storeDetail *dao.StoreDetail, messageFlag bool) *model.StoreManageState {
var (
dayTimeBegin, dayTimeEnd = utils.Str2Time(utils.Time2Str(utils.Time2Date(time.Now())) + "00:00:00"), utils.Str2Time(utils.Time2Str(utils.Time2Date(time.Now())) + "23:59:59")
)
storeManage := &model.StoreManageState{
StoreID: storeMap.StoreID,
VendorID: storeMap.VendorID,
}
dao.WrapAddIDCULEntity(storeManage, ctx.GetUserName())
handler := partner.GetPurchasePlatformFromVendorID(storeMap.VendorID)
store, err := handler.ReadStore(ctx, storeDetail.VendorOrgCode, storeDetail.VendorStoreID)
if err != nil || store == nil {
return nil
}
// if coverAreaFlag {
if storeMap.VendorID == model.VendorIDJD && store.DeliveryRangeType != model.DeliveryRangeTypePolygon {
storeManage.CoverArea = utils.Str2Float64(fmt.Sprintf("%.2f", math.Pi*utils.Str2Float64WithDefault(store.DeliveryRange, 0)/float64(1000)*utils.Str2Float64WithDefault(store.DeliveryRange, 0)/float64(1000)))
} else {
storeManage.CoverArea = utils.Str2Float64(fmt.Sprintf("%.2f", CalculateCoverArea(strings.Split(store.DeliveryRange, ";"), storeMap.VendorID)))
}
// }
//营业状态
storeManage.VendorStatus = store.Status
//不一致发消息
if messageFlag {
vendorStatus, status := -1, -1
if store.Status == model.StoreStatusOpened {
vendorStatus = 1
}
if storeDetail.Status == model.StoreStatusOpened {
status = 1
}
statusMap := map[int]string{
1: "营业",
-1: "休息",
}
if vendorStatus != status {
content := "您的门店 [" + storeDetail.Name + "]ID:[" + utils.Int2Str(storeDetail.ID) + "],在[" + model.VendorChineseNames[storeMap.VendorID] + "] 平台上营业状态和京西不一致!平台状态:【" + statusMap[vendorStatus] + "】,京西状态:【" + statusMap[status] + "】"
if user, err := dao.GetUserByID(db, "mobile", storeDetail.MarketManPhone); err == nil {
ddmsg.SendUserMessage(dingdingapi.MsgTyeText, user.UserID, "平台门店状态变化", content)
}
}
}
//营业时长
optime := jxutils.JxOperationTime2TimeByDate(storeDetail.CloseTime1, time.Now()).Sub(jxutils.JxOperationTime2TimeByDate(storeDetail.OpenTime1, time.Now())).Hours()
if storeDetail.CloseTime2 != 0 && storeDetail.OpenTime2 != 0 {
optime += jxutils.JxOperationTime2TimeByDate(storeDetail.CloseTime2, time.Now()).Sub(jxutils.JxOperationTime2TimeByDate(storeDetail.OpenTime2, time.Now())).Hours()
}
storeManage.OpenTime = utils.Str2Float64(fmt.Sprintf("%.2f", optime))
//商品数
highSkuCount := 0
storeSkus, _ := dao.GetStoresSkusForManageState(db, storeMap.StoreID, model.StoreSkuBindStatusNormal)
for _, v := range storeSkus {
if v.UnitPrice > v.MidUnitPrice {
highSkuCount++
}
}
storeManage.SkuCount, storeManage.HighSkuCount = len(storeSkus), highSkuCount
//活动丰富度
ample, _ := handler.GetActAmple(ctx, storeDetail.VendorStoreID, storeDetail.VendorStoreID)
storeManage.ActAmple = ample
//订单
refuseOrderCount := 0
orderList, _ := dao.QueryOrdersForManageState(db, storeMap.StoreID, storeMap.VendorID, model.OrderStatusCanceled, dayTimeBegin, dayTimeEnd)
for _, v := range orderList {
if v.BindID == 0 {
refuseOrderCount++
}
}
storeManage.NullOrderCount, storeManage.RefuseOrderCount = len(orderList), refuseOrderCount
//评分(美团)
if storeMap.VendorID == model.VendorIDMTWM {
mtapi := partner.CurAPIManager.GetAPI(model.VendorIDMTWM, storeDetail.VendorOrgCode).(*mtwmapi.API)
if scoreResult, err := mtapi.CommentScore(storeDetail.VendorStoreID); err == nil {
storeManage.StoreScore = scoreResult.AvgPoiScore
}
}
return storeManage
}
func GetStoreManageState(ctx *jxcontext.Context, storeIDs, brandIDs []int, vendorID, sortType, offset, pageSize int) (pageInfo *model.PagedInfo, err error) {
var (
db = dao.GetDB()
)
//权限
if permission.IsRoled(ctx) {
if storeIDsMap, err := permission.GetUserStoresResultMap(ctx.GetUserID()); err == nil {
var storeIDs2 []int
if len(storeIDs) > 0 {
for _, v := range storeIDs {
if storeIDsMap[v] != 0 {
storeIDs2 = append(storeIDs2, v)
}
}
if len(storeIDs2) == 0 {
storeIDs2 = append(storeIDs2, -1)
}
} else {
for k, _ := range storeIDsMap {
storeIDs2 = append(storeIDs2, k)
}
}
storeIDs = nil
storeIDs = storeIDs2
}
}
return dao.GetStoreManageState(db, storeIDs, brandIDs, vendorID, sortType, offset, pageSize)
}
func CalculateCoverArea(coordinate []string, vendorID int) (area float64) {
//我先把地理坐标转成了平面坐标(百度的方法)
//然后按多个坐标求面积公式求的面积(百度的方法)
if len(coordinate) == 0 {
return 0
}
var xyList [][2]float64
for _, v := range coordinate {
cell := strings.Split(v, ",")
if len(cell) == 0 || len(cell) == 1 {
continue
}
var lat, lng float64
if vendorID == model.VendorIDJD || vendorID == model.VendorIDEBAI {
lng = utils.Str2Float64WithDefault(cell[0], 0)
lat = utils.Str2Float64WithDefault(cell[1], 0)
} else {
lat = utils.Str2Float64WithDefault(cell[0], 0)
lng = utils.Str2Float64WithDefault(cell[1], 0)
}
xys := jxutils.MillierConvertion(lat, lng)
xyList = append(xyList, xys)
}
var sum float64 = 0
if len(xyList) == 0 {
return 0
}
for i := 0; i < len(xyList)-1; i++ {
// sum += (xyList[i+1][0] - xyList[i][0]) * (xyList[i+1][1] + xyList[i][1])
sum += (xyList[i][0]*xyList[i+1][1] - xyList[i+1][0]*xyList[i][1])
}
// sum += (xyList[0][0] - xyList[len(xyList)-1][0]) * (xyList[0][1] + xyList[len(xyList)-1][1])
sum += (xyList[len(xyList)-1][0]*xyList[0][1] - xyList[0][0]*xyList[len(xyList)-1][1])
sum /= float64(2)
sum = math.Abs(sum)
sum = utils.Str2Float64(fmt.Sprintf("%.2f", sum))
return sum
}
func RefreshJDMembers(ctx *jxcontext.Context) (err error) {
var (
db = dao.GetDB()
pageSize = 50
page int
pages []int
memberMap = make(map[string]*model.UserMember)
)
userMemebers, _ := dao.GetUserMemberWithoutDeleted(db, model.VendorIDJD)
for _, v := range userMemebers {
memberMap[v.Mobile] = v
}
pageResult, err := api.JdAPI.QueryMemberTransListByCondition("", "", page, pageSize)
if err != nil {
if strings.Contains(err.Error(), "cookie") {
globals.SugarLogger.Warnf("京东cookie过期了!")
}
}
if pageResult.Total%pageSize == 0 {
page = pageResult.Total / pageSize
} else {
page = pageResult.Total/pageSize + 1
}
for ; page > 0; page-- {
pages = append(pages, page)
}
task := tasksch.NewParallelTask2("RefreshJDMembers", tasksch.NewParallelConfig().SetIsContinueWhenError(true), ctx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, successCount int, err error) {
pageNo := batchItemList[0].(int)
pageResult2, err := api.JdAPI.QueryMemberTransListByCondition("", "", pageNo, pageSize)
if pageResult2 != nil {
for _, v := range pageResult2.Rows {
if utils.Str2Time(v.Endtimestr+" 23:59:59").Sub(time.Now()) >= 0 && v.Dealstatus == 0 {
if memberMap[v.Merchantcardno] != nil { //库里有这个人的会员信息了
if utils.Time2Str(memberMap[v.Merchantcardno].EndAt) != v.Endtimestr+" 23:59:59" { //可能这个人续费了,续存了
memberMap[v.Merchantcardno].EndAt = utils.Str2Time(v.Endtimestr + " 23:59:59")
memberMap[v.Merchantcardno].DeletedAt = utils.DefaultTimeValue
dao.UpdateEntity(db, memberMap[v.Merchantcardno], "EndAt", "DeletedAt")
}
} else {
userMember := &model.UserMember{
VendorOrderID: v.Orderid,
VendorID: model.VendorIDJD,
Mobile: v.Merchantcardno,
MemberType: 1,
EndAt: utils.Str2Time(v.Endtimestr + " 23:59:59"),
IsPay: 1,
}
dao.WrapAddIDCULDEntity(userMember, "jxadmin")
if v.Createtime != "" {
userMember.CreatedAt = utils.Str2Time(v.Createtime)
} else {
userMember.CreatedAt = utils.Str2Time(v.Cardcreatetime)
}
if userMember.EndAt.Sub(time.Now()) <= 0 {
userMember.DeletedAt = time.Now()
}
dao.CreateEntity(db, userMember)
}
}
}
}
return retVal, successCount, err
}, pages)
tasksch.HandleTask(task, nil, true).Run()
task.GetID()
return err
}
func UserMemberReport(ctx *jxcontext.Context, vendorID int, keyword string, offset, pageSize int) (page *model.PagedInfo, err error) {
var (
db = dao.GetDB()
)
var list []*dao.UserMemberReportResult
sql := `
SELECT SQL_CALC_FOUND_ROWS a.mobile, IF(a.vendor_id = ?, b.name, t1.consignee_name) name, IF(a.deleted_at = ?, ?, ?) status, a.vendor_id, t1.buy_count, t1.buy_price,
t1.good_comment_count, t1.bad_comment_count, t2.finished_count, t2.finished_price
FROM user_member a
LEFT JOIN user b ON a.mobile = b.mobile
LEFT JOIN (
SELECT a.mobile, MAX(b.consignee_name) consignee_name, COUNT(b.vendor_store_id) buy_count, SUM(b.actual_pay_price) buy_price, COUNT(c.score > 3) good_comment_count, COUNT(c.score < 3) bad_comment_count
FROM user_member a
LEFT JOIN goods_order b ON a.mobile = b.consignee_mobile2 AND a.vendor_id = b.vendor_id AND b.order_type = ? AND b.store_id <> ?
LEFT JOIN jx_bad_comments c ON c.order_id = b.vendor_order_id
GROUP BY 1
) t1 ON t1.mobile = a.mobile
LEFT JOIN (
SELECT a.mobile, COUNT(b.vendor_store_id) finished_count, SUM(b.actual_pay_price) finished_price
FROM user_member a
LEFT JOIN goods_order b ON a.mobile = b.consignee_mobile2 AND a.vendor_id = b.vendor_id AND b.order_type = ? AND status = ? AND b.store_id <> ?
GROUP BY 1
)t2 ON t2.mobile = a.mobile
WHERE 1 = 1
`
sqlParams := []interface{}{
model.VendorIDJX, utils.DefaultTimeValue, model.YES, model.NO,
model.OrderTypeNormal, model.MatterStoreID,
model.OrderTypeNormal, model.OrderStatusFinished, model.MatterStoreID,
}
if vendorID != -1 {
sql += " AND a.vendor_id = ?"
sqlParams = append(sqlParams, vendorID)
}
if keyword != "" {
keywordLike := "%" + keyword + "%"
sql += " AND (a.mobile LIKE ? OR name LIKE ?)"
sqlParams = append(sqlParams, keywordLike, keywordLike)
}
sql += `
LIMIT ? OFFSET ?
`
pageSize = jxutils.FormalizePageSize(pageSize)
sqlParams = append(sqlParams, pageSize, offset)
txDB, _ := dao.Begin(db)
defer dao.Commit(db, txDB)
if err = dao.GetRowsTx(txDB, &list, sql, sqlParams...); err == nil {
page = &model.PagedInfo{
TotalCount: dao.GetLastTotalRowCount2(db, txDB),
//Data: page,
}
task := tasksch.NewParallelTask("", tasksch.NewParallelConfig().SetIsContinueWhenError(true), jxcontext.AdminCtx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
v := batchItemList[0].(*dao.UserMemberReportResult)
var good *model.GoodsOrder
sql := `
SELECT * FROM goods_order WHERE consignee_mobile2 = ? AND vendor_id = ? AND order_type = ? AND store_id <> ? LIMIT 1 OFFSET 0
`
sqlParams := []interface{}{v.Mobile, v.VendorID, model.OrderTypeNormal, model.MatterStoreID}
dao.GetRow(db, &good, sql, sqlParams)
if good != nil {
v.NewPrice = good.ActualPayPrice
}
var place *model.Place
sql2 := `
SELECT a.* FROM place a,(
SELECT b.city_code, COUNT(*) count
FROM goods_order a
LEFT JOIN store b ON b.id = IF(a.jx_store_id = 0, store_id, jx_store_id)
WHERE consignee_mobile2 = ? AND vendor_id = ?
GROUP BY 1
ORDER BY COUNT(*)
LIMIT 1 OFFSET 0)b
WHERE a.code = b.city_code
`
dao.GetRow(db, &place, sql2, sqlParams)
if place != nil {
v.CityName = place.Name
v.CityCode = place.Code
}
return retVal, err
}, list)
tasksch.HandleTask(task, nil, true).Run()
task.GetResult(0)
page.Data = list
}
return page, err
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,44 +0,0 @@
package tempop
import (
"fmt"
"io/ioutil"
"net/http"
"testing"
"git.rosy.net.cn/jx-callback/globals/api2"
"git.rosy.net.cn/jx-callback/globals/testinit"
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/ebai"
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/elm"
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/jd"
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/mtwm"
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/weimob/wsc"
)
func init() {
testinit.Init()
api2.Init()
}
func TestJdStoreInfo1125(t *testing.T) {
_, err := JdStoreInfo1125()
if err != nil {
t.Fatal(err)
}
}
func Testaa(t *testing.T) {
request, _ := http.NewRequest(http.MethodGet, "https://stores.shop.jd.com/stores/updateStoreStatus?storeId=24332466&storeStatus=1", nil)
c := &http.Cookie{
Name: "thor",
Value: "80FAF09E9A09B6E618A68057BDFCFCB8C86E8252DC9F7D3B34572625904FBA0AB6BF053A5325612EC0407791BB05F5301356E71E8B282C40C06D0B5DF3439DEECB102A78FAFF7AC0FC4E2D1FA8DD8BBAE1A011E50B5C74F1870AD982D7BF453F470F31F2241B73AC4C25485025C2ABEBC8A538AF7257824D2FAEE300A1435175B0B451FB5C19B78D729FC83152CA3BAF",
}
request.AddCookie(c)
client := &http.Client{}
fmt.Println("test1", request.URL)
response, _ := client.Do(request)
defer response.Body.Close()
bodyData, _ := ioutil.ReadAll(response.Body)
fmt.Println("test1", string(bodyData))
}

File diff suppressed because it is too large Load Diff

View File

@@ -4,8 +4,8 @@ import (
"fmt"
"sync"
"git.rosy.net.cn/jx-callback/business/dao"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/business/model/legacymodel"
)

View File

@@ -9,24 +9,19 @@ import (
"image/png"
"net/http"
"git.rosy.net.cn/jx-callback/business/dao"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/globals/api"
"github.com/qiniu/api.v7/storage"
)
const (
qiniuTokenExpires = 300 // 七牛TOKEN有效时间5分钟
MainImgWidth = 800
MainImgHeight = 800
MainImgWidth2 = 500
MainImgHeight2 = 500
MainImgWidth = 800
MainImgHeight = 800
)
type UploadResTokenInfo struct {
@@ -53,23 +48,24 @@ func Binary2Image(binaryData []byte, mimeType string) (img image.Image, outMimeT
}
func GetQiniuUploadToken(ctx *jxcontext.Context, suffix, hashCode string) (upTokenInfo *UploadResTokenInfo, err error) {
imgURL := ""
if hashCode != "" {
imgURL, _ = GetDataResource(ctx, hashCode)
}
putPolicy := storage.PutPolicy{
Scope: globals.QiniuBucket,
Expires: qiniuTokenExpires,
}
upTokenInfo = &UploadResTokenInfo{
Token: putPolicy.UploadToken(api.QiniuAPI),
Expires: putPolicy.Expires,
FileName: jxutils.GenPicFileName(suffix),
Hit: imgURL != "",
Img: imgURL,
}
return upTokenInfo, err
//imgURL := ""
//if hashCode != "" {
// imgURL, _ = GetDataResource(ctx, hashCode)
//}
//
//putPolicy := storage.PutPolicy{
// Scope: globals.QiniuBucket,
// Expires: qiniuTokenExpires,
//}
//upTokenInfo = &UploadResTokenInfo{
// Token: putPolicy.UploadToken(api.QiniuAPI),
// Expires: putPolicy.Expires,
// FileName: jxutils.GenPicFileName(suffix),
// Hit: imgURL != "",
// Img: imgURL,
//}
//return upTokenInfo, err
return nil, err
}
// 此函数要求resBinary不能空mimeType与hashCode必须是正确的
@@ -83,7 +79,7 @@ func RegisterDataResource(ctx *jxcontext.Context, name, resourceURL, mimeType, h
return nil, err
}
if imgType == model.ImgTypeMain {
if (img.Bounds().Dx() != MainImgWidth || img.Bounds().Dy() != MainImgHeight) && (img.Bounds().Dx() != MainImgWidth2 || img.Bounds().Dy() != MainImgHeight2) {
if img.Bounds().Dx() != MainImgWidth || img.Bounds().Dy() != MainImgHeight {
return nil, fmt.Errorf("图片大小:%dx%d非法要求必须:%dx%d", img.Bounds().Dx(), img.Bounds().Dy(), MainImgWidth, MainImgHeight)
}
}
@@ -111,10 +107,10 @@ func RegisterDataResource(ctx *jxcontext.Context, name, resourceURL, mimeType, h
return dataRes, err
}
if imgType > 0 {
if globals.EnableStoreWrite {
// 忽略上传错误
UploadImage2Vendors(ctx, nil, dataRes, resBinary, isAsyncUpload2Vendor)
}
//if globals.EnableStoreWrite {
// 忽略上传错误
UploadImage2Vendors(ctx, nil, dataRes, resBinary, isAsyncUpload2Vendor)
//}
}
return dataRes, err
}
@@ -154,82 +150,82 @@ func GetDataResource(ctx *jxcontext.Context, hashCode string) (resourceURL strin
// 这个函数,可能部分平台成功,部分失败
func UploadImage2Vendors(ctx *jxcontext.Context, parentTask tasksch.ITask, dataRes *model.DataResource, imgData []byte, isAsync bool) (hint string, err error) {
var vendorIDs []int
if dataRes.EbaiURL == "" {
vendorIDs = append(vendorIDs, model.VendorIDEBAI)
}
if dataRes.MtwmURL == "" {
vendorIDs = append(vendorIDs, model.VendorIDMTWM)
}
// var vendorIDs []int
// if dataRes.EbaiURL == "" {
// vendorIDs = append(vendorIDs, model.VendorIDEBAI)
// }
// if dataRes.MtwmURL == "" {
// vendorIDs = append(vendorIDs, model.VendorIDMTWM)
// }
// if dataRes.JdsURL == "" {
// vendorIDs = append(vendorIDs, model.VendorIDJDShop)
// }
if len(vendorIDs) > 0 {
imgName := jxutils.GetShortNameFromURL(dataRes.MainURL)
task := tasksch.NewSeqTask(fmt.Sprintf("上传图片至平台1:%s,%s", dataRes.Name, dataRes.MainURL), ctx,
func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
switch step {
case 0:
if imgData == nil {
if imgData, _, err = jxutils.DownloadFileByURL(dataRes.MainURL); err != nil {
return nil, err
}
}
case 1:
uploadTask := tasksch.NewParallelTask(fmt.Sprintf("上传图片至平台2:%s,%s", dataRes.Name, imgName),
tasksch.NewParallelConfig().SetIsContinueWhenError(true), ctx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
vendorID := batchItemList[0].(int)
if handler := partner.GetPurchasePlatformFromVendorID(vendorID); handler != nil {
// TODO vendorOrgCode
imgHint, err2 := handler.UploadImg(ctx, "", dataRes.MainURL, imgData, imgName, int(dataRes.UseType))
if err = err2; err == nil {
retVal = [][]interface{}{
[]interface{}{
vendorID,
imgHint,
},
}
}
}
return retVal, err
}, vendorIDs)
tasksch.HandleTask(uploadTask, task, false).Run()
resultList, err2 := uploadTask.GetResult(0)
err = err2
if len(resultList) > 0 {
db := dao.GetDB()
for _, v := range resultList {
result := v.([]interface{})
vendorID := result[0].(int)
imgHint := result[1].(string)
updateField := ""
if vendorID == model.VendorIDEBAI {
dataRes.EbaiURL = imgHint
updateField = "EbaiURL"
} else if vendorID == model.VendorIDMTWM {
dataRes.MtwmURL = imgHint
updateField = "MtwmURL"
}
// else if vendorID == model.VendorIDJDShop {
// dataRes.JdsURL = imgHint
// updateField = "JdsURL"
// }
dao.UpdateEntity(db, dataRes, updateField)
}
}
}
return result, err
}, 2)
tasksch.HandleTask(task, parentTask, false).Run()
if !isAsync {
if _, err = task.GetResult(0); err == nil {
hint = "1"
}
} else {
hint = task.GetID()
}
}
// if len(vendorIDs) > 0 {
// imgName := jxutils.GetShortNameFromURL(dataRes.MainURL)
// task := tasksch.NewSeqTask(fmt.Sprintf("上传图片至平台1:%s,%s", dataRes.Name, dataRes.MainURL), ctx,
// func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
// switch step {
// case 0:
// if imgData == nil {
// if imgData, _, err = jxutils.DownloadFileByURL(dataRes.MainURL); err != nil {
// return nil, err
// }
// }
// case 1:
// uploadTask := tasksch.NewParallelTask(fmt.Sprintf("上传图片至平台2:%s,%s", dataRes.Name, imgName),
// tasksch.NewParallelConfig().SetIsContinueWhenError(true), ctx,
// func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
// vendorID := batchItemList[0].(int)
// if handler := partner.GetPurchasePlatformFromVendorID(vendorID); handler != nil {
// // TODO vendorOrgCode
// imgHint, err2 := handler.UploadImg(ctx, "", dataRes.MainURL, imgData, imgName, int(dataRes.UseType))
// if err = err2; err == nil {
// retVal = [][]interface{}{
// []interface{}{
// vendorID,
// imgHint,
// },
// }
// }
// }
// return retVal, err
// }, vendorIDs)
// tasksch.HandleTask(uploadTask, task, false).Run()
// resultList, err2 := uploadTask.GetResult(0)
// err = err2
// if len(resultList) > 0 {
// db := dao.GetDB()
// for _, v := range resultList {
// result := v.([]interface{})
// vendorID := result[0].(int)
// imgHint := result[1].(string)
// updateField := ""
// if vendorID == model.VendorIDEBAI {
// dataRes.EbaiURL = imgHint
// updateField = "EbaiURL"
// } else if vendorID == model.VendorIDMTWM {
// dataRes.MtwmURL = imgHint
// updateField = "MtwmURL"
// }
// // else if vendorID == model.VendorIDJDShop {
// // dataRes.JdsURL = imgHint
// // updateField = "JdsURL"
// // }
// dao.UpdateEntity(db, dataRes, updateField)
// }
// }
// }
// return result, err
// }, 2)
// tasksch.HandleTask(task, parentTask, false).Run()
// if !isAsync {
// if _, err = task.GetResult(0); err == nil {
// hint = "1"
// }
// } else {
// hint = task.GetID()
// }
// }
return hint, err
}

View File

@@ -7,17 +7,11 @@ import (
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/globals/api2"
"git.rosy.net.cn/jx-callback/globals/testinit"
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/ebai"
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/jd"
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/mtwm"
)
func init() {
testinit.Init()
api2.Init()
}
func TestGetQiniuUploadToken(t *testing.T) {

View File

@@ -1,58 +0,0 @@
package ddmsg
import (
"fmt"
"git.rosy.net.cn/baseapi/platformapi/dingdingapi"
"git.rosy.net.cn/baseapi/utils/errlist"
"git.rosy.net.cn/jx-callback/business/auth2"
"git.rosy.net.cn/jx-callback/business/auth2/authprovider/dingding"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/globals/api"
)
func SendDDUserMessage(msgType, ddUserID, title, content string) (err error) {
globals.SugarLogger.Debugf("SendDDUserMessage ddUserID:%s, title:%s", ddUserID, title)
if globals.IsProductEnv() {
if msgType == dingdingapi.MsgTyeText {
err = api.DingDingAPI.CorpAsyncSendSimple(ddUserID, content)
} else if msgType == dingdingapi.MsgTypeMarkdown {
err = api.DingDingAPI.CorpAsyncSendMarkdown([]string{ddUserID}, nil, false, title, content)
}
}
return err
}
func SendUserMessage(msgType, userID, title, content string) (err error) {
globals.SugarLogger.Debugf("SendUserMessage userID:%s, title:%s", userID, title)
authList, err := auth2.GetUserBindAuthInfo(userID)
findOneMethod := false
if err == nil {
for _, auth := range authList {
if auth.Type == dingding.AuthTypeStaff /*|| auth.Type == weixin.AuthTypeMP*/ {
findOneMethod = true
if len(content) > dingdingapi.MaxWorkContentLen {
content = content[:dingdingapi.MaxWorkContentLen-4] + "..."
}
err = SendDDUserMessage(msgType, auth.AuthID, title, content)
break
}
}
}
if !findOneMethod {
err = fmt.Errorf("用户[%s]找不到至少一个有效的通讯方式", userID)
}
if err != nil {
globals.SugarLogger.Infof("SendUserMessage userID:%s, title:%s, content:%s failed with error:%v", userID, title, content, err)
}
return err
}
func SendUsersMessage(msgType string, userIDs []string, title, content string) (err error) {
errList := errlist.New()
for _, userID := range userIDs {
errList.AddErr(SendUserMessage(msgType, userID, title, content))
}
err = errList.GetErrListAsOne()
return err
}

View File

@@ -7,8 +7,8 @@ import (
"time"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/dao"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/globals/refutil"
)

View File

@@ -101,15 +101,12 @@ func (h *Hub) GetToken(tokenType, oldToken string, waitTime time.Duration) (toke
case EventTypeWXToken:
token = api.WeixinAPI.CBGetToken()
case EventTypeYLYToken:
token = api.YilianyunAPI.GetToken()
case EventTypeWeimobToken:
if weimobToken := api.WeimobAPI.GetToken(); weimobToken != nil {
token = string(utils.MustMarshal(weimobToken))
}
case EventTypePushToken:
token = api.PushAPI.CBGetToken()
case EventTypeWX2Token:
token = api.WeixinMiniAPI2.CBGetToken()
}
if token != oldToken {

View File

@@ -7,7 +7,6 @@ import (
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/auth2"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/globals"
)
@@ -25,6 +24,8 @@ type Context struct {
const (
MaxUserNameLen = 30
RsmDefultToken = "rushSkyMonkeyToken_20201203"
)
var (
@@ -72,7 +73,10 @@ func New(notUsed interface{}, token string, w http.ResponseWriter, r *http.Reque
// }
}
if err == model.ErrTokenIsInvalid {
if !globals.IsProductEnv() {
//if !globals.IsProductEnv() {
// err = nil
//} else
if token == RsmDefultToken {
err = nil
} else {
errCode = model.ErrCodeTokenIsInvalid
@@ -158,14 +162,3 @@ func (ctx *Context) GetUserID() (userID string) {
}
return userID
}
func (ctx *Context) GetFullUser() (user *model.User) {
token := ctx.GetToken()
authInfo, err2 := auth2.GetTokenInfo(token)
if err2 == nil {
if authInfo.TokenType == auth2.TokenTypeNormal {
user, _ = dao.GetUserByID(dao.GetDB(), "user_id", authInfo.GetID())
}
}
return user
}

View File

@@ -1,8 +1,6 @@
package jxutils
import (
"bytes"
"context"
"crypto/aes"
"crypto/md5"
"encoding/base64"
@@ -11,19 +9,12 @@ import (
"math"
"math/rand"
"regexp"
"sort"
"strings"
"time"
"git.rosy.net.cn/baseapi"
"git.rosy.net.cn/baseapi/platformapi/autonavi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/baseapi/utils/routinepool"
"git.rosy.net.cn/jx-callback/business/jxutils/excel"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/globals/api"
"github.com/qiniu/api.v7/storage"
)
var (
@@ -42,36 +33,22 @@ var (
model.VendorIDEBAI: []string{
"image-star.elemecdn.com",
},
model.VendorIDYB: []string{
"pospalstoreimg.area27.pospal.cn",
},
}
letterBytes = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
flowUnitMap = map[string]string{
"KB": "KB",
"MB": "MB",
"GB": "GB",
}
)
const fileExt = ".xlsx"
type OrderSkuList []*model.OrderSku
func (l OrderSkuList) Len() int {
return len(l)
}
// Less reports whether the element with
// index i should sort before the element with index j.
func (l OrderSkuList) Less(i, j int) bool {
return l[i].SalePrice < l[j].SalePrice
}
// Swap swaps the elements with indexes i and j.
func (l OrderSkuList) Swap(i, j int) {
tmp := l[i]
l[i] = l[j]
l[j] = tmp
}
func init() {
rand.Seed(time.Now().Unix())
routinePool = routinepool.New(2000, 2000)
routinePool = routinepool.New(1000, 1000)
// Go regex does not support lookarounds.
// https://stackoverflow.com/questions/38933898/error-parsing-regexp-invalid-or-unsupported-perl-syntax
@@ -80,102 +57,20 @@ func init() {
orderNoBeginTimestamp = utils.Str2Time("2010-01-01 00:00:00").Unix()
}
func getJxStoreIDFromOrder(order *model.GoodsOrder) (retVal int) {
if order.JxStoreID != 0 {
return order.JxStoreID
func RandStringBytes(n int) string {
b := make([]byte, n)
for i := range b {
b[i] = letterBytes[rand.Intn(len(letterBytes))]
}
return order.StoreID
return string(b)
}
// 此函数得到的是order的销售门店京西ID与GetJxStoreIDFromOrder的区别是order.StoreID的解释不同参考其它相关资料
func GetSaleStoreIDFromOrder(order *model.GoodsOrder) (retVal int) {
return getJxStoreIDFromOrder(order)
}
// 此函数得到的是order的商品的展示门店京西ID与GetJxStoreIDFromOrder的区别是order.StoreID的解释不同参考其它相关资料
func GetShowStoreIDFromOrder(order *model.GoodsOrder) (retVal int) {
return getJxStoreIDFromOrder(order)
}
func GetSkuIDFromOrderSku(sku *model.OrderSku) (skuID int) {
if sku.JxSkuID > 0 {
return sku.JxSkuID
}
return sku.SkuID
}
func GetSaleStoreIDFromAfsOrder(order *model.AfsOrder) (retVal int) {
if order.JxStoreID > 0 {
return order.JxStoreID
}
return order.StoreID
}
func GetSkuIDFromOrderSkuFinancial(sku *model.OrderSkuFinancial) (skuID int) {
if sku.JxSkuID > 0 {
return sku.JxSkuID
}
return sku.SkuID
}
func SplitUniversalOrderID(universalOrderID string) (orderID string, vendorID int) {
index := strings.Index(universalOrderID, "|")
if index != -1 {
orderID = universalOrderID[:index]
vendorID = int(utils.Str2Int64(universalOrderID[index+1:]))
} else {
if vendorID = GetPossibleVendorIDFromVendorOrderID(universalOrderID); vendorID == model.VendorIDUnknown {
// globals.SugarLogger.Errorf("unkown order type:%v", universalOrderID)
panic(fmt.Sprintf("unkown order type, orderID:%s", universalOrderID))
}
orderID = universalOrderID
}
return orderID, vendorID
}
func GetPossibleVendorIDFromVendorOrderID(vendorOrderID string) (vendorID int) {
vendorID = model.VendorIDUnknown
//if vendorOrderIDInt64 := utils.Str2Int64WithDefault(vendorOrderID, 0); vendorOrderIDInt64 > 0 {
orderIDLen := len(vendorOrderID)
globals.SugarLogger.Debugf("GetPossibleVendorIDFromVendorOrderID, orderIDLen: %v", orderIDLen)
// 5287873015048 13 wsc
// 15380342248732 14 old ebai order
// 800402581000221 15,16 jd order
// 33437032333978492 17 mtwm order
// 3022716176275221584 19 elm order, new ebai order
// 京东到家从2020年开始订单号的长度都会在现有基础上加一位订单号的前两位取的是当年的最后两位数2020取的20以适应业务的发展。
// 改造点:
// 1、订单号位数变化由原有15位数增加1位数调整为16位数对接商家需检查是否有对订单号位数做长度校验。
// 2、第一位数字发生变化由原来9开头调整为当年年份后两位数如2020年订单开头为20
if orderIDLen == len("925265130002541") || orderIDLen == len("1925265130002541") {
vendorID = model.VendorIDJD
} else if orderIDLen == len("3022716176275221584") {
// vendorID = model.VendorIDELM
vendorID = model.VendorIDEBAI // 饿百零售开放平台订单接口中订单ID“order_id”字段长度将调整为19位和饿了么订单ID“eleme_order_id”字段格式保持一致。
} else if orderIDLen == len("15380342248732") {
if vendorOrderID[:2] == "88" {
vendorID = model.VendorIDJX
} else {
vendorID = model.VendorIDEBAI
}
} else if orderIDLen == len("33437032333978492") || orderIDLen == len("116379390766579767") {
vendorID = model.VendorIDMTWM
} else if orderIDLen == len("5287873015048") {
vendorID = model.VendorIDWSC
} else if orderIDLen == len("1000004390") {
vendorID = model.VendorIDJX
} else if orderIDLen == len("18100216009800000001") || orderIDLen == len("191075245758000000039") {
vendorID = model.VendorIDJDShop
}
//} else {
// globals.SugarLogger.Debugf("GetPossibleVendorIDFromVendorOrderID, 2: %v", vendorOrderID)
//}
return vendorID
func GenRand6() (num int) {
return utils.Str2Int(fmt.Sprintf("%06v", rand.New(rand.NewSource(time.Now().UnixNano())).Int31n(1000000)))
}
func GenOrderNo() (orderNo int64) {
const prefix = 88
var prefix = utils.Str2Int64(time.Now().Format("20060102"))
const randPartNum = 1000
orderNo = time.Now().Unix() - orderNoBeginTimestamp
orderNo = orderNo * randPartNum
@@ -189,54 +84,6 @@ func GenOrderNo() (orderNo int64) {
return orderNo
}
func GenAfsOrderNo() (orderNo int64) {
const prefix = 80
const randPartNum = 100
orderNo = time.Now().Unix() - orderNoBeginTimestamp
orderNo = orderNo * randPartNum
md5Bytes := md5.Sum([]byte(utils.GetUUID()))
randPart := 0
for k, v := range md5Bytes {
randPart += int(v) << ((k % 3) * 8)
}
orderNo += int64(randPart % randPartNum)
orderNo += int64(math.Pow10(int(math.Log10(float64(orderNo)))+1)) * prefix
return orderNo
}
func GetPossibleVendorIDFromAfsOrderID(afsOrderID string) (vendorID int) {
vendorID = model.VendorIDUnknown
if afsOrderIDInt64 := utils.Str2Int64WithDefault(afsOrderID, 0); afsOrderIDInt64 > 0 {
orderIDLen := len(afsOrderID)
if orderIDLen == len("22586438") { // 8
vendorID = model.VendorIDJD
} else if orderIDLen == len("1413138834") { // 10
vendorID = model.VendorIDEBAI
} else if orderIDLen == len("29488498752") { // 11
vendorID = model.VendorIDMTWM
}
}
return vendorID
}
func ComposeUniversalOrderID(orderID string, vendorID int) string {
// return fmt.Sprintf("%s|%d", orderID, vendorID)
return orderID // 当前用长度就能区分先不加上vendorID
// return orderID + utils.Int64ToStr(time.Now().Unix())
}
func GetUniversalOrderIDFromWaybill(bill *model.Waybill) string {
return ComposeUniversalOrderID(bill.VendorOrderID, bill.OrderVendorID)
}
func GetUniversalOrderIDFromOrder(order *model.GoodsOrder) string {
return ComposeUniversalOrderID(order.VendorOrderID, order.VendorID)
}
func GetUniversalOrderIDFromOrderStatus(status *model.OrderStatus) string {
return ComposeUniversalOrderID(status.VendorOrderID, status.VendorID)
}
// distance单位为米
func ConvertDistanceToLogLat(lng, lat, distance, angle float64) (newLng, newLat float64) {
oneDu := 111319.55 // 单位为米
@@ -261,36 +108,6 @@ func EarthDistance(lng1, lat1, lng2, lat2 float64) float64 {
return dist * radius
}
// 返回结果单元为公里
func WalkingDistance(lng1, lat1, lng2, lat2 float64) (distance float64) {
if distance = api.AutonaviAPI.WalkingDistance(lng1, lat1, lng2, lat2); distance == 0 {
distance = EarthDistance(lng1, lat1, lng2, lat2) * 1.4
} else {
distance /= 1000
}
return distance
}
//经纬度坐标转换到平面坐标
func MillierConvertion(lat float64, lon float64) [2]float64 {
var L, H, W, temp, mill, x, y float64
L = 6371.393 * math.Pi * 2 //地球周长
W = L // 平面展开后x轴等于周长
H = L / 2 // y轴约等于周长一半
mill = 2.3 // 米勒投影中的一个常数范围大约在正负2.3之间
temp = math.Pi
x = lon * temp / 180 // 将经度从度数转换为弧度
y = lat * temp / 180 // 将纬度从度数转换为弧度
y = 1.25 * math.Log(math.Tan(0.25*temp+0.4*y)) // 米勒投影的转换
// 弧度转为实际距离
x = (W / 2) + (W/(2*math.Pi))*x
y = (H / 2) - (H/(2*mill))*y
x = utils.Str2Float64(fmt.Sprintf("%.2f", x))
y = utils.Str2Float64(fmt.Sprintf("%.2f", y))
var result = [2]float64{x, y}
return result
}
func StandardCoordinate2Int(value float64) int {
return int(math.Round(value * 1000000))
}
@@ -299,25 +116,6 @@ func IntCoordinate2Standard(value int) float64 {
return float64(value) / 1000000
}
func IntCoordinate2MarsStandard(gpsLng, gpsLat int, coordinateType int) (marsLng, marsLat float64, err error) {
marsLng = IntCoordinate2Standard(gpsLng)
marsLat = IntCoordinate2Standard(gpsLat)
coordSys := ""
switch coordinateType {
case model.CoordinateTypeGPS:
coordSys = autonavi.CoordSysGPS
case model.CoordinateTypeMars:
return marsLng, marsLat, nil
case model.CoordinateTypeBaiDu:
coordSys = autonavi.CoordSysBaidu
case model.CoordinateTypeMapbar:
coordSys = autonavi.CoordSysMapbar
default:
panic(fmt.Sprintf("known coordinate type:%d", coordinateType))
}
return api.AutonaviAPI.CoordinateConvert(marsLng, marsLat, coordSys)
}
func IntPrice2Standard(value int64) float64 {
return float64(value) / 100
}
@@ -420,7 +218,7 @@ func ComposeSkuNameOriginal(prefix, name, comment, unit string, spec_quality flo
return skuName
}
func ComposeSkuNameForMTWM(prefix, name, comment, unit string, spec_quality float32, spec_unit string, maxLen int) (skuName string) {
func ComposeSkuNameForJds(prefix, name, comment, unit string, spec_quality float32, spec_unit string, maxLen int) (skuName string) {
strBuilder := &strings.Builder{}
if prefix != "" {
strBuilder.WriteString("[")
@@ -429,16 +227,15 @@ func ComposeSkuNameForMTWM(prefix, name, comment, unit string, spec_quality floa
}
skuName += name
strBuilder.WriteString(name)
strBuilder.WriteString("")
if comment != "" {
strBuilder.WriteString(" ")
strBuilder.WriteString(comment)
}
if unit == "份" {
strBuilder.WriteString("约")
}
if unit != "" {
strBuilder.WriteString(ComposeSkuSpec(spec_quality, spec_unit))
strBuilder.WriteString("/")
strBuilder.WriteString(unit)
}
if comment != "" {
strBuilder.WriteString("(")
strBuilder.WriteString(comment)
strBuilder.WriteString(")")
}
skuName = strBuilder.String()
if maxLen > 0 {
@@ -457,12 +254,10 @@ func ComposeSkuName(prefix, name, comment, unit string, spec_quality float32, sp
return skuName
}
func ComposeSkuNameSync(prefix, name, comment, unit string, spec_quality float32, spec_unit string, maxLen int, exPrefix string, exPrefixBegin, exPrefixEnd *time.Time, isEx bool) (skuName string) {
func ComposeSkuNameSync(prefix, name, comment, unit string, spec_quality float32, spec_unit string, maxLen int, exPrefix string, exPrefixBegin, exPrefixEnd *time.Time) (skuName string) {
if exPrefix != "" && exPrefixBegin != nil && exPrefixEnd != nil {
if utils.Time2Date(time.Now().Add(6*time.Hour)).Sub(*exPrefixBegin) >= 0 && utils.Time2Date(time.Now()).Sub(*exPrefixEnd) <= 0 {
if isEx {
skuName = exPrefix
}
skuName = exPrefix
}
if utils.Time2Date(time.Now().Add(6*time.Hour)).Sub(*exPrefixEnd) > 0 {
skuName = ""
@@ -472,18 +267,16 @@ func ComposeSkuNameSync(prefix, name, comment, unit string, spec_quality float32
return skuName
}
func ComposeSkuNameSync2(prefix, name, comment, unit string, spec_quality float32, spec_unit string, maxLen int, exPrefix string, exPrefixBegin, exPrefixEnd *time.Time, isEx bool) (skuName string) {
func ComposeSkuNameSync2(prefix, name, comment, unit string, spec_quality float32, spec_unit string, maxLen int, exPrefix string, exPrefixBegin, exPrefixEnd *time.Time) (skuName string) {
if exPrefix != "" && exPrefixBegin != nil && exPrefixEnd != nil {
if utils.Time2Date(time.Now().Add(6*time.Hour)).Sub(*exPrefixBegin) >= 0 && utils.Time2Date(time.Now()).Sub(*exPrefixEnd) <= 0 {
if isEx {
skuName = exPrefix
}
skuName = exPrefix
}
if utils.Time2Date(time.Now().Add(6*time.Hour)).Sub(*exPrefixEnd) > 0 {
skuName = ""
}
}
skuName += ComposeSkuNameForMTWM(prefix, name, comment, unit, spec_quality, spec_unit, maxLen)
skuName += ComposeSkuNameForJds(prefix, name, comment, unit, spec_quality, spec_unit, maxLen)
return skuName
}
@@ -584,7 +377,7 @@ func MakeValidationMapFromSlice(validValues []string, flag int) map[string]int {
}
func ComposeQiniuResURL(key string) string {
return "http://image.jxc4.com/" + key
return "https://image.jxc4.com/" + key
}
func IsLegalMobileNumber(num int64) bool {
@@ -624,151 +417,6 @@ func Strings2Objs(strAndObjAddPairs ...interface{}) (err error) {
return nil
}
func RefreshOrderSkuRelated(order *model.GoodsOrder) *model.GoodsOrder {
order.SkuCount = 0
order.GoodsCount = 0
order.SalePrice = 0
order.VendorPrice = 0
order.ShopPrice = 0
order.Weight = 0
order.EarningPrice = 0
for _, sku := range order.Skus {
if sku.SkuID > math.MaxInt32 {
sku.SkuID = sku.JxSkuID
}
sku.OrderCreatedAt = order.OrderCreatedAt
sku.VendorID = order.VendorID
sku.VendorOrderID = order.VendorOrderID
order.SkuCount++
order.GoodsCount += sku.Count
order.SalePrice += sku.SalePrice * int64(sku.Count)
order.VendorPrice += sku.VendorPrice * int64(sku.Count)
order.ShopPrice += sku.ShopPrice * int64(sku.Count)
order.EarningPrice += sku.EarningPrice * int64(sku.Count)
order.Weight += sku.Weight * sku.Count
}
return order
}
func RefreshOrderEarningPrice2(order *model.GoodsOrder, payPercentage int) *model.GoodsOrder {
if order.EarningType == model.EarningTypePoints {
// if order.VendorID == model.VendorIDJDShop || order.VendorID == model.VendorIDJX {
// order.NewEarningPrice = order.TotalShopMoney * int64((100 - payPercentage)) / 100
// } else {
order.NewEarningPrice = order.TotalShopMoney * int64((100 - payPercentage/2)) / 100
// }
} else {
order.NewEarningPrice = order.EarningPrice
}
return order
}
func RefreshOrderEarningPrice3(order *model.GoodsOrder, payPercentage int, bill *model.Waybill) *model.GoodsOrder {
if order.EarningType == model.EarningTypePoints {
// if order.VendorID == model.VendorIDJDShop || order.VendorID == model.VendorIDJX {
// order.NewEarningPrice = (order.TotalShopMoney - bill.DesiredFee) * int64((100 - payPercentage)) / 100
// } else {
order.NewEarningPrice = order.TotalShopMoney*int64((100-payPercentage/2))/100 - bill.DesiredFee
// }
} else {
order.NewEarningPrice = order.EarningPrice
}
return order
}
func RefreshAfsOrderSkuRelated(afsOrder *model.AfsOrder) *model.AfsOrder {
afsOrder.SkuUserMoney = 0
afsOrder.PmSkuSubsidyMoney = 0
for _, orderSku := range afsOrder.Skus {
if orderSku.SkuID > math.MaxInt32 {
orderSku.SkuID = orderSku.JxSkuID
}
afsOrder.SkuUserMoney += orderSku.UserMoney
afsOrder.PmSkuSubsidyMoney += orderSku.PmSkuSubsidyMoney
}
return afsOrder
}
func RemoveSkuFromOrder(order *model.GoodsOrder, removedSkuList []*model.OrderSku) *model.GoodsOrder {
removedSkuMap := make(map[int]*model.OrderSku)
removedSkuMap2 := make(map[string]*model.OrderSku)
for _, sku := range removedSkuList {
if skuID := GetSkuIDFromOrderSku(sku); skuID > 0 {
if removedSkuMap[skuID] == nil {
removedSkuMap[skuID] = sku
} else {
removedSkuMap[skuID].Count += sku.Count
}
}
if vendorSkuID := sku.VendorSkuID; vendorSkuID != "" {
if removedSkuMap2[vendorSkuID] == nil {
removedSkuMap2[vendorSkuID] = sku
} else {
removedSkuMap2[vendorSkuID].Count += sku.Count
}
}
}
var skuList []*model.OrderSku
sort.Sort(sort.Reverse(OrderSkuList(order.Skus)))
for _, sku := range order.Skus {
var removedSku *model.OrderSku
if skuID := GetSkuIDFromOrderSku(sku); skuID > 0 {
removedSku = removedSkuMap[skuID]
}
if removedSku == nil {
if vendorSkuID := sku.VendorSkuID; vendorSkuID != "" {
removedSku = removedSkuMap2[vendorSkuID]
}
}
copiedSku := *sku
tmp := &copiedSku
if removedSku != nil {
if removedSku.Count >= sku.Count {
tmp = nil
removedSku.Count -= sku.Count
} else {
tmp.Count -= removedSku.Count
removedSku.Count = 0
}
}
if tmp != nil {
skuList = append(skuList, tmp)
}
}
order.Skus = skuList
return RefreshOrderSkuRelated(order)
}
func UploadExportContent(content []byte, key string) (downloadURL string, err error) {
putPolicy := storage.PutPolicy{
Scope: globals.QiniuBucket,
Expires: 10 * 60,
DeleteAfterDays: 1,
}
upToken := putPolicy.UploadToken(api.QiniuAPI)
cfg := &storage.Config{}
formUploader := storage.NewFormUploader(cfg)
ret := storage.PutRet{}
for i := 0; i < 3; i++ {
if err = formUploader.Put(context.Background(), &ret, upToken, key, bytes.NewReader(content), int64(len(content)), &storage.PutExtra{}); err == nil {
break
}
}
if err == nil {
downloadURL = ComposeQiniuResURL(key)
}
return downloadURL, err
}
func UploadExeclAndPushMsg(sheetList []*excel.Obj2ExcelSheetConfig, name string) (downloadURL, fileName string, err error) {
excelBin := excel.Obj2Excel(sheetList)
timeStr := utils.Int64ToStr(time.Now().Unix())
fileName = name + timeStr + fileExt
baseapi.SugarLogger.Debugf("WriteToExcel:save %s success", fileName)
downloadURL, err = UploadExportContent(excelBin, fileName)
return downloadURL, fileName, err
}
func TaskResult2Hint(resultList []interface{}) (hint string) {
strList := make([]string, len(resultList))
for k, v := range resultList {
@@ -826,42 +474,15 @@ func OperationTime2Str2(openTime, closeTime int16) (str string) {
return str
}
func OperationTimeStr4VendorStore(v *model.VendorStoreSnapshot) (str string) {
str = fmt.Sprintf("%s", OperationTime2Str2(v.OpenTime1, v.CloseTime1))
if v.OpenTime2 > 0 && v.CloseTime2 > 0 {
str += fmt.Sprintf(",%s", OperationTime2Str2(v.OpenTime2, v.CloseTime2))
}
return str
}
func OperationTime2HourMinuteFormat(time time.Time) (i int16) {
return int16(time.Hour()*100 + time.Minute())
}
// 得到饿百订单的取货码
func GetEbaiOrderGetCode(order *model.GoodsOrder) (getCode string) {
if order.VendorID == model.VendorIDEBAI && len(order.VendorOrderID2) >= 4 {
getCode = order.VendorOrderID2[len(order.VendorOrderID2)-4:]
}
return getCode
}
func WriteFile(fileName string, binData []byte) error {
err := ioutil.WriteFile(fileName, binData, 0666)
return err
}
func GetRealMobile4Order(order *model.GoodsOrder) (mobileNumber string) {
mobileNumber = order.ConsigneeMobile2
if mobileNumber == "" {
mobileNumber = order.ConsigneeMobile
}
if !IsStringLikeMobile(mobileNumber) {
mobileNumber = ""
}
return mobileNumber
}
func GuessDataResourceVendor(resourceURL string) (vendorID int) {
vendorID = -1
for tmpVendorID, urlList := range resourceTypeMap {
@@ -924,30 +545,23 @@ func GetOneEmailFromStr(str string) (email string) {
// 计算一个坐标点距离一个门店的距离单位为米如果不在有效范围内则返回0
func Point2StoreDistance(lng, lat float64, intStoreLng, intStoreLat int, deliveryRangeType int8, deliveryRange string) (distance int) {
storeLng := IntCoordinate2Standard(intStoreLng)
storeLat := IntCoordinate2Standard(intStoreLat)
if deliveryRangeType == model.DeliveryRangeTypeRadius {
maxDistance := int(utils.Str2Int64WithDefault(deliveryRange, 0))
distance = int(EarthDistance(lng, lat, storeLng, storeLat) * 1000)
if distance > maxDistance {
distance = 0
}
} else {
points := CoordinateStr2Points(deliveryRange)
if utils.IsPointInPolygon(lng, lat, points) {
distance = int(EarthDistance(lng, lat, storeLng, storeLat) * 1000)
}
}
// storeLng := IntCoordinate2Standard(intStoreLng)
// storeLat := IntCoordinate2Standard(intStoreLat)
// if deliveryRangeType == model.DeliveryRangeTypeRadius {
// maxDistance := int(utils.Str2Int64WithDefault(deliveryRange, 0))
// distance = int(EarthDistance(lng, lat, storeLng, storeLat) * 1000)
// if distance > maxDistance {
// distance = 0
// }
// } else {
// points := CoordinateStr2Points(deliveryRange)
// if utils.IsPointInPolygon(lng, lat, points) {
// distance = int(EarthDistance(lng, lat, storeLng, storeLat) * 1000)
// }
// }
return distance
}
func TranslateStorePriceType(storePriceType int8) int8 {
if storePriceType == model.StoreChangePriceTypeManagedStore {
storePriceType = model.StoreChangePriceTypeBossDisabled
}
return storePriceType
}
func TranslateSoundSize(vendorID, soundPercentage int) (soundSize string) {
if vendorID == model.VendorIDYiLianYun || vendorID == model.VendorIDFeiE {
if soundPercentage == 0 {
@@ -962,25 +576,6 @@ func TranslateSoundSize(vendorID, soundPercentage int) (soundSize string) {
if soundPercentage > 66 && soundPercentage <= 100 {
soundSize = "3"
}
} else if vendorID == model.VendorIDJxprint {
if soundPercentage == 0 {
soundSize = "0"
}
if soundPercentage > 0 && soundPercentage <= 20 {
soundSize = "1"
}
if soundPercentage > 20 && soundPercentage <= 40 {
soundSize = "2"
}
if soundPercentage > 40 && soundPercentage <= 60 {
soundSize = "3"
}
if soundPercentage > 60 && soundPercentage <= 80 {
soundSize = "4"
}
if soundPercentage > 80 && soundPercentage <= 100 {
soundSize = "5"
}
}
return soundSize
}
@@ -1017,43 +612,9 @@ func PKCS5UnPadding(origData []byte) []byte {
return origData[:(length - unpadding)]
}
//合成水印图
func MixWatermarkImg(imgWatermark, img string, exPrefixBegin, exPrefixEnd *time.Time) (imgMix string) {
if exPrefixBegin != nil && exPrefixEnd != nil {
if utils.Time2Date(time.Now().Add(6*time.Hour)).Sub(*exPrefixBegin) >= 0 && utils.Time2Date(time.Now()).Sub(*exPrefixEnd) <= 0 {
baseURL := base64.URLEncoding.EncodeToString([]byte(imgWatermark))
var imgUrl string
if strings.Contains(img, "?") {
imgUrl = img + "/imageView2/0/q/75|watermark/1/image/" + baseURL + "/dissolve/100/gravity/Center/dx/0/dy/0"
} else {
imgUrl = img + "?imageView2/0/q/75|watermark/1/image/" + baseURL + "/dissolve/100/gravity/Center/dx/0/dy/0"
}
if resBinary, _, err := DownloadFileByURL(imgUrl); err == nil {
if downloadURL, err := UploadExportContent(resBinary, utils.Int64ToStr(time.Now().Unix())+img[strings.LastIndex(img, "/")+1:len(img)]); err == nil {
if err == nil {
return downloadURL
}
}
}
}
if utils.Time2Date(time.Now().Add(6*time.Hour)).Sub(*exPrefixEnd) > 0 {
return imgMix
}
}
return imgMix
}
func GetDefendPriceIssue() (issue int) {
if time.Now().Hour() >= 22 {
issue = utils.Str2Int(time.Now().AddDate(0, 0, 1).Format("20060102"))
} else {
issue = utils.Str2Int(time.Now().Format("20060102"))
}
return issue
}
func GetLastDefendPriceIssue() (issue int) {
return utils.Str2Int(time.Now().AddDate(0, 0, 1).Format("20060102"))
func GetIssue() (issue int) {
year, month, _ := time.Now().Date()
return year*100 + int(month)
}
//根据一堆坐标求面积
@@ -1086,16 +647,74 @@ func polarTriangleArea(tan1, lng1, tan2, lng2 float64) (s float64) {
return 2 * math.Atan2(t*math.Sin(deltaLng), 1+t*math.Cos(deltaLng))
}
func IntListToStrList(i []int) (s []string) {
for _, v := range i {
s = append(s, utils.Int2Str(v))
func GenRandomString(l int) string {
str := "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
bytes := []byte(str)
result := []byte{}
r := rand.New(rand.NewSource(time.Now().UnixNano()))
for i := 0; i < l; i++ {
result = append(result, bytes[r.Intn(len(bytes))])
}
return s
return string(result)
}
func StrListToIntList(s []string) (i []int) {
for _, v := range s {
i = append(i, utils.Str2Int(v))
}
return i
func GetDayTime() (dayTimeBegin, dayTimeEnd time.Time) {
dayTimeBegin = utils.Str2Time(utils.Time2Str(utils.Time2Date(time.Now())) + " 00:00:00")
dayTimeEnd = dayTimeBegin.AddDate(0, 0, 1)
return dayTimeBegin, dayTimeEnd
}
func GetWeekTime() (weekTimeBegin, weekTimeEnd time.Time) {
offset := int(time.Now().Weekday() - 1)
if offset == -1 {
offset = -6
}
weekTimeBegin = time.Now().AddDate(0, 0, offset)
weekTimeEnd = weekTimeBegin.AddDate(0, 0, 7)
return weekTimeBegin, weekTimeEnd
}
func BuildErr(errs []error) (err error) {
var errStr = strings.Builder{}
for _, v := range errs {
errStr.WriteString(v.Error())
}
return fmt.Errorf(errStr.String())
}
func SplitFlowAndUnit(flowStr string) (flow float64, unit string) {
for _, v := range flowUnitMap {
if strings.Contains(flowStr, v) {
return utils.Str2Float64WithDefault(flowStr[:len(flowStr)-2], 0), flowStr[len(flowStr)-2:]
}
}
return flow, unit
}
func Flow2KB(flow float64, unit string) (flowKB float64) {
if unit == "KB" {
return flow
} else if unit == "MB" {
return flow * 1024
} else if unit == "GB" {
return flow * 1024 * 1024
}
return flowKB
}
func FlowKB2Other(flowKB float64) (flow float64, unit string) {
if flowKB < 1024 {
return flowKB, "KB"
} else {
flowMB := math.Round(flowKB / float64(1024))
if flowMB < 1024 {
return flowMB, "MB"
} else {
flowGB := math.Round(flowMB / float64(1024))
if flowGB < 1024 {
return flowGB, "GB"
}
}
}
return flow, unit
}

View File

@@ -1,41 +0,0 @@
package jxutils
import (
"git.rosy.net.cn/jx-callback/business/model"
)
type ActStoreSkuMap struct {
actStoreSkuMap map[int64]map[int]*model.ActStoreSku2
}
// isActPrice为true表示是活动false表示是结算
func NewActStoreSkuMap(actStoreSkuList []*model.ActStoreSku2, isActPrice bool) (actMap *ActStoreSkuMap) {
actMap = &ActStoreSkuMap{}
actStoreSkuMap := make(map[int64]map[int]*model.ActStoreSku2)
for _, v := range actStoreSkuList {
index := Combine2Int(v.StoreID, v.SkuID)
if actStoreSkuMap[index] == nil {
actStoreSkuMap[index] = make(map[int]*model.ActStoreSku2)
}
if (isActPrice && v.ActualActPrice > 0 && (actStoreSkuMap[index][v.VendorID] == nil || actStoreSkuMap[index][v.VendorID].ActualActPrice > v.ActualActPrice)) ||
(!isActPrice && v.EarningPrice > 0 && (actStoreSkuMap[index][v.VendorID] == nil || actStoreSkuMap[index][v.VendorID].EarningPrice > v.EarningPrice)) {
actStoreSkuMap[index][v.VendorID] = v
}
}
actMap.actStoreSkuMap = actStoreSkuMap
return actMap
}
func (a *ActStoreSkuMap) GetActStoreSku(storeID, skuID, vendorID int) (storeSku *model.ActStoreSku2) {
index := Combine2Int(storeID, skuID)
if a.actStoreSkuMap[index] != nil {
if vendorID < 0 {
for k := range a.actStoreSkuMap[index] {
vendorID = k
break
}
}
storeSku = a.actStoreSkuMap[index][vendorID]
}
return storeSku
}

Some files were not shown because too many files have changed in this diff Show More