1175 Commits
jdshop ... api

Author SHA1 Message Date
邹宗楠
5e987ac99e 1 2023-03-21 18:29:04 +08:00
邹宗楠
99a073484b 1 2023-03-21 18:22:19 +08:00
邹宗楠
831a860ce2 饿百订单打印失败 2023-03-21 17:30:10 +08:00
邹宗楠
610a7feeca 1 2023-02-24 14:51:32 +08:00
邹宗楠
6275b14570 1 2022-12-30 10:22:52 +08:00
邹宗楠
b2bf89996f 1 2022-12-30 09:50:19 +08:00
邹宗楠
7b8be18bd6 1 2022-12-30 09:48:24 +08:00
邹宗楠
14b55e118c 1 2022-12-29 18:35:46 +08:00
邹宗楠
fe59f8bca7 1 2022-12-27 14:07:48 +08:00
邹宗楠
ede900560d 1 2022-12-27 14:02:33 +08:00
邹宗楠
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
525 changed files with 4532 additions and 270420 deletions

2
.gitignore vendored
View File

@@ -2,6 +2,7 @@
jx-callback jx-callback
*.tmp *.tmp
swagger/
debug debug
.DS_Store .DS_Store
*.log *.log
@@ -15,4 +16,3 @@ param_parser.go
*.exe~ *.exe~
.vscode .vscode
.idea .idea
./swagger

View File

@@ -1,32 +0,0 @@
package app_version
import (
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
)
// AddApplicationVersion 添加app版本控制
func AddApplicationVersion(userName, appId, version string) error {
config := &model.NewConfig{
Type: model.ConfigTypeApplication,
Key: appId,
Value: version,
}
dao.WrapAddIDCULDEntity(config, userName)
return dao.CreateEntity(dao.GetDB(), config)
}
// UpdateApplicationVersion 修改app版本
func UpdateApplicationVersion(appId, version string) error {
sql := ` UPDATE new_config c SET c.value = ? WHERE c.key = ? AND c.deleted_at = ? `
param := []interface{}{version, appId, utils.DefaultTimeValue}
_, err := dao.ExecuteSQL(dao.GetDB(), sql, param...)
return err
}
// GetApplicationVersion 查询小程序版本控制
func GetApplicationVersion(appId string) ([]*model.NewConfig, error) {
return dao.QueryConfigs(dao.GetDB(), appId, model.ConfigTypeApplication, "")
}

View File

@@ -3,15 +3,16 @@ package auth2
import ( import (
"bytes" "bytes"
"encoding/base64" "encoding/base64"
"encoding/json"
"errors" "errors"
"fmt"
"regexp" "regexp"
"strings" "strings"
"time" "time"
"git.rosy.net.cn/baseapi/utils" "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"
"git.rosy.net.cn/jx-callback/business/model/dao" "git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/globals/api" "git.rosy.net.cn/jx-callback/globals/api"
"github.com/dchest/captcha" "github.com/dchest/captcha"
) )
@@ -32,18 +33,15 @@ const (
) )
const ( const (
AuthTypeNone = "" AuthTypeNone = ""
AuthTypePassword = "localpass" AuthTypePassword = "localpass"
AuthTypeEmail = "email" AuthTypeEmail = "email"
AuthTypeMobile = "mobile" AuthTypeMobile = "mobile"
AuthTypeWXApp = "weixinapp" //微信小程序(商家版)
AuthTypeWXAppCaishi = "weixinappcs" //微信小程序(用户)
AuthTypeWXMini = "weixinmini" //微信小程序
) )
const ( const (
DefTokenDuration = 7 * 24 * 2 * time.Hour // 正式TOKEN7天有效期 DefTokenDuration = 7 * 24 * time.Hour // 正式TOKEN7天有效期
TmpTokenDuration = 30 * time.Minute // 临时TOKEN30分钟有效期 TmpTokenDuration = 30 * time.Minute // 临时TOKEN30分钟有效期
MinCaptchaLen = 4 MinCaptchaLen = 4
MaxCaptchaWidth = 400 MaxCaptchaWidth = 400
MaxCaptchaHeight = 400 MaxCaptchaHeight = 400
@@ -64,7 +62,6 @@ const (
UpdateUserTypeAdd = 1 UpdateUserTypeAdd = 1
UpdateUserTypeDelete = 2 UpdateUserTypeDelete = 2
UpdateUserTypeUpdate = 3 UpdateUserTypeUpdate = 3
WeCartAppID = "wx4b5930c13f8b1170"
) )
type IUserProvider interface { type IUserProvider interface {
@@ -162,7 +159,6 @@ func getFixedTokenName(token string) *AuthInfo {
func createAuthInfo(user IUser, authBindInfo *AuthBindEx) (authInfo *AuthInfo) { func createAuthInfo(user IUser, authBindInfo *AuthBindEx) (authInfo *AuthInfo) {
token, tokenType := createToken(user, authBindInfo) token, tokenType := createToken(user, authBindInfo)
//user为空 tokenType=2
expireDuration := DefTokenDuration expireDuration := DefTokenDuration
authInfo = &AuthInfo{ authInfo = &AuthInfo{
AuthBindInfo: authBindInfo, AuthBindInfo: authBindInfo,
@@ -173,9 +169,11 @@ func createAuthInfo(user IUser, authBindInfo *AuthBindEx) (authInfo *AuthInfo) {
} }
if user != nil { if user != nil {
authInfo.UpdateByIUser(user) authInfo.UpdateByIUser(user)
globals.SugarLogger.Debugf("createAuthInfo id:%s, id2:%s, mobile:%s, authInfo:%s", authInfo.GetID(), authInfo.GetID2(), authInfo.GetMobile(), utils.Format4Output(authInfo, true))
} else { } else {
expireDuration = TmpTokenDuration expireDuration = TmpTokenDuration
authInfo.ExpiresAt = time.Now().Add(expireDuration).Unix() authInfo.ExpiresAt = time.Now().Add(expireDuration).Unix()
globals.SugarLogger.Debugf("createAuthInfo authInfo:%s", utils.Format4Output(authInfo, true))
} }
SetUserInfo(token, authInfo, expireDuration) SetUserInfo(token, authInfo, expireDuration)
return authInfo return authInfo
@@ -215,9 +213,6 @@ func SendVerifyCode(authToken, captchaID, captchaValue, authID string) (verfifyC
if handler := authers[authType]; handler == nil { if handler := authers[authType]; handler == nil {
err = ErrIllegalAuthType err = ErrIllegalAuthType
} else { } else {
//if user, _ := dao.GetUserByID(dao.GetDB(), "mobile", authID); user != nil {
// return "", authInfo, fmt.Errorf("该用户已存在,请勿重复注册!")
//}
verfifyCode, err = handler.SendVerifyCode(authID) verfifyCode, err = handler.SendVerifyCode(authID)
} }
} }
@@ -248,8 +243,7 @@ func LoginInternal(ctx *Context, authType, authID, authIDType, authSecret string
} }
realAuthID = user.GetID() realAuthID = user.GetID()
} }
authBindEx, err = handler.VerifySecret(realAuthID, authSecret) if authBindEx, err = handler.VerifySecret(realAuthID, authSecret); err == nil {
if err == nil {
if authBindEx == nil { // mobile, email会返回nil表示不会新建AuthBind实体 if authBindEx == nil { // mobile, email会返回nil表示不会新建AuthBind实体
user = userProvider.GetUser(authID, authIDType) user = userProvider.GetUser(authID, authIDType)
authBindEx = &AuthBindEx{ authBindEx = &AuthBindEx{
@@ -263,18 +257,15 @@ func LoginInternal(ctx *Context, authType, authID, authIDType, authSecret string
// 返回authBind中UserID为空表示只是认证但本地没有记录这种情况会返回临时TOKEN // 返回authBind中UserID为空表示只是认证但本地没有记录这种情况会返回临时TOKEN
if authBindEx.UserHint != nil && authBindEx.UserID == "" { if authBindEx.UserHint != nil && authBindEx.UserID == "" {
// 利用得到受信任的信息查找用户 // 利用得到受信任的信息查找用户
if authBindEx.UserHint.Mobile != "" { // if authBindEx.UserHint.Mobile != "" {
user = userProvider.GetUser(authBindEx.UserHint.Mobile, UserIDMobile) // user = userProvider.GetUser(authBindEx.UserHint.Mobile, UserIDMobile)
} // }
if user == nil && authBindEx.UserHint.Email != "" { // if user == nil && authBindEx.UserHint.Email != "" {
user = userProvider.GetUser(authBindEx.UserHint.Email, UserIDEmail) // user = userProvider.GetUser(authBindEx.UserHint.Email, UserIDEmail)
} // }
if user != nil { // if user != nil {
authBindEx.UserID = user.GetID() // authBindEx.UserID = user.GetID()
} // }
if user2 := userProvider.GetUser(authBindEx.UserHint.Email, UserIDMobile); user2 != nil {
user = user2
}
} else if authBindEx.UserID != "" { } else if authBindEx.UserID != "" {
user = userProvider.GetUser(authBindEx.UserID, UserIDID) user = userProvider.GetUser(authBindEx.UserID, UserIDID)
} }
@@ -284,12 +275,11 @@ func LoginInternal(ctx *Context, authType, authID, authIDType, authSecret string
userProvider.UpdateLastLogin(user.GetID(), authType, ctx.GetRealRemoteIP()) userProvider.UpdateLastLogin(user.GetID(), authType, ctx.GetRealRemoteIP())
} }
//如果是小程序 //如果是小程序
if authType == AuthTypeWXMini { // || authType == AuthTypeWXApp 此处AuthTypeWXApp没用上 if authType == "weixinmini" || authType == "weixinapp" {
appID := strings.Split(authSecret, ",")[0] appID := strings.Split(authSecret, ",")[0]
// 菜市商家 // // // 京西商城 if appID == "wxa4a76d7b4c88604e" || appID == "wx2d6949f724b2541d" || appID == "wx18111a41fd17f24f" { //菜市或者果园
if appID == model.JXC4BusinessAppId || appID == "wx2d6949f724b2541d" || appID == "wx18111a41fd17f24f" || appID == model.JXC4AppId { //菜市或者果园 if user != nil {
if authInfo.AuthBindInfo.UserID != "" { binds, err := dao.GetUserBindAuthInfo(dao.GetDB(), user.GetID(), 0, nil, "", "", "wx2bb99eb5d2c9b82c")
binds, err := dao.GetUserBindAuthInfo(dao.GetDB(), authInfo.AuthBindInfo.UserID, 0, nil, "", "", []string{"wx2bb99eb5d2c9b82c", "wx4b5930c13f8b1170"})
if err != nil { if err != nil {
return authInfo, err return authInfo, err
} }
@@ -298,29 +288,9 @@ func LoginInternal(ctx *Context, authType, authID, authIDType, authSecret string
} else { } else {
authInfo.IsExistOpenID = true authInfo.IsExistOpenID = true
} }
if WeCartAppID == appID {
authInfo.AppID = WeCartAppID
}
} }
} }
} }
//微信APP端登录
if authType == AuthTypeWXApp || authType == AuthTypeWXAppCaishi {
appID := strings.Split(authSecret, ",")[0]
if appID == model.JXC4ClientAppID && authInfo.AuthBindInfo.UserID != "" {
binds, err := dao.GetUserBindAuthInfo(dao.GetDB(), authInfo.AuthBindInfo.UserID, 0, nil, "", "", []string{model.JXC4ClientAppID})
if err != nil {
return authInfo, err
}
if len(binds) == 0 {
authInfo.IsExistOpenID = false
} else {
authInfo.IsExistOpenID = true
}
authInfo.AppID = model.JXC4ClientAppID
}
}
} }
} else { } else {
err = ErrIllegalAuthType err = ErrIllegalAuthType
@@ -335,59 +305,6 @@ func Login(ctx *Context, authType, authID, authIDType, authSecret string) (authI
return LoginInternal(ctx, authType, authID, authIDType, authSecret) return LoginInternal(ctx, authType, authID, authIDType, authSecret)
} }
// TikTokDecryptInfo 抖音用户信息解密
type TikTokDecryptInfo struct {
CountryCode string `json:"countryCode"`
PhoneNumber string `json:"phoneNumber"`
PurePhoneNumber string `json:"purePhoneNumber"`
Watermark *struct {
AppID string `json:"appid"`
Timestamp int64 `json:"timestamp"`
} `json:"watermark"`
}
// KuaiShouInfo 抖音用户信息解密
type KuaiShouInfo struct {
CountryCode string `json:"countryCode"`
PhoneNumber string `json:"phoneNumber"`
}
func DecryptUserMsg(sessionKey, iv, msg, loginType string) (string, error) {
decodeMsg, err := base64.StdEncoding.DecodeString(msg)
if err != nil {
return "", err
}
decodeIv, err := base64.StdEncoding.DecodeString(iv)
if err != nil {
return "", err
}
decodeSessionKey, err := base64.StdEncoding.DecodeString(sessionKey)
if err != nil {
return "", err
}
userInfo, err := utils.AESCBC16Decrypt(decodeSessionKey, decodeIv, decodeMsg)
if err != nil {
return "", err
}
switch loginType {
case "tiktokmini":
result := &TikTokDecryptInfo{}
if err := json.Unmarshal(userInfo, result); err != nil {
return "", err
}
return result.PhoneNumber, nil
case "kuaishoumini":
result := &KuaiShouInfo{}
if err := json.Unmarshal(userInfo, result); err != nil {
return "", err
}
return result.PhoneNumber, nil
}
return "", ErrIllegalAuthType
}
// 通过临时TOKEN绑定新创建的用户 // 通过临时TOKEN绑定新创建的用户
func BindUser(inauthInfo *AuthInfo, user IUser) (outauthInfo *AuthInfo, err error) { func BindUser(inauthInfo *AuthInfo, user IUser) (outauthInfo *AuthInfo, err error) {
if err = AddAuthBind(user, inauthInfo); err == nil { if err = AddAuthBind(user, inauthInfo); err == nil {
@@ -399,6 +316,7 @@ func BindUser(inauthInfo *AuthInfo, user IUser) (outauthInfo *AuthInfo, err erro
// 添加新绑定 // 添加新绑定
func AddAuthBind(user IUser, newAuthInfo *AuthInfo) (err error) { func AddAuthBind(user IUser, newAuthInfo *AuthInfo) (err error) {
globals.SugarLogger.Debugf("AddAuthBind user:%s, newAuthInfo:%s", utils.Format4Output(user, true), utils.Format4Output(newAuthInfo, true))
if user == nil || newAuthInfo == nil { if user == nil || newAuthInfo == nil {
return ErrInternalErrror return ErrInternalErrror
} }
@@ -422,22 +340,8 @@ func AddAuthBind(user IUser, newAuthInfo *AuthInfo) (err error) {
return err return err
} }
func AddAuthBindWithMobile(authInfo *AuthInfo, mobile string) (err error) {
if handler := authers[authInfo.AuthBindInfo.Type]; handler != nil {
user, err := dao.GetUserByID(dao.GetDB(), "mobile", mobile)
if err != nil {
return errors.New("此接口有执行顺序请先调用注册登录接口【第一步Login第二步TiktokDecrypt】")
}
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) { 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 { if handler := authers[authType]; handler != nil {
err = handler.UnbindAuth(userID, authType, authTypeID, userName) err = handler.UnbindAuth(userID, authType, authTypeID, userName)
} else { } else {
@@ -447,6 +351,7 @@ func UnbindAuth(userID, authType, authTypeID, userName string) (err error) {
} }
func Logout(authInfo *AuthInfo) (err error) { func Logout(authInfo *AuthInfo) (err error) {
globals.SugarLogger.Debugf("Logout authInfo:%s", utils.Format4Output(authInfo, true))
if handler := authers[authInfo.AuthBindInfo.Type]; handler != nil { if handler := authers[authInfo.AuthBindInfo.Type]; handler != nil {
err = handler.Logout(authInfo) err = handler.Logout(authInfo)
} }
@@ -488,6 +393,8 @@ func ClearUserToken(userID string) {
} }
} }
/////////////
func createToken(user IUser, authBindInfo *AuthBindEx) (token string, tokenType int) { func createToken(user IUser, authBindInfo *AuthBindEx) (token string, tokenType int) {
userID := TokenUserEmpty userID := TokenUserEmpty
userName := authBindInfo.AuthID userName := authBindInfo.AuthID
@@ -556,7 +463,7 @@ func DisableUser(userID, operatorUserName string) (err error) {
} }
func GetUserBindAuthInfo(userID string) (authList []*model.AuthBind, 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) { func DeletedTokenInfoWithoutParam(authInfo *AuthInfo) (err error) {
@@ -569,3 +476,16 @@ func DeletedTokenInfoWithoutParam(authInfo *AuthInfo) (err error) {
} }
return err 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

@@ -5,6 +5,7 @@ import (
"strings" "strings"
"git.rosy.net.cn/baseapi/utils" "git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/globals"
) )
type Context struct { type Context struct {
@@ -20,6 +21,7 @@ func NewContext(w http.ResponseWriter, r *http.Request) (ctx *Context) {
r: r, r: r,
accessUUID: utils.GetUUID(), accessUUID: utils.GetUUID(),
} }
globals.SugarLogger.Debugf("NewContext ip:%s", ctx.GetRealRemoteIP())
return ctx return ctx
} }
@@ -38,6 +40,7 @@ func (ctx *Context) GetTrackInfo() string {
func (ctx *Context) GetRealRemoteIP() (ip string) { func (ctx *Context) GetRealRemoteIP() (ip string) {
r := ctx.r r := ctx.r
if r != nil { if r != nil {
// globals.SugarLogger.Debugf("GetRealRemoteIP header:%s", utils.Format4Output(r.Header, false))
ip = r.Header.Get("X-Forwarded-For") ip = r.Header.Get("X-Forwarded-For")
if ip == "" { if ip == "" {
ip = r.Header.Get("X-real-ip") ip = r.Header.Get("X-real-ip")

View File

@@ -74,7 +74,6 @@ type AuthInfo struct {
Token string `json:"token"` Token string `json:"token"`
TokenType int `json:"tokenType"` // TOKEN类型 TokenType int `json:"tokenType"` // TOKEN类型
IsExistOpenID bool `json:"isExistOpenID"` IsExistOpenID bool `json:"isExistOpenID"`
AppID string `json:"appId"` // appId
} }
func (a *AuthInfo) GetAuthID() string { func (a *AuthInfo) GetAuthID() string {

View File

@@ -1,40 +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/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) {
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,9 @@ import (
"git.rosy.net.cn/baseapi/utils" "git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/auth2" "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"
"git.rosy.net.cn/jx-callback/business/model/dao" "git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/globals/api" "git.rosy.net.cn/jx-callback/globals/api"
) )
@@ -35,6 +36,7 @@ func (a *DefAuther) AddAuthBind(authBindEx *auth2.AuthBindEx, userName string) (
} }
func (a *DefAuther) UnbindAuth(userID, authType, authTypeID, userName string) (err error) { func (a *DefAuther) UnbindAuth(userID, authType, authTypeID, userName string) (err error) {
globals.SugarLogger.Debugf("DefAuther.UnbindAuth userID:%s, authType:%s, GetAuthTypeID:%s, userName:%s", userID, authType, authTypeID, userName)
condition := map[string]interface{}{ condition := map[string]interface{}{
"UserID": userID, "UserID": userID,
"Type": authType, "Type": authType,
@@ -62,6 +64,8 @@ func (a *DefAuther) GetUserType() (userType int8) {
// 此函数用于联合通过unionID查找用户 // 此函数用于联合通过unionID查找用户
func (a *DefAuther) UnionFindAuthBind(curAuthType, curAuthTypeID string, unionAuthTypeList []string, openID, unionID string, authDetail interface{}) (authBindEx *auth2.AuthBindEx, err error) { func (a *DefAuther) UnionFindAuthBind(curAuthType, curAuthTypeID string, unionAuthTypeList []string, openID, unionID string, authDetail interface{}) (authBindEx *auth2.AuthBindEx, err error) {
globals.SugarLogger.Debugf("UnionFindAuthBind curAuthType:%s, curAuthTypeID:%s, unionAuthTypeList:%v, openID:%s, unionID:%s, authDetail:%s",
curAuthType, curAuthTypeID, unionAuthTypeList, openID, unionID, utils.Format4Output(authDetail, true))
db := dao.GetDB() db := dao.GetDB()
var authBind *model.AuthBind var authBind *model.AuthBind
if authBind, err = dao.GetAuthBind(db, model.AuthBindTypeAuth, curAuthType, openID); err == nil { // 直接找到了 if authBind, err = dao.GetAuthBind(db, model.AuthBindTypeAuth, curAuthType, openID); err == nil { // 直接找到了
@@ -76,9 +80,9 @@ func (a *DefAuther) UnionFindAuthBind(curAuthType, curAuthTypeID string, unionAu
dao.UpdateEntity(db, authBind, "TypeID") dao.UpdateEntity(db, authBind, "TypeID")
} }
} else if dao.IsNoRowsError(err) { // 直接找不到尝试unionID } else if dao.IsNoRowsError(err) { // 直接找不到尝试unionID
if unionID != "" || openID != "" { // 且有unionID if unionID != "" { // 且有unionID
var authBindList []*model.AuthBind var authBindList []*model.AuthBind
if authBindList, err = dao.GetUserBindAuthInfo(db, "", model.AuthBindTypeAuth, unionAuthTypeList, openID, 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 = authBindList[0]
authBind.Type = curAuthType authBind.Type = curAuthType
authBind.TypeID = curAuthTypeID authBind.TypeID = curAuthTypeID
@@ -98,8 +102,7 @@ func (a *DefAuther) UnionFindAuthBind(curAuthType, curAuthTypeID string, unionAu
err = nil err = nil
} }
} }
if err == nil && authBindEx == nil { if err == nil && authBindEx == nil { //如果没有报错且没有找到一个认证方式创建无用户UserID为空的认证方式
//如果没有报错且没有找到一个认证方式创建无用户UserID为空的认证方式
authBindEx = &auth2.AuthBindEx{ authBindEx = &auth2.AuthBindEx{
AuthBind: model.AuthBind{ AuthBind: model.AuthBind{
Type: curAuthType, Type: curAuthType,
@@ -139,6 +142,7 @@ func (a *DefAuther) GenerateVerifyCode(keyID string) (verifyCode string) {
if verifyCode == "" { if verifyCode == "" {
verifyCode = fmt.Sprintf("%06d", rand.Intn(1000000)) verifyCode = fmt.Sprintf("%06d", rand.Intn(1000000))
} }
globals.SugarLogger.Debugf("GenerateVerifyCode keyID:%s verifyCode:%s", keyID, verifyCode)
return verifyCode return verifyCode
} }

View File

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

View File

@@ -1,48 +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/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) (*auth2.AuthBindEx, error) {
userQRInfo, err := api.DingDingQRCodeAPI.GetUserInfoByCode(code)
if err != nil {
return nil, err
}
tmp_userID, err := api.DingDingAPI.GetByUnionID(userQRInfo.UnionID)
if err != nil {
return nil, err
}
userInfo, err := api.DingDingAPI.GetUser(tmp_userID.UserID)
if err != nil {
return nil, err
}
authBindEx, err := a.UnionFindAuthBind(AuthTypeQRCode, api.DingDingQRCodeAPI.GetAppID(), []string{AuthTypeStaff, AuthTypeQRCode}, userQRInfo.OpenID, userQRInfo.UnionID, userQRInfo)
if err != nil {
return nil, err
}
authBindEx.UserHint = &auth2.UserBasic{
UserID2: tmp_userID.UserID,
Mobile: utils.Interface2String(userInfo["mobile"]),
Email: utils.Interface2String(userInfo["email"]),
Name: utils.Interface2String(userInfo["name"]),
}
return authBindEx, err
}

View File

@@ -1,44 +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/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) {
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,108 +0,0 @@
package douyin
import (
"git.rosy.net.cn/baseapi/platformapi/tiktok"
"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/auth2/authprovider/weixin"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/globals/api"
"strings"
)
const (
AuthTypeTiktokMini = "tiktokmini" // 抖音小程序
)
type TiktokMiniAuther struct {
authprovider.DefAuther
}
var (
AutherObjMini *TiktokMiniAuther
)
func init() {
AutherObjMini = new(TiktokMiniAuther)
auth2.RegisterAuther(AuthTypeTiktokMini, AutherObjMini)
}
func (a *TiktokMiniAuther) VerifySecret(dummy, code string) (authBindEx *auth2.AuthBindEx, err error) {
//appID, realCode := splitCode(code)
//sessionInfo, err := getTikTokApp(appID).GetTiktokOauth(realCode)
sessionInfo, err := api.TiktokApi.GetTiktokOauth(code)
if err != nil {
return nil, err
}
sessionKey := sessionInfo.Data.SessionKey
if authBindEx, err = a.UnionFindAuthBind(AuthTypeTiktokMini, api.TiktokApi.GetAppID(), []string{AuthTypeTiktokMini}, sessionInfo.Data.OpenId, sessionInfo.Data.Unionid, sessionInfo); err == nil {
authBindEx.UserData = sessionKey
}
return authBindEx, err
}
// 特殊接口
func (a *TiktokMiniAuther) DecryptData(authInfo *auth2.AuthInfo, jsCode, encryptedData, iv string) (decryptedDataBase64 string, err error) {
var sessionKey string
appID, jsCode := weixin.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 != AuthTypeTiktokMini {
// return "", ErrAuthTypeShouldBeMini
}
sessionKey = authInfo.AuthBindInfo.UserData.(string)
}
decryptedData, err := weixinapi.SNSDecodeMiniProgramData(encryptedData, sessionKey, iv)
if err != nil {
return "", err
}
return string(decryptedData), nil
}
func (a *TiktokMiniAuther) 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 getTikTokApp(appID string) (TikTokMini *tiktok.API) {
TikTokMini = api.TiktokApi
if len(appID) > 0 && appID == api.TiktokJXDJApiID {
TikTokMini = api.TiktokJXDJApi
}
return TikTokMini
}
func splitCode(code string) (appID, realCode string) {
str := strings.Split(code, "&")
if len(str) == 2 {
appID = str[1]
realCode = str[0]
} else {
globals.SugarLogger.Warnf("splitCode abnormal code:%s", code)
}
return appID, realCode
}

View File

@@ -1,100 +0,0 @@
package kuaishou
import (
"git.rosy.net.cn/jx-callback/business/auth2"
"git.rosy.net.cn/jx-callback/business/auth2/authprovider"
"git.rosy.net.cn/jx-callback/globals/api"
)
const (
AuthTypeKuaiShouMini = "kuaishoumini" // 快手小程序
)
type KuaiShouMiniAuther struct {
authprovider.DefAuther
}
var (
AutherObjMini *KuaiShouMiniAuther
)
func init() {
AutherObjMini = new(KuaiShouMiniAuther)
auth2.RegisterAuther(AuthTypeKuaiShouMini, AutherObjMini)
}
func (a *KuaiShouMiniAuther) VerifySecret(dummy, code string) (authBindEx *auth2.AuthBindEx, err error) {
//appID, realCode := splitCode(code)
//sessionInfo, err := getTikTokApp(appID).GetTiktokOauth(realCode)
sessionInfo, openId, err := api.KuaiShouApi.AuthLoginKuaiShou(code)
if err != nil {
return nil, err
}
if authBindEx, err = a.UnionFindAuthBind(AuthTypeKuaiShouMini, api.KuaiShouApi.GetAppID(), []string{AuthTypeKuaiShouMini}, openId, "", sessionInfo); err == nil {
authBindEx.UserData = sessionInfo
}
return authBindEx, err
}
//func (a *KuaiShouMiniAuther) DecryptData(authInfo *auth2.AuthInfo, jsCode, encryptedData, iv string) (decryptedDataBase64 string, err error) {
// var sessionKey string
// appID, jsCode := weixin.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 != AuthTypeKuaiShouMini {
// // return "", ErrAuthTypeShouldBeMini
// }
// sessionKey = authInfo.AuthBindInfo.UserData.(string)
// }
// decryptedData, err := weixinapi.SNSDecodeMiniProgramData(encryptedData, sessionKey, iv)
// if err != nil {
// return "", err
// }
// return string(decryptedData), nil
//}
//
//func (a *KuaiShouMiniAuther) 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 getTikTokApp(appID string) (TikTokMini *tiktok.API) {
// TikTokMini = api.TiktokApi
// if len(appID) > 0 && appID == api.TiktokJXDJApiID {
// TikTokMini = api.TiktokJXDJApi
// }
// return TikTokMini
//}
//func splitCode(code string) (appID, realCode string) {
// str := strings.Split(code, "&")
// if len(str) == 2 {
// appID = str[1]
// realCode = str[0]
// } else {
// globals.SugarLogger.Warnf("splitCode abnormal code:%s", code)
// }
// return appID, realCode
//}

View File

@@ -1,88 +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) {
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,86 +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"
)
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) {
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,126 +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/api"
)
const (
AuthTypeWeixin = "wxqrcode" // 微信扫码
AuthTypeMP = "weixinsns" // 公众号
AuthTypeWXNative = "wxnative" // 微信APP
AuthTypeWxApp = "weixinapp" //app微信登录(商家版)
AuthTypeWxAppCaishi = "weixinappcs" //app微信登录(用户版)
)
type Auther struct {
authprovider.DefAuther
authType string
}
var (
AutherObjWX *Auther
AutherObjMP *Auther
AutherObjNative *Auther
AutherObjApp *Auther
AutherObjCaiShiApp *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)
AutherObjCaiShiApp = &Auther{
authType: AuthTypeWxAppCaishi,
}
auth2.RegisterAuther(AuthTypeWxAppCaishi, AutherObjCaiShiApp)
}
func (a *Auther) VerifySecret(id, secret string) (authBindEx *auth2.AuthBindEx, err error) {
var openID, accessToken string
_, jsCode := SplitJsCode(secret)
if a.authType != AuthTypeWXNative {
state := id
code := jsCode
if state == "" {
//temp := a.getAPI()
//fmt.Printf("secret=%s,appid=%s", temp.GetSecret(), temp.GetAppID())
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, AuthTypeWxAppCaishi}, 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
}
if a.authType == AuthTypeWxAppCaishi {
return api.WeixinApp2
}
return api.WeixinAPI
}
func (a *Auther) GetUserType() (userType int8) {
return model.UserTypeStoreBoss
}
func GetAPI(appID string) *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
}

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) {
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) {
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
}
//if len(appID) > 0 && appID == api.WeixinMiniPrintAppId {
// miniApi = api.WeixinMiniAPIPrint
//}
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/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/authz" "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"
"git.rosy.net.cn/jx-callback/business/model/dao"
) )
func GetRoleDescription(name string, storeID int) (description string) { func GetRoleDescription(name string, storeID int) (description string) {

View File

@@ -1,169 +0,0 @@
package casbinauth
import (
jxmodel "git.rosy.net.cn/jx-callback/business/model"
"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 {
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())
// }

File diff suppressed because one or more lines are too long

View File

@@ -1,266 +0,0 @@
package bidding
import (
"encoding/json"
"fmt"
"git.rosy.net.cn/baseapi/platformapi/ali_logistics_query"
"git.rosy.net.cn/baseapi/platformapi/dingdingapi"
"git.rosy.net.cn/baseapi/platformapi/tonglianpayapi"
"git.rosy.net.cn/baseapi/platformapi/weixinapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils/ddmsg"
"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"
"time"
)
func LoadingLogistics(paramLogistic []*model.UpdateMaterialLogistic) []error {
var param []*model.UpdateMaterialLogistic
if len(paramLogistic) == 0 || paramLogistic == nil {
param = GetLogisticOrder()
} else {
param = paramLogistic
}
var db = dao.GetDB()
var errList = make([]error, 0, 0)
for _, v := range param {
// 更新订单状态
goodsOrder, err := partner.CurOrderManager.LoadOrder(v.OrderId, model.VendorIDJX)
if err != nil {
errList = append(errList, err)
continue
}
if time.Since(goodsOrder.CreatedAt) >= 3*24*time.Hour {
goodsOrder.Status = model.OrderStatusFinished
goodsOrder.VendorStatus = utils.Int2Str(model.WaybillStatusDelivered)
goodsOrder.StatusTime = time.Now()
goodsOrder.OrderFinishedAt = time.Now()
if _, err := dao.UpdateEntity(db, goodsOrder, "Status", "VendorStatus", "StatusTime", "OrderFinishedAt"); err != nil {
errList = append(errList, err)
continue
}
payList, _ := dao.GetOrderPayList(db, goodsOrder.VendorOrderID, goodsOrder.VendorID)
for _, pl := range payList {
if pl.OriginalData != "" {
originalData := &tonglianpayapi.CallBackResult{}
json.Unmarshal([]byte(pl.OriginalData), originalData)
if err = api.WeixinMiniAPI2.SNSDeliveryGoodsOrder(&weixinapi.DeliveryOrder{
TransactionId: originalData.ChnlTrxID,
ReceivedTime: time.Now().Unix(),
}); err != nil {
ddmsg.SendUserMessage(dingdingapi.MsgTyeText, "2452A93EEB9111EC9B06525400E86DC0", "微信物料送达推送", fmt.Sprintf("物料商城下单,送达错误:%s,请注意查看,err:%s", goodsOrder.VendorOrderID, err.Error()))
}
}
}
}
}
return nil
// GetLogisticsInfo 免费物流查询资源不可用,暂时不管
//for _, logistics := range param {
// // 获取当前订单物流状态
// statusList, err := orderman.FixedOrderManager.GetLogisticsOrderStatusList(logistics.OrderId, logistics.LogisticId, 9)
// if err != nil {
// errList = append(errList, err)
// continue
// }
//
// // 获取当前订单三方配送物流
// logisticsList, err := api.LogisticsApi.GetLogisticsInfo(logistics.LogisticId)
// if err != nil {
// errList = append(errList, err)
// continue
// }
//
// // 新订单,本地暂无物流信息,全部更新远端物流信息到本地
// if len(logisticsList.Info[0].LogisticsTraceDetailList) == model.NO {
// errList = append(errList, errors.New("运单号[%s]:已经过期/新订单暂无物流推送信息"))
// continue
// }
// var orderStatus = make([]*model.OrderStatus, 0, 0)
// goodsOrderStatus := 0
// for _, v := range logisticsList.Info[0].LogisticsTraceDetailList {
// orderStatusToLocal := &model.OrderStatus{
// VendorOrderID: logisticsList.Info[0].MailNo,
// VendorID: model.VendorIDTotalWl,
// OrderType: model.OrderTypeWaybill,
// RefVendorOrderID: logistics.OrderId,
// RefVendorID: model.VendorIDJX,
// VendorStatus: v.SubLogisticsStatus,
// StatusTime: time.Time{},
// DuplicatedCount: 0,
// Remark: v.Desc,
// ModelTimeInfo: model.ModelTimeInfo{CreatedAt: time.Now(), UpdatedAt: time.Now()},
// }
//
// switch v.SubLogisticsStatus {
// case ali_logistics_query.LogisticsStatusRECEVIE:
// orderStatusToLocal.Status = model.WaybillStatusNew // 新订单
// goodsOrderStatus = model.OrderStatusNew // 新订单
// case ali_logistics_query.LogisticsStatusWAIT_ACCEPT:
// orderStatusToLocal.Status = model.WaybillStatusAccepted // 分配骑手
// goodsOrderStatus = model.OrderStatusAccepted // 拣货完成等待骑手
// case ali_logistics_query.LogisticsStatusACCEPT:
// orderStatusToLocal.Status = model.WaybillStatusCourierArrived // 兼容骑手取货状态
// goodsOrderStatus = model.OrderStatusFinishedPickup
// case ali_logistics_query.LogisticsStatusTRANSPORT, ali_logistics_query.LogisticsStatusSEND_ON, ali_logistics_query.LogisticsStatusARRIVE_CITY, ali_logistics_query.LogisticsStatusDELIVERING:
// orderStatusToLocal.Status = model.WaybillStatusDelivering // 配送中
// goodsOrderStatus = model.OrderStatusDelivering
// case ali_logistics_query.LogisticsStatusAGENT_SIGN, ali_logistics_query.LogisticsStatusSIGN, ali_logistics_query.LogisticsStatusSTA_SIGN:
// orderStatusToLocal.Status = model.WaybillStatusDelivered // 配送结束
// goodsOrderStatus = model.OrderStatusFinished
// default: // 剩余状态全部为异常状态,除非新加状态
// orderStatusToLocal.Status = model.WaybillStatusUnknown // 异常配送
// goodsOrderStatus = model.OrderStatusDeliverFailed // 投递失败
// }
// orderStatusToLocal.StatusTime = utils.Timestamp2Time(v.Time)
// orderStatus = append(orderStatus, orderStatusToLocal)
// }
//
// if len(statusList) == 0 || statusList == nil { // 本地订单状态为空不存在
// for _, v := range orderStatus {
// if err := dao.CreateEntity(db, v); err != nil {
// errList = append(errList, err)
// continue
// }
// }
// } else {
// for _, v := range orderStatus {
// if statusList[len(statusList)-1].StatusTime.Unix() > v.StatusTime.Unix() && checkOrderStatus(statusList[len(statusList)-1].VendorStatus) {
// continue
// }
// if err := dao.CreateEntity(db, v); err != nil {
// errList = append(errList, err)
// continue
// }
// }
// }
//
// // 获取当前订单运单状态
// wayBill, err := dao.GetWaybills(db, logistics.OrderId, nil)
// if err != nil {
// errList = append(errList, err)
// continue
// }
// status := orderStatus[len(orderStatus)-1].Status
// vendorStatus := orderStatus[len(orderStatus)-1].VendorStatus
// statusTime := orderStatus[len(orderStatus)-1].StatusTime
// if len(wayBill) == 0 || wayBill == nil {
// wayBillObj := &model.Waybill{
// VendorWaybillID: logistics.LogisticId,
// WaybillVendorID: model.VendorIDTotalWl,
// VendorOrderID: logistics.OrderId,
// OrderVendorID: model.VendorIDJX,
// CourierName: logisticsList.Info[0].Courier,
// CourierMobile: logisticsList.Info[0].CourierPhone,
// Status: status,
// VendorStatus: vendorStatus,
// ActualFee: logistics.LogisticFee,
// DesiredFee: logistics.LogisticFee,
// DeliveryFlag: model.OrderDeliveryFlagMaskScheduleDisabled,
// WaybillCreatedAt: time.Now(),
// StatusTime: statusTime,
// ModelTimeInfo: model.ModelTimeInfo{CreatedAt: time.Now(), UpdatedAt: time.Now()},
// WaybillFinishedAt: time.Now(),
// }
// if err := dao.CreateEntity(db, wayBillObj); err != nil {
// errList = append(errList, err)
// continue
// }
// } else {
// wayBill[0].UpdatedAt = time.Now()
// wayBill[0].Status = status
// wayBill[0].VendorStatus = vendorStatus
// wayBill[0].StatusTime = statusTime
// wayBill[0].WaybillFinishedAt = time.Now()
// if _, err := dao.UpdateEntity(db, wayBill[0], "Status", "UpdatedAt", "VendorStatus", "StatusTime"); err != nil {
// errList = append(errList, err)
// continue
// }
// }
//
// // 更新订单状态
// goodsOrder, err := partner.CurOrderManager.LoadOrder(logistics.OrderId, model.VendorIDJX)
// if err != nil {
// errList = append(errList, err)
// continue
// }
// goodsOrder.Status = goodsOrderStatus
// goodsOrder.VendorStatus = vendorStatus
// goodsOrder.StatusTime = statusTime
// if orderStatus[len(orderStatus)-1].Status >= model.OrderStatusEndBegin {
// goodsOrder.OrderFinishedAt = time.Now()
// }
// if _, err := dao.UpdateEntity(db, goodsOrder, "Status", "VendorStatus", "StatusTime", "OrderFinishedAt"); err != nil {
// errList = append(errList, err)
// continue
// }
//}
//
//return errList
}
func checkOrderStatus(orderStatus string) bool {
switch orderStatus {
case ali_logistics_query.LogisticsStatusRECEVIE:
return true
case ali_logistics_query.LogisticsStatusWAIT_ACCEPT:
return true
case ali_logistics_query.LogisticsStatusACCEPT:
return true
case ali_logistics_query.LogisticsStatusTRANSPORT, ali_logistics_query.LogisticsStatusSEND_ON, ali_logistics_query.LogisticsStatusARRIVE_CITY, ali_logistics_query.LogisticsStatusDELIVERING:
return true
case ali_logistics_query.LogisticsStatusAGENT_SIGN, ali_logistics_query.LogisticsStatusSIGN, ali_logistics_query.LogisticsStatusSTA_SIGN:
return true
case ali_logistics_query.LogisticsStatusSTA_INBOUND, ali_logistics_query.LogisticsStatusRETURN_SIGN, ali_logistics_query.LogisticsStatusFAILED, ali_logistics_query.LogisticsStatusREFUSE_SIGN, ali_logistics_query.LogisticsStatusDELIVER_ABNORMAL:
return true
case ali_logistics_query.LogisticsStatusRETENTION, ali_logistics_query.LogisticsStatusISSUE, ali_logistics_query.LogisticsStatusRETURN, ali_logistics_query.LogisticsStatusDAMAGE, ali_logistics_query.LogisticsStatusCANCEL_ORDER:
return true
default:
return false
}
}
// GetLogisticOrder 查询未完成的物料订单,更新物流信息
func GetLogisticOrder() []*model.UpdateMaterialLogistic {
var (
timeNow = time.Now()
startTime = timeNow.AddDate(0, -1, 0)
endTime = timeNow
goodsList = make([]*model.GoodsOrder, 0, 0)
)
sql := ` SELECT * FROM goods_order g WHERE g.order_created_at >= ? AND g.order_created_at < ? AND g.store_id = ? AND order_type = ? AND g.status < ? ` // 一个月内状态未完成的订单
sqlParam := []interface{}{
startTime, endTime, "666666", 1, model.OrderStatusEndBegin,
}
if err := dao.GetRows(dao.GetDB(), &goodsList, sql, sqlParam...); err != nil {
globals.SugarLogger.Debugf("loading jx material order err :%s", err)
return nil
}
if len(goodsList) == 0 {
return nil
}
logisticsList := make([]*model.UpdateMaterialLogistic, 0, len(goodsList))
for _, v := range goodsList {
logistics := &model.UpdateMaterialLogistic{
OrderId: v.VendorOrderID,
LogisticId: v.VendorWaybillID,
LogisticFee: v.BaseFreightMoney,
}
logisticsList = append(logisticsList, logistics)
}
return logisticsList
}

View File

@@ -1,230 +0,0 @@
package bidding
import (
"fmt"
"git.rosy.net.cn/baseapi/platformapi/mtwmapi"
"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/globals"
"git.rosy.net.cn/jx-callback/globals/api"
"sort"
"strconv"
"strings"
"time"
)
// GetStatisticsList 京西数据查询
func GetStatisticsList(start, end time.Time, storeIds []int, offset, pageSize int) (*model.PagedInfo, error) {
return dao.GetStatistics(dao.GetDB(), start, end, storeIds, offset, pageSize)
}
// GetMTInfo 更新美团门店信息
func GetMTInfo() []error {
var db = dao.GetDB()
var errList = make([]error, 0, 0)
// 获取当前一月有效订单的门店信息
effectiveStores, err := dao.StoreInformationStatistics(db)
if err != nil {
return append(errList, err)
}
var mtApi *mtwmapi.API
for _, v := range effectiveStores {
if v.VendorOrgCode == globals.Mtwm2Code {
mtApi = api.Mtwm2API
mtApi.SetToken(v.MtwmToken)
} else {
mtApi = api.MtwmAPI
}
statistics := &model.ActivityStation{
StoreID: v.JxStoreID,
VendorID: model.VendorIDMTWM,
VendorStoreID: v.VendorStoreID,
BrandID: v.VendorOrgCode,
//Activity1: 0,
//Activity2: 0,
//Activity: 0,
//StoreSkuNum: 0,
//StoreRating: 0,
//DeliveryFee: "",
//DeliveryFee2: "",
PromotionFee: "暂无法获取",
//BusinessHours: "",
}
dao.WrapAddIDCULEntity(statistics, "system")
down, up := getActivityCount(mtApi, v.VendorStoreID)
statistics.Activity1 = int64(down)
statistics.Activity2 = int64(up)
statistics.Activity = int64(down + up)
score, err := mtApi.CommentScore(v.VendorStoreID)
if err != nil {
errList = append(errList, fmt.Errorf("%s获取评分错误:%s", v.VendorStoreID, err.Error()))
}
if score != nil {
statistics.StoreRating = score.AvgPoiScore
} else {
statistics.StoreRating = 0
}
// 获取门店营业时长
detail, _ := mtApi.PoiMGet([]string{v.VendorStoreID})
if detail != nil {
statistics.BusinessHours, err = getStoreShippingTime(detail[0].ShippingTime)
if err != nil {
errList = append(errList, fmt.Errorf("%s获取营业时长错误:%s", v.VendorStoreID, err.Error()))
statistics.BusinessHours = err.Error()
}
statistics.DeliveryFee2 = utils.Float64ToStr(detail[0].ShippingFee)
}
// 获取门店起送价
result, err := mtApi.ShippingList(v.VendorStoreID)
if err != nil {
errList = append(errList, fmt.Errorf("%s获取起送价错误:%s", v.VendorStoreID, err.Error()))
statistics.DeliveryFee = err.Error()
}
shippingList := make([]ShippingList, 0, 0)
for _, v2 := range result {
shippingList = append(shippingList, ShippingList{
TimeRange: utils.Interface2String(v2["time_range"]),
MinPrice: utils.MustInterface2Float64(v2["min_price"]),
ShippingFee: utils.MustInterface2Float64(v2["shipping_fee"]),
})
}
statistics.DeliveryFee = utils.Format4Output(shippingList, false)
if len(result) == 0 {
statistics.DeliveryFee = ""
}
dao.CreateEntity(db, statistics)
}
return errList
}
// 获取门店折扣活动商品数量
func getActivityCount(api *mtwmapi.API, vendorStoreId string) (int, int) {
threefoldDown := 0 // 0-3 折活动数量
threefoldUp := 0 // 3.01-9 折活动
// 获取美团活动
directList, _ := api.RetailDiscountList(vendorStoreId, mtwmapi.RetailActTypeDirectDown) // 折扣活动
for _, v := range directList {
if v.ActPrice/v.OriginalPrice >= 3.01 {
threefoldUp++
} else {
threefoldDown++
}
}
secKillList, _ := api.RetailDiscountList(vendorStoreId, mtwmapi.RetailActTypeSecKill) // 爆品活动
if secKillList != nil {
threefoldDown = threefoldDown + len(secKillList)
}
return threefoldDown, threefoldUp
}
func getStoreShippingTime(storeTime string) (string, error) {
time2 := strings.Split(storeTime, ";")
aa := int(time.Now().Weekday())
if aa == 0 {
aa = 7
}
if len(time2) == 1 {
aa = 1
}
intervals, err := parseIntervals(time2[aa-1])
if err != nil {
fmt.Printf("解析错误: %v\n", err)
return "", err
}
merged := mergeIntervals(intervals)
totalMinutes := 0
for _, iv := range merged {
totalMinutes += iv.end - iv.start
}
return fmt.Sprintf("%.2f", float64(totalMinutes)/float64(60)), err
}
// timeToMinutes 将 "HH:MM" 转为当天第几分钟0 ~ 1439
func timeToMinutes(t string) (int, error) {
parts := strings.Split(t, ":")
if len(parts) != 2 {
return 0, fmt.Errorf("invalid time format: %s", t)
}
h, err := strconv.Atoi(parts[0])
if err != nil || h < 0 || h > 23 {
return 0, fmt.Errorf("invalid hour in %s", t)
}
m, err := strconv.Atoi(parts[1])
if err != nil || m < 0 || m > 59 {
return 0, fmt.Errorf("invalid minute in %s", t)
}
return h*60 + m, nil
}
// parseIntervals 解析 "00:00-01:00,01:05-23:59" → []interval
type interval struct {
start, end int // minutes since 00:00
}
func parseIntervals(s string) ([]interval, error) {
var intervals []interval
for _, seg := range strings.Split(s, ",") {
seg = strings.TrimSpace(seg)
if seg == "" {
continue
}
parts := strings.Split(seg, "-")
if len(parts) != 2 {
return nil, fmt.Errorf("invalid interval format: %s", seg)
}
startMins, err := timeToMinutes(strings.TrimSpace(parts[0]))
if err != nil {
return nil, err
}
endMins, err := timeToMinutes(strings.TrimSpace(parts[1]))
if err != nil {
return nil, err
}
if startMins > endMins {
return nil, fmt.Errorf("start after end in interval: %s", seg)
}
intervals = append(intervals, interval{start: startMins, end: endMins})
}
return intervals, nil
}
// mergeIntervals 合并重叠/相邻区间(如 [0,60], [65,1439] → 保留两个;若 [0,60], [60,120] → 可合并为 [0,120]
func mergeIntervals(ints []interval) []interval {
if len(ints) == 0 {
return ints
}
// 排序
sort.Slice(ints, func(i, j int) bool {
return ints[i].start < ints[j].start
})
merged := make([]interval, 0, len(ints))
curr := ints[0]
for i := 1; i < len(ints); i++ {
if ints[i].start <= curr.end { // 重叠或紧邻(如 end=60, next.start=60 → 合并)
if ints[i].end > curr.end {
curr.end = ints[i].end
}
} else {
merged = append(merged, curr)
curr = ints[i]
}
}
merged = append(merged, curr)
return merged
}
type ShippingList struct {
TimeRange string `json:"time_range"` // 配送生效时间范围
MinPrice float64 `json:"min_price"` // 最小起送价
ShippingFee float64 `json:"shipping_fee"` // 配送费
}

View File

@@ -1,124 +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) {
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 {
response = weimobapi.Err2CallbackResponse(err, "")
}
}
}
return response
}
func changeStoreSkusByOrder(order *weimobapi.OrderDetail) {
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
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

@@ -79,6 +79,7 @@ func Begin(db *DaoDB) (txDB orm.TxOrmer, err error) {
func (db *DaoDB) startWatchTransaction() { func (db *DaoDB) startWatchTransaction() {
db.beginTransactionStack = debug.Stack() db.beginTransactionStack = debug.Stack()
db.transactionWatchTimer = utils.AfterFuncWithRecover(transactionWarningSeconds*time.Second, func() { db.transactionWatchTimer = utils.AfterFuncWithRecover(transactionWarningSeconds*time.Second, func() {
globals.SugarLogger.Warnf("Begin Transaction too long, %s", string(db.beginTransactionStack))
db.transactionWatchTimer = nil db.transactionWatchTimer = nil
db.beginTransactionStack = nil db.beginTransactionStack = nil
}) })
@@ -96,7 +97,7 @@ func Commit(db *DaoDB, txDB orm.TxOrmer) (err error) {
if db.transactionLevel == 1 { if db.transactionLevel == 1 {
db.stopWatchTransaction() db.stopWatchTransaction()
err = txDB.Commit() err = txDB.Commit()
// err = db.Db.Commit() //err = db.Db.Commit()
db.transactionLevel = 0 db.transactionLevel = 0
} else if db.transactionLevel > 1 { } else if db.transactionLevel > 1 {
db.transactionLevel-- db.transactionLevel--
@@ -108,7 +109,7 @@ func Rollback(db *DaoDB, txDB orm.TxOrmer) (err error) {
if db.transactionLevel > 0 { if db.transactionLevel > 0 {
db.stopWatchTransaction() db.stopWatchTransaction()
err = txDB.Rollback() err = txDB.Rollback()
// err = db.Db.Rollback() //err = db.Db.Rollback()
} }
db.transactionLevel = 0 db.transactionLevel = 0
return err return err
@@ -142,17 +143,22 @@ func GetRowTx(txDB orm.TxOrmer, inPtr interface{}, sql string, values ...interfa
if txDB == nil { if txDB == nil {
return return
} }
typeInfo := reflect.TypeOf(inPtr) if !useGetRowsWhenGetRow { // beego QueryRow有bug嵌入的struct不能正常绑定
if typeInfo.Kind() != reflect.Ptr { err = txDB.Raw(sql, values).QueryRow(inPtr)
return errors.New("inPtr must be ptr") //err = db.Db.Raw(sql, values).QueryRow(inPtr)
} } else {
slice := reflect.New(reflect.SliceOf(typeInfo.Elem())) typeInfo := reflect.TypeOf(inPtr)
if err = GetRowsTx(txDB, slice.Interface(), sql, values...); err == nil { if typeInfo.Kind() != reflect.Ptr {
slice = slice.Elem() return errors.New("inPtr must be ptr")
if slice.Len() > 0 { }
reflect.ValueOf(inPtr).Elem().Set(slice.Index(0)) slice := reflect.New(reflect.SliceOf(typeInfo.Elem()))
} else { if err = GetRowsTx(txDB, slice.Interface(), sql, values...); err == nil {
return orm.ErrNoRows slice = slice.Elem()
if slice.Len() > 0 {
reflect.ValueOf(inPtr).Elem().Set(slice.Index(0))
} else {
return orm.ErrNoRows
}
} }
} }
return err return err
@@ -171,7 +177,7 @@ func GetRowsTx(txDB orm.TxOrmer, inPtr interface{}, sql string, values ...interf
return return
} }
_, err = txDB.Raw(sql, values).QueryRows(inPtr) _, 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 return err
} }
@@ -196,6 +202,16 @@ func UpdateEntity(db *DaoDB, item interface{}, cols ...string) (num int64, err e
return num, err 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) { func UpdateEntityTx(txDB orm.TxOrmer, item interface{}, cols ...string) (num int64, err error) {
if txDB == nil { if txDB == nil {
return return
@@ -207,16 +223,6 @@ func UpdateEntityTx(txDB orm.TxOrmer, item interface{}, cols ...string) (num int
return num, err 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) { func CreateEntityTx(txDB orm.TxOrmer, item interface{}) (err error) {
if txDB == nil { if txDB == nil {
return return
@@ -257,6 +263,18 @@ func DeleteEntity(db *DaoDB, item interface{}, cols ...string) (num int64, err e
return num, err 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) { func ExecuteSQL(db *DaoDB, sql string, params ...interface{}) (num int64, err error) {
if db == nil { if db == nil {
db = GetDB() db = GetDB()
@@ -274,16 +292,13 @@ func ExecuteSQL(db *DaoDB, sql string, params ...interface{}) (num int64, err er
// 此函数要求db在事务中否则可能导致取得到的是另一个连接的数据 // 此函数要求db在事务中否则可能导致取得到的是另一个连接的数据
func GetLastTotalRowCount(db *DaoDB) int { func GetLastTotalRowCount(db *DaoDB) int {
countInfo := &struct{ Ct 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 { if err := GetRow(db, countInfo, "SELECT FOUND_ROWS() ct"); err == nil {
return countInfo.Ct return countInfo.Ct
} }
return 0 return 0
} }
func GetLastTotalRowCount2(db *DaoDB, txDB orm.TxOrmer) int { func GetLastTotalRowCountTx(txDB orm.TxOrmer) int {
countInfo := &struct{ Ct int }{} countInfo := &struct{ Ct int }{}
if err := GetRowTx(txDB, countInfo, "SELECT FOUND_ROWS() ct"); err == nil { if err := GetRowTx(txDB, countInfo, "SELECT FOUND_ROWS() ct"); err == nil {
return countInfo.Ct return countInfo.Ct

View File

@@ -22,11 +22,12 @@ func GetAuthBind(db *DaoDB, bindType int, authType, authID string) (authBind *mo
authType, authType,
authID, authID,
} }
// globals.SugarLogger.Debugf("GetAuthBind sql:%s, sqlParams:%s", sql, utils.Format4Output(sqlParams, false))
err = GetRow(db, &authBind, sql, sqlParams...) err = GetRow(db, &authBind, sql, sqlParams...)
return authBind, err 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 := ` sql := `
SELECT * SELECT *
FROM auth_bind t1 FROM auth_bind t1
@@ -43,7 +44,6 @@ func GetUserBindAuthInfo(db *DaoDB, userID string, bindType int, typeList []stri
sql += " AND t1.bind_type = ?" sql += " AND t1.bind_type = ?"
sqlParams = append(sqlParams, bindType) sqlParams = append(sqlParams, bindType)
} }
if len(typeList) > 0 { if len(typeList) > 0 {
sql += " AND t1.type IN (" + GenQuestionMarks(len(typeList)) + ")" sql += " AND t1.type IN (" + GenQuestionMarks(len(typeList)) + ")"
sqlParams = append(sqlParams, typeList) sqlParams = append(sqlParams, typeList)
@@ -56,9 +56,9 @@ func GetUserBindAuthInfo(db *DaoDB, userID string, bindType int, typeList []stri
sql += " AND t1.auth_id2 = ?" sql += " AND t1.auth_id2 = ?"
sqlParams = append(sqlParams, authID2) sqlParams = append(sqlParams, authID2)
} }
if len(typeIDs) > 0 { if typeID != "" {
sql += " AND t1.type_id IN (" + GenQuestionMarks(len(typeIDs)) + ")" sql += " AND t1.type_id = ?"
sqlParams = append(sqlParams, typeIDs) sqlParams = append(sqlParams, typeID)
} }
sql += " ORDER BY t1.type" sql += " ORDER BY t1.type"
err = GetRows(db, &authList, sql, sqlParams...) err = GetRows(db, &authList, sql, sqlParams...)

View File

@@ -54,11 +54,6 @@ func UpdateEntityByKV(db *DaoDB, item interface{}, kvs map[string]interface{}, c
qs = qs.Filter(k, v) qs = qs.Filter(k, v)
} }
} }
for k, v := range kvs {
if k == "jdCategoryID" && (v == "" || v == nil) {
delete(kvs, k)
}
}
num, err = qs.Update(kvs) num, err = qs.Update(kvs)
if err != nil && !IsDuplicateError(err) { if err != nil && !IsDuplicateError(err) {
globals.SugarLogger.Errorf("UpdateEntityByKV %s failed with error:%v", reflect.TypeOf(item).Name(), err) globals.SugarLogger.Errorf("UpdateEntityByKV %s failed with error:%v", reflect.TypeOf(item).Name(), err)
@@ -136,6 +131,7 @@ func UpdateEntityLogicallyAndUpdateSyncStatus(db *DaoDB, item interface{}, kvs m
valueRows := reflect.New(reflect.SliceOf(typeInfo)) valueRows := reflect.New(reflect.SliceOf(typeInfo))
rows := valueRows.Interface() rows := valueRows.Interface()
if err = GetEntitiesByKV(db, rows, conditions, false); err == nil { if err = GetEntitiesByKV(db, rows, conditions, false); err == nil {
// globals.SugarLogger.Debug(utils.Format4Output(rows, false))
valueRows = reflect.Indirect(valueRows) valueRows = reflect.Indirect(valueRows)
for i := 0; i < valueRows.Len(); i++ { for i := 0; i < valueRows.Len(); i++ {
value := reflect.Indirect(valueRows.Index(i)) value := reflect.Indirect(valueRows.Index(i))

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,34 @@
package dao
import (
"errors"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/model"
)
// 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
}
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) txDB, _ := Begin(db)
defer Commit(db, txDB) defer Commit(db, txDB)
if err = GetRowsTx(txDB, &operateEventExt, sql, sqlParams...); err == nil { if err = GetRowsTx(txDB, &operateEventExt, sql, sqlParams...); err == nil {
totalCount = GetLastTotalRowCount2(db, txDB) totalCount = GetLastTotalRowCountTx(txDB)
} }
var ( var (
accessUUidList []string accessUUidList []string
@@ -142,31 +142,131 @@ func GetOperateEvents(db *DaoDB, name string, apiFunctions []string, operateType
return operateEventExt, totalCount, err 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 := ` sql := `
SELECT * SELECT a.*, b.name user_name, b.avatar
FROM im_message_record FROM message_group a
WHERE deleted_at = ? LEFT JOIN user b ON b.user_id = a.user_id
WHERE a.deleted_at = ?
` `
sqlParams := []interface{}{ sqlParams := []interface{}{utils.DefaultTimeValue}
utils.DefaultTimeValue,
}
if vendorOrderID != "" {
sql += " AND vendor_order_id = ?"
sqlParams = append(sqlParams, vendorOrderID)
}
if userID != "" { if userID != "" {
sql += " AND user_id = ?" sql += " AND a.user_id = ?"
sqlParams = append(sqlParams, userID) sqlParams = append(sqlParams, userID)
} }
if storeID != 0 { if groupType != 0 {
sql += " AND store_id = ?" sql += " AND a.type = ?"
sqlParams = append(sqlParams, storeID) sqlParams = append(sqlParams, groupType)
} }
if vendorID >= 0 { if groupID != 0 {
sql += " AND vendor_id = ?" sql += " AND a.group_id LIKE ?"
sqlParams = append(sqlParams, vendorID) sqlParams = append(sqlParams, utils.Int2Str(groupID)+"%")
} }
err = GetRows(db, &msg, sql, sqlParams) if err = GetRows(db, &messageGroupsResult, sql, sqlParams); err == nil {
return msg, err 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

@@ -2,8 +2,8 @@ package dao
import ( import (
"fmt" "fmt"
"git.rosy.net.cn/baseapi/utils/errlist" "git.rosy.net.cn/baseapi/utils/errlist"
"time"
"git.rosy.net.cn/baseapi/utils" "git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/model" "git.rosy.net.cn/jx-callback/business/model"
@@ -34,7 +34,6 @@ func QueryConfigs(db *DaoDB, key, configType, keyword string) (configList []*mod
err = GetRows(db, &configList, sql, sqlParams...) err = GetRows(db, &configList, sql, sqlParams...)
if err == nil && len(configList) == 0 && key != "" { if err == nil && len(configList) == 0 && key != "" {
fmt.Println("条件:key:,type:,keyword:不能找到配置", key, configType, keyword)
err = fmt.Errorf("条件:key:%s,type:%s,keyword:%s不能找到配置", key, configType, keyword) err = fmt.Errorf("条件:key:%s,type:%s,keyword:%s不能找到配置", key, configType, keyword)
} }
return configList, err return configList, err
@@ -60,10 +59,3 @@ func GetSysConfigAsInt64(db *DaoDB, key string) (value int64, err error) {
} }
return value, err return value, err
} }
// 修改配置
func UpdateOperatorConfig(param string, types, key string) error {
sql := `UPDATE new_config c SET c.value = ?,c.updated_at = ? WHERE c.type = ? AND c.key = ?`
_, err := ExecuteSQL(GetDB(), sql, []interface{}{param, time.Now(), types, key})
return err
}

65
business/dao/place.go Normal file
View File

@@ -0,0 +1,65 @@
package dao
import (
"git.rosy.net.cn/jx-callback/business/model"
"github.com/astaxie/beego/client/orm"
)
const (
EnableCondAll = 0
EnableCondEnalbed = 1
EnableCondDisabled = 2
)
func GetPlaceByCode(db *DaoDB, code int) (place *model.Place, err error) {
if db == nil {
db = GetDB()
}
place = &model.Place{
Code: code,
}
err = GetEntity(db, place, "Code")
return place, err
}
func GetPlacesByCond(db *DaoDB, enableCond int) (placeList []*model.Place, err error) {
if db == nil {
db = GetDB()
}
sql := `
SELECT *
FROM place
WHERE level = 2
`
if enableCond == EnableCondEnalbed {
sql += " AND enabled = 1"
} else if enableCond == EnableCondDisabled {
sql += " AND enabled = 0"
}
sql += " ORDER BY code"
err = GetRows(db, &placeList, sql)
return placeList, err
}
func GetPlaceByName(db *DaoDB, name string, level int, parentCode int) (place *model.Place, err error) {
if db == nil {
db = GetDB()
}
cols := []string{
"Name",
"Level",
}
place = &model.Place{
Name: name,
Level: int8(level),
}
if parentCode != 0 {
cols = append(cols, "ParentCode")
place.ParentCode = parentCode
}
if err = GetEntity(db, place, cols...); err == orm.ErrNoRows {
err = db.Db.Raw("SELECT * FROM place WHERE parent_code = ? AND level = ? AND name LIKE ?", parentCode, level, "%"+name+"%").QueryRow(place)
}
return place, 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,539 @@
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 || err != nil {
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): // utils.Int2Str(model.OrderStatusFinishedPickup), utils.Int2Str(model.OrderStatusAccepted)
//if param[model.OrderStatusPrint] != utils.Int2Str(model.OrderStatusNew) && param[model.VendorIDPrint] == utils.Int64ToStr(model.VendorIDMTWM) {
// return "", err
//}
//if param[model.OrderStatusPrint] == utils.Int2Str(model.OrderStatusFinishedPickup) && param[model.VendorIDPrint] == utils.Int64ToStr(model.VendorIDEBAI) {
// return "", err
//}
// 称谓设置/平台语音设置
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 enterprise
import (
"git.rosy.net.cn/baseapi/platformapi/ebaiapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/globals"
"testing"
)
func TestOOO(t *testing.T) {
product := map[string]interface{}{
"apply_quantity": 1,
"apply_refund_time": 1711447475000,
"apply_refund_user_amount": 143,
"commodity_type": 2,
"custom_sku_id": "25381",
"custom_sku_spec_id": "",
"discount_detail": map[string]interface{}{
"agent_discount_amount": 0,
"discount_total_amount": 577,
"merchant_discount_amount": 563,
"platform_discount_amount": 14,
"total_price": 720,
"user_discount_amount": 0,
},
"free_gift": false,
"fund_calculate_type": 0,
"gift_related_sub_biz_order_id_list": nil,
"is_combine": false,
"last_refund_status": 0,
"platform_sku_id": 16319366072214214,
"refund_order_id": 2403269635888396215,
"refund_quantity": 1,
"refund_status": 50,
"refund_user_amount": 143,
"refund_weight": 350,
"sku_name": "【尽享好价】西红柿 番茄约300~350g/组",
"sku_spec_id": "null",
"sub_biz_order_id": "4006435770425226215",
"upc": "upc-25381",
"virtual_type": "0",
}
skuList := aa(product)
globals.SugarLogger.Debugf("=====skulist := %s", utils.Format4Output(skuList, false))
}
func aa(product map[string]interface{}) (skuList []*model.OrderSku) {
skuList = make([]*model.OrderSku, 0, 0)
if product["virtual_type"] == ebaiapi.OrderVirtualType {
skuName := product["sku_name"].(string)
_, _, _, specUnit, _, specQuality := jxutils.SplitSkuName(skuName)
number := int(utils.MustInterface2Int64(product["apply_quantity"]))
sku := &model.OrderSku{
VendorOrderID: "1",
VendorID: model.VendorIDEBAI,
Count: number,
SkuID: int(utils.Str2Int64WithDefault(utils.Interface2String(product[ebaiapi.KeyCustomSkuID]), 0)),
VendorSkuID: utils.Int2Str(product["platform_sku_id"].(int)),
SkuName: skuName,
Weight: int(utils.Interface2Int64WithDefault(product["refund_weight"], 0)) / number, // 退单这里的total_weight有BUG这里的total_weight还是没有退单时的值
VendorPrice: utils.MustInterface2Int64(product["refund_user_amount"]),
}
//sku.SalePrice, _, sku.StoreSubName = getSkuSalePrice(product)
sku.SalePrice = utils.Interface2Int64WithDefault(product["discount_detail"].(map[string]interface{})["total_price"], 0)
if sku.Weight == 0 {
sku.Weight = jxutils.FormatSkuWeight(specQuality, specUnit) // 订单信息里没有重量,只有名字里尝试找
}
skuList = append(skuList, sku)
}
return skuList
}

View File

@@ -1,44 +0,0 @@
package enterprise
import (
"git.rosy.net.cn/baseapi/platformapi/enterprise_wechat"
"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"
"strconv"
)
var EnterpriseSuite = new(enterprise_wechat.SuiteTicketInfo)
// 初始化加载全局变量
func Init() {
var config []*legacymodel.Config
sql := `SELECT * FROM config WHERE thirdparty = ? `
if err := dao.GetRows(dao.GetDB(), &config, sql, []interface{}{"enterprise"}...); err != nil {
globals.SugarLogger.Debug("enterprice init config err = ", err)
}
if len(config) >= model.YES {
EnterpriseSuite.SuiteId = config[0].RefreshToken
EnterpriseSuite.SuiteTicket = config[0].Token
EnterpriseSuite.InfoType = ""
time, _ := strconv.ParseInt(config[0].Date, 10, 64)
EnterpriseSuite.TimeStamp = time
}
}
func UpdateEnterpriseSuite(data *enterprise_wechat.SuiteTicketInfo) error {
if data.SuiteTicket != "" && data.TimeStamp > 0 {
EnterpriseSuite = data
}
// 修改数据库
db := dao.GetDB()
config := &legacymodel.Config{
Thirdparty: "enterprise",
Token: data.SuiteTicket,
Date: string(data.TimeStamp),
LastOperator: model.AdminName,
RefreshToken: data.SuiteId,
}
return dao.CreateOrUpdate(db, config)
}

View File

@@ -1,484 +0,0 @@
package enterprise
import (
"fmt"
"git.rosy.net.cn/baseapi/platformapi/ebaiapi"
"git.rosy.net.cn/baseapi/platformapi/jdapi"
"git.rosy.net.cn/baseapi/platformapi/mtwmapi"
//"git.rosy.net.cn/baseapi/platformapi/mtwmapi"
tao "git.rosy.net.cn/baseapi/platformapi/tao_vegetable"
domain585 "git.rosy.net.cn/baseapi/platformapi/tao_vegetable/sdk/ability585/domain"
request585 "git.rosy.net.cn/baseapi/platformapi/tao_vegetable/sdk/ability585/request"
product_listV2_request "git.rosy.net.cn/baseapi/platformapi/tiktok_shop/sdk-golang/api/product_listV2/request"
product_listV2_response "git.rosy.net.cn/baseapi/platformapi/tiktok_shop/sdk-golang/api/product_listV2/response"
sku_syncStock_request "git.rosy.net.cn/baseapi/platformapi/tiktok_shop/sdk-golang/api/sku_syncStock/request"
"git.rosy.net.cn/baseapi/platformapi/tiktok_shop/tiktok_api"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxstore/cms"
"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"
"git.rosy.net.cn/jx-callback/globals/api/apimanager"
beego "github.com/astaxie/beego/server/web"
"strings"
)
// 该函数主要用于对比京西平台商品和各个平台门店商品的差异
// 对比上下架状态以及商品价格差异,相同的不做修改,不同的以京西系统商品为主
func CompareJxVendorSku(jxStoreId int, vendorIds []int) (string, error) {
var (
db = dao.GetDB()
errListToStr = new(strings.Builder)
)
skuList, err := dao.GetStoresSkusInfo(db, []int{jxStoreId}, nil)
if err != nil {
return "", err
}
// 门店商品列表平
skuMap := make(map[string]*model.StoreSkuBind, 0)
skuIdList := make([]string, 0, len(skuList))
for _, v := range skuList {
localSkuId := utils.Int2Str(v.SkuID)
skuMap[localSkuId] = v
skuIdList = append(skuIdList, localSkuId)
}
// 有效的三方平台
storeMap, err := dao.GetStoresMapList(db, vendorIds, []int{jxStoreId}, []int{model.StoreStatusOpened, model.StoreStatusClosed, model.StoreStatusHaveRest}, model.StoreStatusDisabled, 1, "", "", "")
if err != nil {
return "", err
}
for _, sm := range storeMap {
switch sm.VendorID {
case model.VendorIDJD:
if errs := JdSyncSkuPriceAndStatus(db, sm, skuMap); err != nil {
errListToStr.WriteString(errs.Error())
globals.SugarLogger.Debugf("京东同步商品异常信息: %v", errs)
}
continue
case model.VendorIDMTWM:
if errs := MtWmSyncSkuPriceAndStatus(db, sm, skuMap); errs != nil {
errListToStr.WriteString(errs.Error())
globals.SugarLogger.Debugf("美团同步商品异常信息: %v", errs)
}
continue
case model.VendorIDEBAI:
if errs := EBaiSyncSkuPriceAndStatus(db, sm, skuMap); errs != nil {
errListToStr.WriteString(errs.Error())
globals.SugarLogger.Debugf("饿百同步商品异常信息: %v", errs)
}
continue
case model.VendorIDDD:
if errs := TiktokSyncSkuPriceAndStatus(db, sm, skuMap); errs != nil {
errListToStr.WriteString(errs.Error())
globals.SugarLogger.Debugf("抖音同步商品异常信息: %v", errs)
}
continue
case model.VendorIDTaoVegetable:
if errs := TaoSyncSkuPriceAndStatus(db, sm, skuMap, skuIdList); errs != nil {
errListToStr.WriteString(errs.Error())
globals.SugarLogger.Debugf("淘宝同步商品异常信息: %v", errs)
}
continue
default:
return errListToStr.String(), fmt.Errorf("无法识别的平台id")
}
}
return "", err
}
// MtWmSyncSkuPriceAndStatus 校验美团平台和京西系统商品差异
func MtWmSyncSkuPriceAndStatus(db *dao.DaoDB, sm *model.StoreMap, skuMap map[string]*model.StoreSkuBind) (err error) {
var (
mtApi = apimanager.CurAPIManager.GetAPI(sm.VendorID, sm.VendorOrgCode).(*mtwmapi.API)
i = model.NO
foodListData = make([]*mtwmapi.AppFood, 0, 0)
errs = make([]string, 0, 0)
vendorStatus = 0
)
if len(skuMap) == 0 || sm.IsSync != model.YES {
return fmt.Errorf("门店未打开同步或者未关注商品")
}
if sm.VendorOrgCode == globals.Mtwm2Code {
mtApi = mtwmapi.New(beego.AppConfig.DefaultString("mtwmAppID2", ""), beego.AppConfig.DefaultString("mtwmSecret2", ""), beego.AppConfig.DefaultString("mtwmCallbackURL2", ""), "")
mtApi.SetToken(sm.MtwmToken)
} else {
mtApi = partner.CurAPIManager.GetAPI(model.VendorIDMTWM, sm.VendorOrgCode).(*mtwmapi.API)
}
for {
foodList, err := mtApi.RetailListAll(sm.VendorStoreID, i)
if err != nil {
globals.SugarLogger.Debugf("美团商品价格和上下架状态获取平台商品异常 :%v", err)
break
}
foodListData = append(foodListData, foodList...)
if len(foodList) < 100 {
break
}
i++
}
for _, vsl := range foodListData {
if sku, ok := skuMap[vsl.AppFoodCode]; ok {
// 同步商品价格
if utils.Float64TwoInt(vsl.Price*float64(100)) != sku.MtwmPrice {
_, err = cms.CurVendorSync.SyncStoresSkus2(jxcontext.AdminCtx, nil, 0, db, []int{sm.VendorID}, []int{sku.StoreID}, false, []int{sku.SkuID}, []int{27379}, model.SyncFlagPriceMask, true, true)
if err != nil {
errs = append(errs, fmt.Sprintf("skuCode:%d,修改美团价格错误:%v", sku.SkuID, err))
}
}
// 同步商品上下架状态
// SPU可能包含多个SKU上下架状态字段取值范围0-全部sku上架1-全部sku下架。以下功能灰度中若同时传递sku_is_sold_out则优先根据sku_is_sold_out传参判断单个sku的上下架状态。
// 本地sku.Status 0-不可售, 1-可售
if vsl.IsSoldOut == sku.Status {
if sku.Status == model.SkuStatusNormal {
vendorStatus = mtwmapi.SellStatusOnline
} else {
vendorStatus = mtwmapi.SellStatusOffline
}
param := []*mtwmapi.BareStoreFoodInfo{
&mtwmapi.BareStoreFoodInfo{
AppFoodCode: utils.Int64ToStr(sku.MtwmID),
Skus: nil,
},
}
foodErrList, err := mtApi.RetailSellStatus(jxcontext.AdminCtx.GetTrackInfo(), sm.VendorStoreID, param, vendorStatus)
if err != nil {
errs = append(errs, fmt.Sprintf("skuCode:%d,修改美团可售状态错误%v", sku.SkuID, err))
}
for _, fel := range foodErrList {
errs = append(errs, fmt.Sprintf("skuCode:%s,修改美团可售状态错误:%s", fel.AppFoodCode, fel.ErrorMsg))
}
}
} else {
param := []*mtwmapi.BareStoreFoodInfo{
&mtwmapi.BareStoreFoodInfo{
AppFoodCode: vsl.AppFoodCode,
Skus: nil,
},
}
foodErrList, err := mtApi.RetailSellStatus(jxcontext.AdminCtx.GetTrackInfo(), sm.VendorStoreID, param, mtwmapi.SellStatusOffline)
if err != nil {
errs = append(errs, fmt.Sprintf("skuCode:%d,修改美团可售状态错误%v", vsl.AppFoodCode, err))
}
for _, fel := range foodErrList {
errs = append(errs, fmt.Sprintf("skuCode:%s,修改美团可售状态错误:%s", fel.AppFoodCode, fel.ErrorMsg))
}
}
}
if len(errs) == model.NO {
return nil
}
return fmt.Errorf("%s", strings.Join(errs, ","))
}
// EBaiSyncSkuPriceAndStatus 校验饿了么平台和京西系统商品差异
func EBaiSyncSkuPriceAndStatus(db *dao.DaoDB, sm *model.StoreMap, skuMap map[string]*model.StoreSkuBind) (err error) {
var (
ebaiApi = apimanager.CurAPIManager.GetAPI(sm.VendorID, sm.VendorOrgCode).(*ebaiapi.API)
//skuIdOffset = 0
foodListData = make([]*ebaiapi.SkuInfo, 0, 0)
errs = make([]string, 0, 0)
)
if len(skuMap) == 0 || sm.IsSync != model.YES {
return fmt.Errorf("门店未打开同步或者未关注商品")
}
for {
page := 1
param := &ebaiapi.SkuListParams{
Page: page,
PageSize: 100,
//SkuIdOffset: skuIdOffset,
}
foodList, err := ebaiApi.SkuList(utils.Int2Str(sm.StoreID), param)
if err != nil {
globals.SugarLogger.Debugf("饿了么商品价格和上下架状态获取平台商品异常 :%v", err)
break
}
foodListData = append(foodListData, foodList.List...)
if len(foodList.List) < 100 {
break
}
//skuIdOffset = foodList.SkuIdOffset
page += 1
}
globals.SugarLogger.Debugf("======len foodListData:= %d", len(foodListData))
globals.SugarLogger.Debugf("======len skuMap:= %d", len(skuMap))
for _, vsl := range foodListData {
if sku, ok := skuMap[vsl.CustomSkuId]; ok {
// 同步商品价格
if vsl.SalePrice != sku.EbaiPrice {
_, err = cms.CurVendorSync.SyncStoresSkus2(jxcontext.AdminCtx, nil, 0, db, []int{sm.VendorID}, []int{sku.StoreID}, false, []int{sku.SkuID}, []int{27379}, model.SyncFlagPriceMask, true, true)
}
// 同步商品上下架状态
// 1为上架0为下架
// 本地sku.Status 0-不可售, 1-可售
if vsl.Status != utils.Int2Str(sku.Status) {
// 平台上架本地下架,将平台商品下架
if sku.Status == model.StoreSkuBindStatusNormal {
ebailResult, err := ebaiApi.SkuOnline(jxcontext.AdminCtx.GetTrackInfo(), utils.Int2Str(sm.StoreID), []int64{sku.EbaiID}, nil, nil)
if err != nil {
errs = append(errs, fmt.Sprintf("skuCode:%d,修改饿百可售状态错误%v", sku.SkuID, err))
}
for _, fel := range ebailResult.FailedList {
errs = append(errs, fmt.Sprintf("skuCode:%d,修改饿百可售状态错误:%s", fel.SkuID, fel.ErrorMsg))
}
} else {
err = ebaiApi.SkuOfflineOne(jxcontext.AdminCtx.GetTrackInfo(), utils.Int2Str(sm.StoreID), sku.EbaiID, "", "")
if err != nil {
errs = append(errs, fmt.Sprintf("skuCode:%d,修改饿百不可售状态错误%v", sku.SkuID, err))
}
}
}
} else {
_, err = ebaiApi.SkuDelete(jxcontext.AdminCtx.GetTrackInfo(), utils.Int2Str(sm.StoreID), nil, []string{vsl.CustomSkuId})
//err = ebaiApi.SkuOfflineOne(jxcontext.AdminCtx.GetTrackInfo(), utils.Int2Str(sm.StoreID), utils.Str2Int64(vsl.CustomSkuId), "", "")
if err != nil {
errs = append(errs, fmt.Sprintf("skuCode:%d,修改饿百不可售状态错误%v", sku.SkuID, err))
}
}
}
if len(errs) == model.NO {
return nil
}
return fmt.Errorf("%s", strings.Join(errs, ","))
}
// TaoSyncSkuPriceAndStatus 校验淘宝平台和京西系统商品差异
func TaoSyncSkuPriceAndStatus(db *dao.DaoDB, sm *model.StoreMap, skuMap map[string]*model.StoreSkuBind, skuIdList []string) (err error) {
var (
taoApi = apimanager.CurAPIManager.GetAPI(sm.VendorID, sm.VendorOrgCode).(*tao.API)
length = len(skuIdList) / 100
foodListData = make([]domain585.AlibabaWdkSkuQuerySkuDo, 0, 0)
onlineStatus int64 = 0
)
if len(skuMap) == 0 || sm.IsSync != model.YES {
return fmt.Errorf("门店未打开同步或者未关注商品")
}
if len(skuIdList)%100 != 0 {
length += 1
}
// 获取平台商品列表
for i := 0; i < length; i++ {
skuCods := skuIdList[i*100 : (i+1)*100]
foodList, _ := taoApi.QueryStoreSKu(&request585.AlibabaWdkSkuQueryRequest{Param: &domain585.AlibabaWdkSkuQuerySkuQueryDo{
OuCode: utils.String2Pointer(sm.VendorStoreID),
SkuCodes: &skuCods,
}})
for _, fl := range *foodList {
if *fl.Success {
foodListData = append(foodListData, *fl.Model)
}
}
}
// 比较商品差异
errs := make([]string, 0, 0)
for _, vsl := range foodListData {
if sku, ok := skuMap[*vsl.SkuCode]; ok {
// 同步商品价格
if utils.Float64TwoInt(utils.Str2Float64(*vsl.SalePrice)*float64(100)) != sku.TaoPrice {
_, err = cms.CurVendorSync.SyncStoresSkus2(jxcontext.AdminCtx, nil, 0, db, []int{sm.VendorID}, []int{sku.StoreID}, false, []int{sku.SkuID}, []int{27379}, model.SyncFlagPriceMask, true, true)
if err != nil {
errs = append(errs, fmt.Sprintf("淘宝对比商品价格异常skuid:%d,错误%v", sku.SkuID, err))
}
}
// 同步商品上下架状态
// 是否线上可售 是 0否 1是。
// 本地sku.Status 0-不可售, 1-可售
if int(*vsl.OnlineSaleFlag) != sku.Status {
// 平台上架本地下架,将平台商品下架
param := &request585.AlibabaWdkSkuUpdateRequest{}
updateSkuList := make([]domain585.AlibabaWdkSkuUpdateSkuDo, 0, 0)
if sku.Status == model.SkuStatusNormal {
onlineStatus = tao.CreateOnlineSaleFlag
} else {
onlineStatus = tao.CreateOfflineSaleFlag
}
updateSkuList = append(updateSkuList, domain585.AlibabaWdkSkuUpdateSkuDo{
OuCode: utils.String2Pointer(utils.Int64ToStr(sku.TaoID)),
SkuCode: utils.String2Pointer(utils.Int2Str(sku.SkuID)),
OnlineSaleFlag: utils.Int64ToPointer(onlineStatus),
SubTitle: utils.String2Pointer("小时达"),
AllowAppSale: utils.Int64ToPointer(onlineStatus),
//CleanSkuMemberPrice: utils.Int64ToPointer(model.YES),
})
param.ParamList = &updateSkuList
result, err := taoApi.UpdateStoreSku(param)
if err != nil {
errs = append(errs, fmt.Sprintf("skuCode:%d,修改饿百可售状态错误%v", sku.SkuID, err))
}
for _, fel := range *result {
if fel.ErrMsg != "" {
errs = append(errs, fmt.Sprintf("skuCode:%s,修改饿百可售状态错误:%s", fel.SkuID, fel.ErrMsg))
}
}
//_, err = cms.CurVendorSync.SyncStoresSkus2(jxcontext.AdminCtx, nil, 0, db, []int{sm.VendorID}, []int{sku.StoreID}, false, []int{sku.SkuID}, []int{27379}, 56, true, true)
//if err != nil {
// errs = append(errs, fmt.Sprintf("%v", err))
//}
}
} else {
// 平台上架本地下架,将平台商品下架
param := &request585.AlibabaWdkSkuUpdateRequest{}
updateSkuList := make([]domain585.AlibabaWdkSkuUpdateSkuDo, 0, 0)
onlineStatus = tao.CreateOfflineSaleFlag
updateSkuList = append(updateSkuList, domain585.AlibabaWdkSkuUpdateSkuDo{
OuCode: vsl.OuCode,
SkuCode: vsl.SkuCode,
OnlineSaleFlag: utils.Int64ToPointer(onlineStatus),
SubTitle: utils.String2Pointer("小时达"),
AllowAppSale: utils.Int64ToPointer(onlineStatus),
//CleanSkuMemberPrice: utils.Int64ToPointer(model.YES),
})
param.ParamList = &updateSkuList
result, err := taoApi.UpdateStoreSku(param)
if err != nil {
errs = append(errs, fmt.Sprintf("skuCode:%d,修改饿百可售状态错误%v", sku.SkuID, err))
}
for _, fel := range *result {
if fel.ErrMsg != "" {
errs = append(errs, fmt.Sprintf("skuCode:%s,修改饿百可售状态错误:%s", fel.SkuID, fel.ErrMsg))
}
}
}
}
if len(errs) == model.NO {
return nil
}
return fmt.Errorf("%s", strings.Join(errs, ","))
}
// TiktokSyncSkuPriceAndStatus 校验抖音平台和京西系统商品差异
func TiktokSyncSkuPriceAndStatus(db *dao.DaoDB, sm *model.StoreMap, skuMap map[string]*model.StoreSkuBind) (err error) {
var (
tiktokApi = apimanager.CurAPIManager.GetAPI(sm.VendorID, sm.VendorOrgCode).(*tiktok_api.API)
page = 0
foodListData = make([]product_listV2_response.DataItem, 0, 0)
errs = make([]string, 0, 0)
)
if len(skuMap) == 0 || sm.IsSync != model.YES {
return fmt.Errorf("门店未打开同步或者未关注商品")
}
for {
param := &product_listV2_request.ProductListV2Param{
Page: int64(page),
Size: 100,
StoreId: utils.Str2Int64(sm.VendorStoreID),
}
foodList, err := tiktokApi.GetSkuDetailList(param)
if err != nil {
globals.SugarLogger.Debugf("抖音商品价格和上下架状态获取平台商品异常 :%v", err)
break
}
foodListData = append(foodListData, foodList.Data...)
if len(foodList.Data) < 100 {
break
}
page += 1
}
for _, vsl := range foodListData {
if sku, ok := skuMap[vsl.OuterProductId]; ok {
// 同步商品价格
if vsl.DiscountPrice != int64(sku.DdPrice) {
_, err = cms.CurVendorSync.SyncStoresSkus2(jxcontext.AdminCtx, nil, 0, db, []int{sm.VendorID}, []int{sku.StoreID}, false, []int{sku.SkuID}, []int{27379}, model.SyncFlagPriceMask, true, true)
if err != nil {
errs = append(errs, fmt.Sprintf("抖音对比商品价格异常skuid:%d,错误%v", sku.SkuID, err))
}
}
// 同步商品上下架状态
// 0-在线 1-下线
// 本地sku.Status 0-不可售,1-可售
if vsl.Status == int64(sku.Status) {
if sku.Status == model.SkuStatusNormal {
param := &sku_syncStock_request.SkuSyncStockParam{
ProductId: sku.DdID,
Incremental: false,
StockNum: 99999,
OutSkuId: int64(sku.SkuID),
}
if err = tiktokApi.UpdateSkuStock(param); err != nil {
errs = append(errs, fmt.Sprintf("抖音对比商品上架异常skuid:%d,错误%v", sku.SkuID, err))
}
} else {
param := &sku_syncStock_request.SkuSyncStockParam{
ProductId: sku.DdID,
Incremental: false,
StockNum: 0,
OutSkuId: int64(sku.SkuID),
}
if err = tiktokApi.UpdateSkuStock(param); err != nil {
errs = append(errs, fmt.Sprintf("抖音对比商品下架异常skuid:%d,错误%v", sku.SkuID, err))
}
}
}
} else {
param := &sku_syncStock_request.SkuSyncStockParam{
ProductId: sku.DdID,
Incremental: false,
StockNum: 0,
OutSkuId: int64(sku.SkuID),
}
if err = tiktokApi.UpdateSkuStock(param); err != nil {
errs = append(errs, fmt.Sprintf("抖音对比商品下架异常skuid:%d,错误%v", sku.SkuID, err))
}
}
}
if len(errs) == model.NO {
return nil
}
return fmt.Errorf("%s", strings.Join(errs, ","))
}
// JdSyncSkuPriceAndStatus 校验京东平台和京西系统商品差异
func JdSyncSkuPriceAndStatus(db *dao.DaoDB, sm *model.StoreMap, skuMap map[string]*model.StoreSkuBind) (err error) {
var (
jdsApi = apimanager.CurAPIManager.GetAPI(sm.VendorID, sm.VendorOrgCode).(*jdapi.API)
)
skuVendibilityList := make([]*jdapi.StockVendibility, 0, 0)
for _, v := range skuMap {
skuVendibilityList = append(skuVendibilityList, &jdapi.StockVendibility{
OutSkuId: utils.Int2Str(v.SkuID),
DoSale: v.Status == model.SkuStatusNormal,
})
}
count := len(skuVendibilityList) / 50
if len(skuVendibilityList)%50 != 0 {
count += 1
}
for i := 1; i <= count; i++ {
if i == count {
jdsApi.BatchUpdateVendibility(jxcontext.AdminCtx.GetTrackInfo(), "", sm.VendorStoreID, skuVendibilityList[(i-1)*50:], jxcontext.AdminCtx.GetUserName())
} else {
jdsApi.BatchUpdateVendibility(jxcontext.AdminCtx.GetTrackInfo(), "", sm.VendorStoreID, skuVendibilityList[(i-1)*50:i*50], jxcontext.AdminCtx.GetUserName())
}
}
return fmt.Errorf("京东运行结束")
}

View File

@@ -1,182 +0,0 @@
package enterprise_session
import (
"errors"
"fmt"
enterprise "git.rosy.net.cn/baseapi/platformapi/enterprise_wechat"
"git.rosy.net.cn/jx-callback/business/auth2"
"git.rosy.net.cn/jx-callback/business/authz"
"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/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/globals/api"
"strconv"
"strings"
)
type CreateSession struct {
}
// 创建老板的业务群
func (c *CreateSession) CreateBossToStaffAndCreateSession(token string, storeId int) (map[string]interface{}, error) {
// 获取老本的电话和门店信息
authInfo, err := auth2.GetTokenInfo(token)
if err != nil {
return nil, err
}
store, err := dao.GetStoreDetail2(dao.GetDB(), storeId, "", 0)
if err != nil {
return nil, err
}
if store.Tel1 != authInfo.Mobile || store.Tel1 == "" {
return nil, errors.New("不是门店老板,不创建群聊")
}
// 检测用户是否存在
if _, err := CheckUserExist(store); err != nil {
return nil, err
}
// 获取创建群聊所需基础人员id
enterpriseIdList, err := CheckBoosGroupChat(store)
if err != nil {
return nil, err
}
result := make(map[string]interface{}, 0)
result["enterpriseIdList"] = enterpriseIdList
result["chatName"] = "京西菜市" + store.Name + "群"
return result, nil
}
// 检测用户是否存在
func CheckUserExist(store *dao.StoreDetail2) (string, error) {
enterpriseUserId, err := api.EnterpriseChatHeadApi.GetUserIdByMobile(store.Tel1)
if strings.Contains(fmt.Sprintf("%v", err), "user no exist") || strings.Contains(fmt.Sprintf("%v", err), "46004") {
boss := &enterprise.CreateBoos2JXStaffReq{
Userid: store.Tel1 + "_" + strconv.Itoa(store.ID),
Name: store.LicenceOwnerName,
Alias: "",
Mobile: store.Tel1,
Department: nil, // 四川省
Order: nil,
Gender: "1",
Email: "",
IsLeaderInDept: nil,
Enable: 0,
AvatarMediaid: "",
Telephone: "",
Address: store.Address,
Extattr: enterprise.Extattr{},
MainDepartment: 0,
ToInvite: true,
ExternalPosition: "",
ExternalProfile: enterprise.ExternalProfile{},
}
if boss.Name == "" {
boss.Name = store.Name + "(老板名称不存在)"
}
// 查询本门店所属省code
parentCityName := ""
if store.CityCode == 0 {
return "", errors.New("门店位置不能为空")
}
parentCityName, err = GetCityCode(store.CityCode)
if err != nil {
return "", err
}
// 查询企业微信所有省份部门分类
departmentList, err := api.EnterpriseChatHeadApi.GetAllDepartmentList()
if err != nil {
return "", err
}
for _, v := range departmentList {
if !strings.Contains(v.Name, parentCityName[:6]) {
continue
}
boss.Department = []int{v.ID}
break
}
// 创建老板为京西员工,并存放在对应的省份里面
if err := api.EnterpriseChatHeadApi.CreateBoss2JxStaff(boss); err != nil {
return "", err
}
enterpriseUserId = boss.Userid
}
return enterpriseUserId, err
}
func GetCityCode(cityCode int) (string, error) {
for i := 0; i < 4; i++ {
place, err := dao.GetPlaceByCode(dao.GetDB(), cityCode)
if err != nil {
return "", err
}
if place.Level == model.YES && place.ParentCode == 0 {
return place.Name, nil
}
cityCode = place.ParentCode
}
return "", errors.New("未查询到目标城市")
}
// 获取当前门店企业内部人员信息
func CheckBoosGroupChat(store *dao.StoreDetail2) ([]string, error) {
// 获取门店角色
roleNames := []string{"StoreBoss"}
storeIDs := []int{store.ID}
var roleList []*authz.RoleInfo
for _, roleName := range roleNames {
if roleName == authz.StoreRoleBoss {
for _, storeID := range storeIDs {
roleList = append(roleList, autils.NewRole(roleName, storeID))
}
} else {
roleList = append(roleList, autils.NewRole(roleName, 0))
}
}
retVal, err := cms.GetRolesUserList(nil, roleList)
if err != nil {
return nil, err
}
// 获取角色系统userId
systemUserId := make([]string, 0, 0)
for _, v := range retVal {
if len(v) == 0 {
return nil, errors.New("门店负责人为空,数据异常.联系管理员")
}
systemUserId = append(systemUserId, v...)
}
// 根据userId获取系统用户电话号码
userList, _, err := dao.GetUsers(dao.GetDB(), 0, "", systemUserId, nil, nil, 0, 50)
if err != nil {
return nil, err
}
enterpriseList := make([]string, 0, 0)
// 获取用户企业微信用户id
for _, v := range userList {
enterpriseId, err := api.EnterpriseChatHeadApi.GetUserIdByMobile(*v.Mobile)
if err != nil {
continue
}
enterpriseList = append(enterpriseList, enterpriseId)
}
return enterpriseList, nil
}
// 获取企业微信token
func GetEnterpriseTokenInfo() (string, string) {
api.EnterpriseChatMin.CheckAccessTokenExpiresIn()
api.EnterpriseChatHeadApi.CheckAccessTokenExpiresIn()
return api.EnterpriseChatMin.ReturnToken(), api.EnterpriseChatHeadApi.ReturnToken()
// 企业微信api
//return api.EnterpriseChatHeadApi.ReturnToken()
}

View File

@@ -1,188 +0,0 @@
package auto_delivery
import (
"crypto/rand"
"encoding/json"
"fmt"
"git.rosy.net.cn/baseapi/platformapi/tao_vegetable"
"git.rosy.net.cn/jx-callback/business/jxcallback/scheduler/defsch"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/partner"
"math/big"
"strings"
"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/globals"
)
var riderListInfo = make(map[string][]map[string]string, 0)
func Init() {
if len(riderListInfo) != 0 {
return
}
db := dao.GetDB()
// 骑手列表
configRiderList, err := dao.QueryConfigs(db, "riderList", "Sys", "")
if err != nil {
globals.SugarLogger.Errorf("抖音自动刷单获取骑手列表错误:%v", err)
return
}
list := make(map[string][]map[string]string, 0)
if len(configRiderList[0].Value) > 0 {
if err := json.Unmarshal([]byte(configRiderList[0].Value), &list); err != nil {
globals.SugarLogger.Errorf("抖音自动刷单获取骑手列表错误:%v", err)
return
}
}
// 获取刷单地址
addressList, err := dao.QueryConfigs(db, "refundAddress", "Sys", "")
if err != nil {
globals.SugarLogger.Errorf("抖音自动刷单获取刷单地址列表错误:%v", err)
return
}
for _, v := range strings.Split(addressList[0].Value, ",") {
if _, ok := list[v]; ok && len(list[v]) >= 200 {
continue
}
riderList, err := dao.GetAddressRiderInfo(db, v)
if err != nil {
globals.SugarLogger.Errorf("初始化各省份骑手信息错误:[%v]", err)
return
}
addressRiderList := make([]map[string]string, 0)
for i := 0; i < len(riderList); i++ {
if len(riderList[i].CourierMobile) == 11 {
riderMap := make(map[string]string, 1)
riderMap[riderList[i].CourierName] = riderList[i].CourierMobile
addressRiderList = append(addressRiderList, riderMap)
}
if len(addressRiderList) >= 200 {
list[v] = addressRiderList
break
}
}
}
listStr, err := json.Marshal(list)
if err != nil {
globals.SugarLogger.Errorf("Marshal 骑手信息错误:[%v]", err)
return
}
if err := dao.UpdateOperatorConfig(string(listStr), "Sys", "riderList"); err != nil {
globals.SugarLogger.Errorf("UpdateOperatorConfig 骑手配置信息错误:[%v]", err)
return
}
riderListInfo = list
}
// AutoSettingFakeDelivery 抖音自动设置骑手, 推送假订单
func AutoSettingFakeDelivery() {
db := dao.GetDB()
// 查询需要刷单的门店
configList, err := dao.QueryConfigs(db, "storeIdList", "Sys", "")
if err != nil {
globals.SugarLogger.Errorf("抖音自动刷单获取刷单门店列表错误:%v", err)
return
}
if len(configList) != model.YES {
globals.SugarLogger.Errorf("newConfig 刷单门店设置异常")
return
}
// 获取刷单门店订单
storeList := strings.Split(configList[0].Value, ",")
for _, v := range storeList {
if !strings.Contains(v, "-") {
globals.SugarLogger.Errorf("newConfig 刷单门店配置异常")
return
}
storeIdAndVendorId := strings.Split(v, "-")
if len(storeIdAndVendorId) == model.NO {
continue
}
orderList, err := dao.GetOrderListByStoreList(db, []int64{utils.Str2Int64(storeIdAndVendorId[0])}, utils.Str2Int(storeIdAndVendorId[1]))
if err != nil {
globals.SugarLogger.Errorf("获取门店刷单记录错误")
continue
}
if len(orderList) == model.NO {
continue
}
// 1.根据订单客户地址获取骑手列表
riderKey := ""
storeDetail, _ := dao.GetStoreDetail(db, utils.Str2Int(storeIdAndVendorId[0]), 0, "")
if strings.Contains(storeDetail.Address, "重庆") || strings.Contains(storeDetail.Address, "上海") || strings.Contains(storeDetail.Address, "北京") || strings.Contains(storeDetail.Address, "天津") {
riderKey = strings.Split(storeDetail.Address, "市")[0]
} else if strings.Contains(storeDetail.Address, "省") {
riderKey = strings.Split(storeDetail.Address, "省")[0]
} else {
place, err := dao.GetParentCodeByCode(db, storeDetail.CityCode)
if err != nil {
return
}
if strings.Contains(place.Name, "省") {
riderKey = strings.Split(place.Name, "省")[0]
} else {
riderKey = strings.Split(place.Name, "市")[0]
}
}
for _, order := range orderList {
if len(riderListInfo[riderKey]) == model.NO {
// 骑手列表
configRiderList, err := dao.QueryConfigs(db, "riderList", "Sys", "")
if err != nil {
globals.SugarLogger.Errorf("抖音自动刷单获取骑手列表错误:%v", err)
return
}
if err := json.Unmarshal([]byte(configRiderList[0].Value), &riderListInfo); err != nil {
globals.SugarLogger.Errorf("抖音自动刷单获取骑手列表错误:%v", err)
return
}
}
randNumber, _ := rand.Int(rand.Reader, big.NewInt(int64(len(riderListInfo[riderKey]))))
randTime := randNumber.Int64()
if randTime < 0 {
randTime = 1
}
if randTime >= int64(len(riderListInfo[riderKey])) {
randTime = int64(len(riderListInfo[riderKey])) - 1
}
if (order.PhoneAscription == "" || strings.Split(order.PhoneAscription, "-")[0] != model.PhoneAscriptionAddressYes) && order.VendorID == model.VendorIDDD {
continue
}
// 自动拣货
if order.Status < model.OrderStatusFinishedPickup { // 未拣货
handler := partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID)
flag := model.IsOrderDeliveryByStore(order) || model.IsOrderDeliveryBySelf(order)
if err := handler.PickupGoods(order, flag, jxcontext.AdminCtx.GetUserName()); err != nil {
partner.CurOrderManager.OnOrderMsg(order, tao_vegetable.OrderStatusPickedUp, fmt.Sprintf("自动拣货错误:[%v]", err))
break
}
partner.CurOrderManager.OnOrderMsg(order, tao_vegetable.OrderStatusPickedUp, "fake自动拣货,已拣货")
}
//自动发单
if len(riderListInfo[riderKey]) == 0 {
globals.SugarLogger.Errorf("riderListInfo[riderKey][randTime] :%s,%s,%d", riderListInfo[riderKey][randTime], riderKey, randTime)
break
}
for riderName, riderPhone := range riderListInfo[riderKey][randTime] {
if err := defsch.FixedScheduler.SelfDeliveringAndUpdateStatus(jxcontext.AdminCtx, order.VendorOrderID, order.VendorID, jxcontext.AdminCtx.GetUserName(), riderName, riderPhone); err != nil {
partner.CurOrderManager.OnOrderMsg(order, tao_vegetable.OrderStatusPickedUp, fmt.Sprintf("自动发货错误:[%v]", err))
break
}
partner.CurOrderManager.OnOrderMsg(order, tao_vegetable.OrderStatusCallRider, "自动发货,出库")
}
}
}
}

View File

@@ -1,71 +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, "", nil)
return err
}
func notifyWxNewFakeJdOrder(order *model.GoodsOrder, storeID int) (err error) {
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()
_, 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,252 +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) {
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) {
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) {
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) {
return err
}
dao.Rollback(db, txDB)
return nil
}
dao.Commit(db, txDB)
return err
}
// 处理售后订单结账信息
func (c *OrderManager) SaveAfsOrderFinancialInfo(afsOrder *model.AfsOrder) (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)
}
}
}()
// 平台结算扣除汇总--平台补贴,售后产生运费,平台收包装费,同城运费、、、
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) {
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) {
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 {
return err
}
dao.Commit(db, txDB)
// orderFinancial 和 OrderSkuFinancial 数据计算完毕,准备进行更新
return err
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,447 +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()
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
}
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)
if err != nil || (isDuplicated && orderStatus.VendorID != model.VendorIDJX) {
if err == nil {
dao.Commit(db, txDB)
}
return err
}
existAfsOrder, err := c.loadAfsOrder(db, afsOrder.AfsOrderID, afsOrder.VendorID)
if err != nil {
if !dao.IsNoRowsError(err) {
return err
}
}
if existAfsOrder != nil {
if existAfsOrder.Status < model.AfsOrderStatusFinished {
// todo 可能导致状态回绕
existAfsOrder.Status = afsOrder.Status
existAfsOrder.VendorStatus = afsOrder.VendorStatus
if _, err = dao.UpdateEntity(db, existAfsOrder, "Status", "VendorStatus", "AfsFinishedAt"); 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) {
if db == nil {
db = dao.GetDB()
}
if err = c.updateAfsOrderOtherInfo(db, afsOrder); err != nil {
return err
}
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 {
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 {
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 {
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) {
if db == nil {
db = dao.GetDB()
}
isDuplicated, err = addOrderOrWaybillStatus(orderStatus, db)
//if err == nil && !isDuplicated && (orderStatus.Status != model.OrderStatusUnknown && orderStatus.Status != model.OrderStatusMsg) {
if err == nil && (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 orderStatus.VendorID == model.VendorIDDD {
order.Flag = 0
if strings.Contains(orderStatus.VendorStatus, "cancel_refund_afsOrder") {
order.Flag = 3
}
updateFields = append(updateFields, "Flag")
}
if model.IsAfsOrderFinalStatus(orderStatus.Status) || orderStatus.Status == model.AfsOrderStatusNew {
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")
}
}
}
_, err = dao.UpdateEntity(db, order, updateFields...)
//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 model.IsAfsOrderFinalStatus(orderStatus.Status) || orderStatus.Status == model.AfsOrderStatusNew && order.VendorID == model.VendorIDMTWM {
if afsOrderObj, _ := partner.CurOrderManager.LoadAfsOrder(orderStatus.VendorOrderID, orderStatus.VendorID); afsOrderObj != nil {
afsOrderObj.AfsFinishedAt = time.Now()
afsOrderObj.Status = orderStatus.Status
dao.UpdateEntity(db, afsOrderObj, "AfsFinishedAt", "Status")
}
}
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) {
jxStoreID := jxutils.GetSaleStoreIDFromAfsOrder(order)
opNumStr := "2"
if jxStoreID == 0 {
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 {
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 {
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) {
if afsOrder.VendorStoreID != "" {
if storeDetail, err := dao.GetStoreDetailByVendorStoreID(db, afsOrder.VendorStoreID, 0, ""); err == nil {
afsOrder.JxStoreID = storeDetail.Store.ID
}
}
order, err2 := c.LoadOrder(afsOrder.VendorOrderID, afsOrder.VendorID)
if afsOrder.StoreID == 0 && afsOrder.JxStoreID == 0 {
if 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)
if afsOrder.RefundType == model.AfsTypeFullRefund && afsOrder.VendorID == model.VendorIDJX && order.DeliveryType != model.OrderDeliveryTypeSelfTake {
afsOrder.SkuUserMoney = order.ActualPayPrice
}
}
}
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) {
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)
}
}
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)
if err == nil {
afsOrder = &model.AfsOrder{
VendorID: vendorID,
VendorOrderID: vendorOrderID,
JxStoreID: order.JxStoreID,
VendorStoreID: order.VendorStoreID,
StoreID: order.StoreID,
VendorOrgCode: order.VendorOrgCode,
}
} else {
return nil, err
}
for _, sku := range order.Skus {
orderSkuFinancial := &model.OrderSkuFinancial{
VendorID: sku.VendorID,
VendorOrderID: sku.VendorOrderID,
VendorSubOrderID: sku.VendorSubOrderID,
// 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,223 +0,0 @@
package orderman
import (
"encoding/json"
"git.rosy.net.cn/jx-callback/business/jxstore/cms"
"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"
)
type tReplyConfig struct {
DelayGapBegin int `json:"delayGapBegin"`
DelayGapEnd int `json:"delayGapEnd"`
Comments []string `json:"comments"`
}
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) {
db := dao.GetDB()
for _, orderComment := range orderCommentList {
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 > cms.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 > cms.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 = cms.COMMENT_NOT_RESOLVED
comment2.OrderFlag = utils.Int2Str(orderComment.VendorID)
comment2.Maxmodifytime = int(orderComment.ModifyDuration)
comment2.VendorOrderId = orderComment.VendorOrderID2
var order *model.GoodsOrder
if orderComment.VendorID == model.VendorIDMTWM && orderComment.VendorOrderID2 != "" {
order, _ = partner.CurOrderManager.LoadOrder(orderComment.VendorOrderID2, orderComment.VendorID)
} else {
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 <= cms.JX_MIDDLE_COMMENTS_MAX_LEVEL && time.Now().Sub(orderComment.CommentCreatedAt) < cms.MAX_REAPLY_TIME && order != nil {
comment2.LastPushTime = utils.Time2Str(time.Now())
comment2.PushNo = 1
weixinmsg.PushJDBadCommentToWeiXin(comment2, orderComment.Score <= cms.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 = cms.COMMENT_RESOLVED
comment2.VendorOrderId = orderComment.VendorOrderID2
if comment2.Jxstoreid != "" && orderComment.Score <= cms.JX_MIDDLE_COMMENTS_MAX_LEVEL && time.Now().Sub(orderComment.CommentCreatedAt) < cms.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
var order *model.GoodsOrder
if orderComment.VendorID == model.VendorIDMTWM && orderComment.VendorOrderID2 != "" {
order, _ = partner.CurOrderManager.LoadOrder(orderComment.VendorOrderID2, orderComment.VendorID)
} else {
order, _ = partner.CurOrderManager.LoadOrder(orderComment.VendorOrderID, orderComment.VendorID)
}
weixinmsg.PushJDBadCommentToWeiXin(&comment3, orderComment.Score <= cms.JX_BAD_COMMENTS_MAX_LEVEL, order)
}
//}
}
if err == nil {
if comment2.OrderFlag == "1" {
}
if isNewComment {
err = dao.CreateEntity(db, comment2)
} else if comment2 != nil {
_, err = dao.UpdateEntity(db, comment2)
}
}
} else {
if orderComment.VendorOrderID2 != "" {
comment2.VendorOrderId = orderComment.VendorOrderID2
_, err = dao.UpdateEntity(db, comment2)
}
}
} else {
comment2.VendorOrderId = orderComment.VendorOrderID2
_, err = dao.UpdateEntity(db, comment2, "VendorOrderId")
}
if err != nil {
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
}
var config *tReplyConfig
if configs, err := dao.QueryConfigs(dao.GetDB(), utils.Int2Str(score), model.ConfigTypeReply, ""); err == nil {
json.Unmarshal([]byte(configs[0].Value), &config)
}
if config == nil {
return
}
//config := replyConfig[score]
delaySeconds := config.DelayGapBegin + rand.Intn(config.DelayGapEnd-config.DelayGapBegin)
content := config.Comments[rand.Intn(len(config.Comments))]
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,29 +0,0 @@
package orderman
import (
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"testing"
"time"
)
func TestSaveJdsOrders(t *testing.T) {
type args struct {
ctx *jxcontext.Context
orderCreatedStart time.Time
orderCreatedEnd time.Time
}
tests := []struct {
name string
args args
wantErr bool
}{
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if err := SaveJdsOrders(tt.args.ctx, tt.args.orderCreatedStart, tt.args.orderCreatedEnd); (err != nil) != tt.wantErr {
t.Errorf("SaveJdsOrders() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}

View File

@@ -1,177 +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 {
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 {
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)
if err != nil {
return
}
ordersCount := len(orders)
if ordersCount > 0 {
bills := FixedOrderManager.LoadPendingWaybills()
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,289 +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 {
return nil
}
return bills
}
func (w *OrderManager) OnWaybillNew(bill2 *model.Waybill, db *dao.DaoDB) (isDuplicated bool, err error) {
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 { // 购物平台(比如京东)重新建的运单,单号始终是与订单相同的
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 {
isDuplicated = true
err = utils.CallFuncLogError(func() error {
_, err = db.Db.Update(bill, "DuplicatedCount")
return err
}, "onWaybillNew Update2")
}
} else {
*bill2 = *bill
}
} 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 {等于10的时候没有运费
if bill.DesiredFee > 0 {
addParams["desired_fee"] = bill.DesiredFee
}
if bill.ActualFee > 0 {
addParams["actual_fee"] = bill.ActualFee
}
//}
//单独增加顺丰派送取消运单修改配送费逻辑
if (bill.WaybillVendorID == model.VendorIDSFPS || bill.WaybillVendorID == model.VendorIDMTWM) && bill.Status == model.WaybillStatusCanceled {
addParams["desired_fee"] = bill.DesiredFee
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 + ",订单运费:" + fmt.Sprintf("%d", bill.DesiredFee),
}
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
}
}
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, waybillVendorID string, complaintID int, waybillID string) (err error) {
wayBillList, err := dao.GetComplaintList(dao.GetDB(), vendorOrderID, waybillID)
if err != nil {
return err
}
if len(wayBillList) != model.YES {
return fmt.Errorf("订单所属运单不存在,或运单为分配骑手,无法投诉")
}
if err == nil && len(wayBillList) > 0 {
switch wayBillList[0].WaybillVendorID {
case model.VendorIDFengNiao, model.VendorIDDada, model.VendorIDMTPS, model.VendorIDUUPT, model.VendorIDSFPS:
tripartiteDelivery := partner.GetDeliveryPlatformFromVendorID(wayBillList[0].WaybillVendorID)
if tripartiteDelivery != nil {
err = tripartiteDelivery.Handler.ComplaintRider(wayBillList[0], complaintID, complaintReasonsMap[complaintID])
} else {
err = fmt.Errorf("投诉三方配送获取运单失败")
}
case model.VendorIDMTWM, model.VendorIDDD, model.VendorIDJD, model.VendorIDEBAI, model.VendorIDTaoVegetable:
platformDelivery := partner.GetPurchaseOrderHandlerFromVendorID(wayBillList[0].WaybillVendorID)
if platformDelivery != nil {
err = platformDelivery.ComplaintRider(wayBillList[0].VendorOrderID, complaintID, complaintReasonsMap[complaintID])
} else {
err = fmt.Errorf("投诉平台配送获取运单失败")
}
}
}
return err
}
// GetComplaintList 获取投诉列表
func GetComplaintList(orderId string) ([]*model.Waybill, error) {
return dao.GetComplaintList(dao.GetDB(), orderId, "")
}

View File

@@ -1,281 +0,0 @@
package basesch
import (
"fmt"
"strings"
tiktokShop "git.rosy.net.cn/baseapi/platformapi/tiktok_shop/tiktok_api"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxcallback/scheduler"
"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/business/partner"
"git.rosy.net.cn/jx-callback/globals"
)
var (
ctx *jxcontext.Context
)
var (
FixedBaseScheduler *BaseScheduler
)
type BaseScheduler struct {
IsReallyCallPlatformAPI bool
}
func (c *BaseScheduler) AcceptOrRefuseOrder(order *model.GoodsOrder, isAcceptIt bool, userName string) (err error) {
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
}
return err
}
func (c *BaseScheduler) PickupGoods(order *model.GoodsOrder, isSelfDelivery bool, userName string) (err error) {
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
} else {
err = scheduler.ErrOrderStatusAlreadySatisfyCurOperation
}
}
return err
}
func (c *BaseScheduler) Swtich2SelfDeliver(order *model.GoodsOrder, userName string) (err error) {
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
} else {
err = scheduler.ErrOrderStatusAlreadySatisfyCurOperation
}
}
return err
}
func (c *BaseScheduler) Swtich2SelfDelivered(order *model.GoodsOrder, userName string) (err error) {
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
} else {
err = scheduler.ErrOrderStatusAlreadySatisfyCurOperation
}
}
return err
}
func (c *BaseScheduler) SelfDeliverDelivering(order *model.GoodsOrder, userName string) (err error) {
if order.Status == model.OrderStatusFinishedPickup {
if c.IsReallyCallPlatformAPI {
err = utils.CallFuncLogError(func() error {
// 下面这个写法暂存,可能会有问题
if order.VendorID == model.VendorIDMTWM {
// 转自送同时取消平台订单(美团才做这个操作)
if _, err := partner.GetPurchasePlatformFromVendorID(order.VendorID).GetCancelDeliveryReason(order); err != nil {
partner.CurOrderManager.OnOrderMsg(order, "订单转自送取消美团平台发单获取理由失败", err.Error())
}
// 取消美团外卖配送,转自送
if err = partner.GetPurchasePlatformFromVendorID(order.VendorID).CancelLogisticsByWmOrderId(order, "101512", "已选择其他配送方式", order.VendorStoreID, order.VendorOrderID); err != nil {
partner.CurOrderManager.OnOrderMsg(order, "取消美团外卖,转用三方配送", err.Error())
}
// 查询订单状态,
orderStatus, _ := partner.GetPurchasePlatformFromVendorID(order.VendorID).OrderLogisticsStatus(order.VendorOrderID)
status := 0
if orderStatus != nil {
status = orderStatus.LogisticsStatus
}
if status == 100 { // 美团取消配送单
partner.CurOrderManager.OnOrderMsg(order, "美团外卖转自送成功.", "")
return nil
} else if strings.Contains(err.Error(), "包裹不存在") || strings.Contains(err.Error(), "运单不存在") || strings.Contains(err.Error(), "1071") || strings.Contains(err.Error(), "1014") || strings.Contains(err.Error(), "invalid character 'o' looking for beginning of value") {
partner.CurOrderManager.OnOrderMsg(order, "美团外卖转自送可能成功,异常:", err.Error())
err = nil
return nil
} else if strings.Contains(err.Error(), "商家没有接入众包配送,无法进行众包配送相关操作") {
partner.CurOrderManager.OnOrderMsg(order, "商家无配送设置,转配送成功", err.Error())
err = nil
} else if strings.Contains(err.Error(), "无需重复取消") {
partner.CurOrderManager.OnOrderMsg(order, "商家无配送设置,转配送成功", err.Error())
err = nil
} else {
bill, _ := partner.CurOrderManager.LoadWaybill(order.VendorWaybillID, order.WaybillVendorID)
err = c.CancelWaybill(bill, partner.CancelWaybillReasonOther, userName+":5"+partner.CancelWaybillReasonStrActive)
partner.CurOrderManager.OnOrderMsg(order, "美团外卖运单无法取消,", err.Error())
return err
}
} else if order.VendorID == model.VendorIDDD { //抖音配送
localBill, _ := partner.CurOrderManager.LoadWaybill(order.VendorWaybillID, order.WaybillVendorID)
// 获取抖音配送状态
tiktokWayBillStatus, err2 := partner.GetPurchasePlatformFromVendorID(order.VendorID).OrderLogisticsStatus(order.VendorOrderID)
if tiktokWayBillStatus != nil && tiktokWayBillStatus.LogisticsStatus >= tiktokShop.ShipmentStatusReceived && tiktokWayBillStatus.LogisticsStatus != tiktokShop.ShipmentStatusCanceled {
//取消抖音配送转自送
err = c.CancelWaybill(localBill, partner.CancelWaybillReasonDYPSCancel, partner.CancelWaybillReasonStrDYPSCancel+"抖音骑手已经接单,无法取消6")
partner.CurOrderManager.OnOrderMsg(order, "取消抖音配送,转用门店自配送/三方配送", "抖音骑手已经接单,无法取消")
return err
} else if tiktokWayBillStatus != nil && tiktokWayBillStatus.LogisticsStatus == -1 { // 先转自送,自送不成功取消平台配送.
if err := partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID).SelfDeliverDelivering(order, userName); err != nil {
partner.CurOrderManager.OnOrderMsg(order, "抖音转自送,平台无运力", "tiktokWayBillStatus = -1")
}
} else if (err2 != nil && strings.Contains(err2.Error(), "当前状态获取不到运力信息")) || (tiktokWayBillStatus != nil && tiktokWayBillStatus.LogisticsStatus == tiktokShop.ShipmentStatusCanceled) {
partner.GetPurchasePlatformFromVendorID(order.VendorID).SelfDeliverDelivering(order, "")
} else if err = partner.GetPurchasePlatformFromVendorID(order.VendorID).CancelLogisticsByWmOrderId(order, "", "", order.VendorStoreID, order.VendorOrderID); err != nil {
partner.CurOrderManager.OnOrderMsg(order, "取消抖音配送异常:", err.Error())
if err = c.CancelWaybill(localBill, partner.CancelWaybillReasonDYPSCancel, partner.CancelWaybillReasonStrDYPSCancel+"7"); err != nil {
partner.CurOrderManager.OnOrderMsg(order, "取消抖音平台运单错误,无法转自送", err.Error())
return err
}
} else {
partner.GetPurchasePlatformFromVendorID(order.VendorID).SelfDeliverDelivering(order, "")
}
} else {
if err := partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID).SelfDeliverDelivering(order, userName); err != nil && (err != scheduler.ErrOrderStatusAlreadySatisfyCurOperation) {
partner.CurOrderManager.OnOrderMsg(order, "SelfDeliverDelivering 调用[SelfDeliverDelivering]转自送", err.Error())
return err
}
}
return err
}, "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
} else {
err = scheduler.ErrOrderStatusAlreadySatisfyCurOperation
}
}
return err
}
func (c *BaseScheduler) SelfDeliverDelivered(order *model.GoodsOrder, userName string) (err error) {
if order.Status >= model.OrderStatusFinishedPickup && order.Status <= model.OrderStatusDelivering {
if c.IsReallyCallPlatformAPI {
err = utils.CallFuncLogError(func() error {
if err = partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID).SelfDeliverDelivered(order, userName); err == nil {
bill, _ := partner.CurOrderManager.LoadWaybill(order.VendorWaybillID, order.WaybillVendorID)
if bill != nil && bill.WaybillVendorID != model.VendorJXFakeWL && bill.WaybillVendorID != model.VendorIDUnknown {
c.CancelWaybill(bill, partner.CancelWaybillReasonOther, userName+":"+partner.CancelWaybillReasonStrActive+"8")
}
}
return err
}, "SelfDeliverDelivered orderID:%s", order.VendorOrderID)
}
} else {
if order.LockStatus != model.OrderStatusUnknown || order.Status < model.OrderStatusDelivering {
err = scheduler.ErrOrderStatusIsNotSuitable4CurOperation
} else {
err = scheduler.ErrOrderStatusAlreadySatisfyCurOperation
}
}
return err
}
func (c *BaseScheduler) CreateWaybill(platformVendorID int, order *model.GoodsOrder, maxDeliveryFee int64) (bill *model.Waybill, err error) {
if !model.IsOrderSolid(order) { // 如果订单是不完整的
return nil, scheduler.ErrOrderIsNotSolid
}
storeDetail, _ := dao.GetStoreDetail(dao.GetDB(), jxutils.GetSaleStoreIDFromOrder(order), order.VendorID, order.VendorOrgCode)
var balance int
// 门店发单,如果是京西门店,直接使用京西余额,非京西门店使用门店余额,余额不足使用品牌余额!
if order.CreateDeliveryType == model.YES {
storeAcct, err := cms.GetStoreAcctBalance(ctx, jxutils.GetSaleStoreIDFromOrder(order)) // 获取门店余额
if err != nil {
return nil, err
}
balance = storeAcct.AccountBalance
} else {
balance, _ = partner.CurStoreAcctManager.GetBrandBalance(storeDetail.BrandID)
}
handlerInfo := partner.GetDeliveryPlatformFromVendorID(platformVendorID)
if handlerInfo != nil && handlerInfo.Use4CreateWaybill {
if _, ok := model.DeliveryBrandMarkMap[platformVendorID]; ok && storeDetail.BrandIsOpen != 0 && balance >= model.BrandBalanceLimit {
if c.IsReallyCallPlatformAPI {
// 如果门店是美团服务商且订单为美团订单
if storeDetail.IsService == model.YES && order.VendorID == model.VendorIDMTWM {
err = fmt.Errorf("京西ID:[%d],平台id[%s],平台[美团]:错误:[%s]", storeDetail.Store.ID, storeDetail.VendorStoreID, "此门店美团平台为服务商模式,不支持本系统提供的三方配送![仅美团,其余平台订单正常使用.]")
} else {
if order.VendorID == model.VendorIDEBAI && strings.Contains(order.ConsigneeAddress, EBaiOrderAddressHide) {
return nil, fmt.Errorf("由于饿了么用户数据隐私保护,发三方配送前请先将订单转为自配送,获取详情地址")
}
// 生成三方运单
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 = fmt.Errorf("创建运单是门店余额不足十元,无法创建运单")
}
} else {
err = scheduler.ErrDeliverProviderWrong
}
return bill, err
}
func (c *BaseScheduler) CancelWaybill(bill *model.Waybill, cancelReasonID int, cancelReason string) (err error) {
// 部分快递平台在取消成功后有时会不发运单取消消息过来比如达达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 {
if err := handlerInfo.Handler.CancelWaybill(bill, cancelReasonID, cancelReason+"9"); err != nil {
return err
}
return nil
}, "CancelWaybill bill:%v", bill); err == nil {
bill.Status = model.WaybillStatusCanceled
bill.DeliveryFlag |= model.WaybillDeliveryFlagMaskActiveCancel
_, err = dao.UpdateEntity(nil, bill, "Status", "DeliveryFlag")
}
}
}
return err
}

View File

@@ -1,577 +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"
)
const (
EBaiOrderAddressHide = "[隐私保护]顾客地址已隐藏"
)
func (c *BaseScheduler) CreateWaybillOnProviders(ctx *jxcontext.Context, order *model.GoodsOrder, courierVendorIDs, excludeCourierVendorIDs []int, maxDeliveryFee int64, createOnlyOne bool) (bills []*model.Waybill, err error) {
storeCourierList, err := dao.GetStoreCourierList2(dao.GetDB(), []int{jxutils.GetSaleStoreIDFromOrder(order)}, courierVendorIDs, model.StoreStatusOpened, []int{model.StoreAuditStatusOnline, model.StoreAuditStatusUpdated})
if err != nil {
return nil, err
}
courierVendorIDMap := jxutils.IntList2Map(courierVendorIDs)
excludeCourierVendorIDMap := jxutils.IntList2Map(excludeCourierVendorIDs)
errList := errlist.New()
store, _ := dao.GetStoreDetail(dao.GetDB(), order.JxStoreID, order.VendorID, order.VendorOrgCode)
for _, storeCourier := range storeCourierList {
switch storeCourier.Status {
case model.YES:
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 {
// 其实这个bill没啥用,运单的创建是通过回调产生的
bill.DesiredFee += int64(model.WayBillDeliveryMarkUp + store.FreightMarkup)
if bill.WaybillVendorID == model.VendorIDFengNiao {
bill.DesiredFee += model.WayBillDeliveryMarkUp
}
bill.DesiredFee += int64(store.FreightMarkup)
bills = append(bills, bill)
if createOnlyOne {
break
}
} else {
errList.AddErr(fmt.Errorf("平台:%s,%s", jxutils.GetVendorName(courierVendorID), err.Error()))
}
}
}
case model.NO:
errList.AddErr(fmt.Errorf("平台:%s,发单配送被关闭,打开后发单", jxutils.GetVendorName(storeCourier.VendorID)))
}
}
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过订单发三方配送亏损超6元/当前订单配送方式不是门店自送/没有绑定有效的三方配送门店", order.VendorOrderID)
} else {
err = fmt.Errorf("orderID:%s所有运单失败%s", order.VendorOrderID, errList.GetErrListAsOne().Error())
}
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) {
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 {
return err
}
order.OrderFinishedAt = time.Now()
dao.UpdateEntity(dao.GetDB(), order, "Status", "OrderFinishedAt")
}
}
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) {
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 {
partner.CurOrderManager.OnOrderMsg(order, fmt.Sprintf("订单手动拣货成功[%s]", ctx.GetUserName()), "")
order.Status = model.OrderStatusFinishedPickup
if err = partner.CurOrderManager.UpdateOrderStatusAndDeliveryFlag(order); err != nil {
return err
}
}
// 京西商城的自提订单,在拣货完成时自动设置为完成订单
if model.IsOrderDeliveryBySelf(order) && order.VendorID == model.VendorIDJX {
order.Status = model.OrderStatusFinished
order.VendorStatus = utils.Int64ToStr(model.OrderStatusFinished)
order.Flag = 128
order.OrderFinishedAt = time.Now()
dao.UpdateEntity(dao.GetDB(), order, "Status", "VendorStatus", "Flag", "OrderFinishedAt")
}
}
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 {
return err
}
order, _ := partner.CurOrderManager.LoadOrder(bill.VendorOrderID, bill.OrderVendorID)
if bill.OrderVendorID != bill.WaybillVendorID { // 取消三方配送
if err = c.CancelWaybill(bill, cancelReasonID, cancelReason); err != nil {
return err
}
} else { // 取消平台配送转自送
if err = c.Swtich2SelfDeliver(order, ctx.GetUserName()); err != nil {
return err
}
}
partner.CurOrderManager.OnOrderMsg(order, utils.Int64ToStr(model.WaybillStatusCancel), "商户发起运单取消10")
return err
}
func (c *BaseScheduler) AgreeOrRefuseRefund(ctx *jxcontext.Context, afsOrderID string, vendorID, approveType int, reason string) (err error) {
skus := make([]*model.OrderFinancialSkuExt, 0, 0)
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, nil)
//美团的订单如果是同意全部退款,要取消所有三方运单并停止调度
if order.VendorID == model.VendorIDMTWM || order.VendorID == model.VendorIDJX || order.VendorID == model.VendorIDEBAI {
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 && order.VendorID == model.VendorIDMTWM {
order.DeliveryFlag |= model.OrderDeliveryFlagMaskScheduleDisabled
partner.CurOrderManager.UpdateOrderFields(order, []string{"DeliveryFlag"})
for _, v := range waybills {
c.CancelWaybill(v, partner.CancelWaybillReasonOther, ctx.GetUserName()+":11"+partner.CancelWaybillReasonStrActive)
}
}
if afsCount == orderCount && order.VendorID == model.VendorIDJX {
order.DeliveryFlag |= model.OrderDeliveryFlagMaskScheduleDisabled
order.Status = model.OrderStatusCanceled
order.VendorStatus = utils.Int2Str(model.OrderStatusCanceled)
partner.CurOrderManager.UpdateOrderFields(order, []string{"DeliveryFlag", "Status", "VendorStatus"})
}
if afsCount == orderCount && order.VendorID == model.VendorIDEBAI {
order.DeliveryFlag |= model.OrderDeliveryFlagMaskScheduleDisabled
order.Status = model.OrderStatusCanceled
order.VendorStatus = "10" // 饿百取消订单
partner.CurOrderManager.UpdateOrderFields(order, []string{"DeliveryFlag", "Status", "VendorStatus"})
for _, v := range waybills {
c.CancelWaybill(v, partner.CancelWaybillReasonOther, ctx.GetUserName()+":12"+partner.CancelWaybillReasonStrActive)
}
}
}
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)
}
}
//if approveType != partner.AfsApproveTypeRefused && err == nil {
// storeDetail, err := partner.CurOrderManager.LoadStoreDetail(afsOrder.StoreID, afsOrder.VendorID)
// if err != nil {
// return err
// }
// if storeDetail.IsPrintRefundOrder == model.YES { // 打印退款订单
// order2, _ := partner.CurOrderManager.LoadOrder(afsOrder.VendorOrderID, afsOrder.VendorID)
// order2.Status = model.AfsOrderStatusFinished
// _, err = netprinter.PrintRefundOrCancelOrder(jxcontext.AdminCtx, model.NO, order2, afsOrder.StoreID)
// }
//}
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, isPay int) (errCode string, err error) {
order, err := partner.CurOrderManager.LoadOrder(vendorOrderID, vendorID)
if err != nil {
return "", err
}
errCode, err = c.CheckStoreBalanceWithTip(ctx, order, tipFee, isPay)
if err != nil {
return errCode, err
}
err = c.SetOrderWaybillTipByOrder(ctx, order, tipFee)
return errCode, err
}
func (c *BaseScheduler) CheckStoreBalanceWithTip(ctx *jxcontext.Context, order *model.GoodsOrder, tipFee int64, isPay int) (errCode string, err error) {
var (
db = dao.GetDB()
)
roundTipFee := tipFee / 100 * 100
if roundTipFee != tipFee {
return model.ErrCodeOnePayTipFeeMore, fmt.Errorf("小费必须是1元的整数倍")
}
//if order.WaybillTipMoney >= tipFee {
// return model.ErrCodeOnePayTipFeeMore, fmt.Errorf("本次小费金额不能小于已经支付的小费")
//}
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("门店账户余额不足,不能加小费!")
}
if tipFee > 1000 {
return model.ErrCodeAccountBalanceNotEnough, fmt.Errorf("小费单次加价金额大于十元")
}
} else {
// 品牌发单
storeDetail, err := dao.GetStoreDetail(db, order.JxStoreID, order.VendorID, order.VendorOrgCode)
if err != nil || storeDetail == nil {
return model.ErrCodeAccountBalanceNotEnough, fmt.Errorf("根据订单获取门店详情错误:%v", err)
}
brandAcct, err := dao.GetBrandBalance(db, storeDetail.BrandID)
if err != nil {
return "", err
}
if tipFee > int64(brandAcct) {
return model.ErrCodeAccountBalanceNotEnough, fmt.Errorf("品牌账户余额不足,不能加小费!")
}
if tipFee > 1000 {
return model.ErrCodeOnePayTipFeeMore, fmt.Errorf("小费单次加价金额大于十元")
}
}
// 是否确认支付
if isPay != model.YES {
return model.ErrCodeIsPaySure, fmt.Errorf("此订单已经支付小费[%d]元,本次增加小费[%d]元,总支出小费[%d]元", order.WaybillTipMoney/100, tipFee/100, (order.WaybillTipMoney+tipFee)/100)
}
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) {
db := dao.GetDB()
thisTimeTipFee := tipFee - order.WaybillTipMoney
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), thisTimeTipFee); err != nil {
globals.SugarLogger.Debugf("订单id[%s],平台id[%d],427,err :[%v]", order.VendorOrderID, order.VendorID, err)
} else {
//加小费成功扣钱
if order.CreateDeliveryType == model.YES {
if err = partner.CurStoreAcctManager.InsertStoreAcctExpendAndUpdateStoreAcctBalance(ctx, jxutils.GetSaleStoreIDFromOrder(order), int(thisTimeTipFee), partner.StoreAcctTypeExpendCreateWaybillTip, order.VendorOrderID, "", 0); err == nil {
flag = true
}
} else if order.CreateDeliveryType == model.NO {
if err = partner.CurStoreAcctManager.InsertBrandBill(ctx, storeDetail.BrandID, int(thisTimeTipFee), model.BrandBillTypeExpend, model.BrandBillFeeTypeTipFee, order.VendorOrderID, ""); 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 waybill.WaybillVendorID == model.VendorIDDada {
err = handler.UpdateWaybillTip(ctx, waybill.VendorOrgCode, storeDetail.VendorStoreID, waybill.VendorOrderID, waybill.VendorWaybillID, waybill.VendorWaybillID2, utils.Int2Str(storeDetail.CityCode), tipFee)
globals.SugarLogger.Debugf("订单id[%s],平台id[%d],462,err :[%v]", order.VendorOrderID, order.VendorID, err)
} else {
err = handler.UpdateWaybillTip(ctx, waybill.VendorOrgCode, storeDetail.VendorStoreID, waybill.VendorOrderID, waybill.VendorWaybillID, waybill.VendorWaybillID2, utils.Int2Str(storeDetail.CityCode), thisTimeTipFee)
globals.SugarLogger.Debugf("订单id[%s],平台id[%d],465,err :[%v]", order.VendorOrderID, order.VendorID, err)
}
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), int(thisTimeTipFee), partner.StoreAcctTypeExpendCreateWaybillTip, order.VendorOrderID, "", 0)
} else if order.CreateDeliveryType == model.NO {
partner.CurStoreAcctManager.InsertBrandBill(ctx, storeDetail.BrandID, int(thisTimeTipFee), model.BrandBillTypeExpend, model.BrandBillFeeTypeTipFee, order.VendorOrderID, "")
}
}
}
}
}
return err
}
func (c *BaseScheduler) confirmSelfTake(ctx *jxcontext.Context, order *model.GoodsOrder, selfTakeCode string) (err error) {
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 {
if selfTakeCode != order.ConsigneeMobile && selfTakeCode != order.VendorOrderID[len(order.VendorOrderID)-4:] {
return fmt.Errorf("京西平台自提单,自提码为订单后四位或完整的下单电话")
}
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,90 +0,0 @@
package defsch
import (
"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"
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/model/dao"
"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)
}
}
}
if order != nil && order.VendorID == model.VendorIDTaoVegetable {
result, _ := dao.GetAfsOrders(dao.GetDB(), model.VendorIDTaoVegetable, order.VendorOrderID, "")
if len(result) <= model.YES {
msghub.OnNewWait4ApproveAfsOrder(order)
weixinmsg.NotifyAfsOrderStatus(order)
push.NotifyAfsOrder(order)
}
} else {
msghub.OnNewWait4ApproveAfsOrder(order)
weixinmsg.NotifyAfsOrderStatus(order)
push.NotifyAfsOrder(order)
}
}
}
storeDetail, err := partner.CurOrderManager.LoadStoreDetail(order.JxStoreID, order.VendorID)
if err == nil {
if storeDetail.IsPrintRefundOrder == model.YES { // 打印退款订单
order2, _ := partner.CurOrderManager.LoadOrder(order.VendorOrderID, order.VendorID)
_, err = netprinter.PrintRefundOrCancelOrder(jxcontext.AdminCtx, model.NO, order2, order2.JxStoreID)
}
}
//if order.Status == model.AfsOrderStatusWait4Approve || order.Status == model.AfsOrderStatusFinished || order.Status == model.AfsOrderStatusNew {
// // 京西云打印机打印数据-如果门店使用京西打印机才使用如下代码块
// store, err := dao.GetStoreDetail(dao.GetDB(), order.JxStoreID, order.VendorID, order.VendorOrgCode)
// if err == nil && store.PrinterVendorID == model.VendorIDJxprint && store.IsPrintCancelOrder == model.YES {
// orderObj, _ := partner.CurOrderManager.LoadOrder(order.VendorOrderID, order.VendorID)
// if orderObj != nil {
// netprinter.PrintOrderByOrder(jxcontext.AdminCtx, orderObj, model.PrintAfsOrder, 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,591 +0,0 @@
package defsch
import (
"fmt"
"git.rosy.net.cn/baseapi/platformapi/mtwmapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxstore/cms"
"git.rosy.net.cn/jx-callback/globals/api"
beego "github.com/astaxie/beego/server/web"
"math"
"math/rand"
"strings"
"time"
"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, courierName, courierMobile string) (err error) {
var order *model.GoodsOrder
jxutils.CallMsgHandler(func() {
err = func() (err error) {
savedOrderInfo := s.loadSavedOrderByID(vendorOrderID, vendorID, true)
if savedOrderInfo != nil {
order = savedOrderInfo.order
if err = s.isPossibleSwitch2SelfDelivery(order); err == nil { // 是否能转自送
err = s.cancelOtherWaybillsCheckOrderDeliveryFlag(savedOrderInfo, nil, partner.CancelWaybillReasonOther, ctx.GetUserName()+"17"+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) // 取消平台自配送
s.CancelAll3rdWaybills(ctx, vendorOrderID, vendorID, true) // 取消三方平台配送以及调度
}
} 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)
//return err
}
}
} else {
order = &model.GoodsOrder{
VendorOrderID: vendorOrderID,
VendorID: vendorID,
}
err = scheduler.ErrCanNotFindOrder
}
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
} else {
partner.CurOrderManager.OnOrderMsg(order, vendorStatus, remark)
}
// 上面是真的转自送,支持美团,饿百,京东,如果时抖店,抖店暂时全部是自送的!但是有骑手信息时,就是一个白嫖单子!
if courierName != "" && courierMobile != "" && err == nil {
timeNow := time.Now()
rand.Seed(timeNow.UnixNano())
randNumber := rand.Int63n(640)
if randNumber < 60 {
randNumber += 60
}
randTime := time.Duration(randNumber) * time.Second
bill := &model.Waybill{
VendorWaybillID: order.VendorOrderID,
VendorWaybillID2: "",
WaybillVendorID: model.VendorJXFakeWL,
VendorOrderID: order.VendorOrderID,
OrderVendorID: order.VendorID,
CourierName: courierName,
CourierMobile: courierMobile,
Status: model.OrderStatusNew,
VendorStatus: utils.Int2Str(model.OrderStatusNew),
ActualFee: 0,
DesiredFee: 0,
TipFee: 0,
DuplicatedCount: 0,
DeliveryFlag: 0,
WaybillCreatedAt: timeNow,
WaybillFinishedAt: utils.DefaultTimeValue,
StatusTime: timeNow.Add(randTime), // 下一状态时间
OriginalData: "",
Remark: "自定义物流单(全平台刷单)",
VendorOrgCode: order.VendorOrgCode,
}
err = dao.CreateEntity(dao.GetDB(), bill)
//if order.VendorID == model.VendorIDTaoVegetable {
// order.VendorWaybillID = order.VendorOrderID
// order.WaybillVendorID = model.VendorJXFakeWL
// dao.UpdateEntity(dao.GetDB(), order, "VendorWaybillID", "WaybillVendorID")
//}
}
return err
}()
}, jxutils.ComposeUniversalOrderID(vendorOrderID, vendorID))
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) {
//TODO 刷单用,之后不刷单了删除
//if order.VendorID == model.VendorIDDD {
// return nil
//}
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)
}
// 检查订单是否在配送状态
waybills, err := dao.GetWaybills(dao.GetDB(), order.VendorOrderID, nil)
for _, v := range waybills {
if v.Status >= model.OrderStatusDelivering && v.Status != model.OrderStatusCanceled && v.Status != model.OrderStatusFinished {
err = fmt.Errorf("订单已经在配送中,无法创建运单,有疑问请联系管理员")
break
}
}
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)
}
// 获取门店品牌余额
storeAcct, err := cms.GetStoreAcctBalance(ctx, jxutils.GetSaleStoreIDFromOrder(order)) // 获取门店余额
// 门店详细信息
storeList, err := dao.GetStoreDetail(dao.GetDB(), jxutils.GetSaleStoreIDFromOrder(order), savedOrderInfo.order.VendorID, order.VendorOrgCode)
if err != nil {
return nil, err
}
deliveryFeeMap, _ := s.QueryOrderWaybillFeeInfoEx(ctx, order.VendorOrderID, order.VendorID)
// 不管是门店发单还是品牌发单都要扣钱,门店发单扣门店,品牌发单扣品牌
if order.CreateDeliveryType == model.YES {
// 获取平台配送费
isEqual, isZero, _ := partner.CurStoreAcctManager.CheckStoreAcctExpendExist(order.VendorOrderID) // 当前订单的支出记录
expend, lastFee, _ := partner.CurStoreAcctManager.GetStoreAcctExpendLastCreateWayBillFee(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 {
maxFee = v.DeliveryFee
}
}
newPrice = maxFee
}
// 门店支出运费,门店发单
if order.CreateDeliveryType == model.YES {
if storeAcct.AccountBalance > int(newPrice) {
if int(newPrice) > lastFee {
// 门店支出费用
partner.CurStoreAcctManager.InsertStoreAcctExpendAndUpdateStoreAcctBalance(ctx, jxutils.GetSaleStoreIDFromOrder(order), int(newPrice)-lastFee, partner.StoreAcctTypeExpendCreateWaybill2ndMore, order.VendorOrderID, "", expend.ID) //int(newPrice)-lastFee
}
}
}
} else { // 新订单的发单记录,门店发单扣门店,品牌发单扣品牌
if len(courierVendorIDs) == 1 {
courierVendorID := courierVendorIDs[0]
if _, ok := deliveryFeeMap[courierVendorID]; ok {
if order.CreateDeliveryType == model.YES {
err = partner.CurStoreAcctManager.InsertStoreAcctExpendAndUpdateStoreAcctBalance(ctx, jxutils.GetSaleStoreIDFromOrder(order), int(deliveryFeeMap[courierVendorID].DeliveryFee), partner.StoreAcctTypeExpendCreateWaybillEx, order.VendorOrderID, "", 0) //int(newPrice)-lastFee
}
}
} else if len(courierVendorIDs) == 0 {
var maxFee int64
for _, v := range deliveryFeeMap {
if v.DeliveryFee > maxFee {
maxFee = v.DeliveryFee
}
}
err = partner.CurStoreAcctManager.InsertStoreAcctExpendAndUpdateStoreAcctBalance(ctx, jxutils.GetSaleStoreIDFromOrder(order), int(maxFee), partner.StoreAcctTypeExpendCreateWaybillEx, order.VendorOrderID, "", 0) //int(maxFee)
}
}
} else {
// 看看此订单有无发单记录,小费记录
// 品牌发单
if len(courierVendorIDs) == 1 {
courierVendorID := courierVendorIDs[0]
if _, ok := deliveryFeeMap[courierVendorID]; ok {
err = partner.CurStoreAcctManager.InsertBrandBill(jxcontext.AdminCtx, storeList.BrandID, int(deliveryFeeMap[courierVendorID].DeliveryFee), model.BrandBillTypeExpend, model.BrandBillFeeTypeDelivery, order.VendorOrderID, order.VendorWaybillID)
}
} else if len(courierVendorIDs) == 0 {
var maxFee int64
for _, v := range deliveryFeeMap {
if v.DeliveryFee > maxFee {
maxFee = v.DeliveryFee
}
}
err = partner.CurStoreAcctManager.InsertBrandBill(jxcontext.AdminCtx, storeList.BrandID, int(maxFee), model.BrandBillTypeExpend, model.BrandBillFeeTypeDelivery, order.VendorOrderID, order.VendorWaybillID)
}
}
}
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
}
}
excludeCourierVendorIDs := make([]int, 0, 0)
allDelivery := map[int]int{model.VendorIDFengNiao: 1, model.VendorIDDada: 1, model.VendorIDMTPS: 1, model.VendorIDUUPT: 1, model.VendorIDSFPS: 1}
for _, v := range courierVendorIDs {
if allDelivery[v] == model.YES {
delete(allDelivery, v)
}
}
for k, _ := range allDelivery {
excludeCourierVendorIDs = append(excludeCourierVendorIDs, k)
}
billFunc := func() {
bills, err = func() (bills []*model.Waybill, err error) {
if vendorID == model.VendorIDELM {
return nil, fmt.Errorf("不要直接使用饿了么订单号,请使用相应的饿百订单号")
}
// 创建可调度对象,并且存储
savedOrderInfo := s.loadSavedOrderByID(vendorOrderID, vendorID, true)
if savedOrderInfo != nil {
savedOrderInfo.order.SendOrderType = 1 // 设置为手动创建订单
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, excludeCourierVendorIDs, 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
}
return bills, err
}()
}
jxutils.CallMsgHandler(billFunc, jxutils.ComposeUniversalOrderID(vendorOrderID, vendorID))
return bills, errCode, err
}
func (s *DefScheduler) CheckStoreBalance(ctx *jxcontext.Context, order *model.GoodsOrder, courierVendorIDs []int) (errCode string, err error) {
var (
db = dao.GetDB()
)
deliveryFeeMap, _ := s.QueryOrderWaybillFeeInfoEx(ctx, order.VendorOrderID, order.VendorID)
if err != nil {
return errCode, fmt.Errorf("获取订单配送费错误[%v]", err)
}
switch order.CreateDeliveryType {
case model.NO: // 品牌发单
storeDetail, err := dao.GetStoreDetail(db, jxutils.GetSaleStoreIDFromOrder(order), order.VendorID, "")
if err != nil {
return "", err
}
brandAcct, err := dao.GetBrandBalance(db, storeDetail.BrandID)
if err != nil {
return "", err
}
if len(courierVendorIDs) == 1 {
courierVendorID := courierVendorIDs[0]
if _, ok := deliveryFeeMap[courierVendorID]; ok {
if deliveryFeeMap[courierVendorID].DeliveryFee > int64(brandAcct) {
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(brandAcct) {
return model.ErrCodeAccountBalanceNotEnough, fmt.Errorf("品牌账户余额小于[%v]元,不能发配送!", jxutils.IntPrice2Standard(maxFee))
}
}
case model.YES: // 门店发单
//暂时这么认为len courierVendorIDs 为1表示是老板或者运营从小程序上点的立即发单因为小程序上是点哪个发哪个
//京西后台则是点一下发3个len courierVendorIDs 是0
//如果是小程序上点哪个扣哪个平台的钱
//如果是后台,则选最高的那个扣
storeAcct, err := cms.GetStoreAcctBalance(ctx, jxutils.GetSaleStoreIDFromOrder(order)) // 获取门店余额
if err != nil {
return "", err
}
//1、先判断是不是第一次发查询库里是否有这个订单的运费支出记录再查询是否有相同金额并且类型为回退的收入记录取消运单退回
//前者有,后者无, 表示已经发过了,暂未取消,若这这次的发单金额小于上次的金额则不进行判断也不多扣钱,若大于则扣除‘这次金额-上次金额’的钱,余额不足问题也根据这个判断
//前者有,后者有,表示发过并且取消过了,是多次发,直接扣
//前者无,表示就是第一次发,直接扣
//2、小程序里这次金额用发单平台的金额后台里这次金额用所有平台最高费用
isEqual, isZero, err := 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
}
_, lastFee, _ := partner.CurStoreAcctManager.GetStoreAcctExpendLastCreateWayBillFee(order.VendorOrderID)
// 如果门店属于京西菜市,京西果园则只能扣门店的金额
if int(newPrice) > lastFee {
if storeAcct.AccountBalance < int(newPrice)-lastFee /*&& result < int(newPrice)-lastFee*/ {
return model.ErrCodeAccountBalanceNotEnough, fmt.Errorf("门店账户余额小于[%v]元,不能发配送!", jxutils.IntPrice2Standard(newPrice-int64(lastFee)))
}
}
} else {
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))
}
}
}
default:
return "", fmt.Errorf("不存在的订单发单类型,检查配置")
}
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) {
// 取消三方运单,取消各平台单号信息,间隔一段时间后定时任务重新调度
savedOrderInfo := s.loadSavedOrderByID(vendorOrderID, vendorID, true)
if savedOrderInfo != nil {
if len(savedOrderInfo.waybills) == model.NO {
wayBills, err := dao.GetWayBillByOrderID(dao.GetDB(), 0, vendorID, 0, vendorOrderID)
if err == nil {
for _, wb := range wayBills {
if wb.Status < model.WaybillStatusDelivered {
err = s.CancelWaybill(wb, partner.CancelWaybillReasonOther, ctx.GetUserName()+":18"+partner.CancelWaybillReasonStrActive)
}
}
}
} else {
err = s.cancelOtherWaybills(savedOrderInfo, nil, partner.CancelWaybillReasonOther, ctx.GetUserName()+":18"+partner.CancelWaybillReasonStrActive)
}
} else {
err = scheduler.ErrCanNotFindOrder
}
// 停止调度,同事停止订单调度,不在通知第三方
if err == nil && isStopSchedule {
order := savedOrderInfo.order
order.DeliveryFlag |= model.OrderDeliveryFlagMaskScheduleDisabled
if err = partner.CurOrderManager.UpdateOrderStatusAndDeliveryFlag(order); err == nil {
s.stopTimer(savedOrderInfo)
}
}
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) {
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
}
// 隐私地址获取(美团)
if vendorID == model.VendorIDMTWM && (strings.Contains(order.ConsigneeAddress, "地址已隐藏") || strings.Contains(order.ConsigneeAddress, "(***)")) {
var apiObj *mtwmapi.API
switch order.VendorOrgCode {
case beego.AppConfig.DefaultString("mtwmAppID2", ""): // 5873
store, _ := dao.GetStoreDetail(dao.GetDB(), order.JxStoreID, order.VendorID, order.VendorOrgCode)
apiObj = api.Mtwm2API
apiObj.SetToken(store.MtwmToken)
default: // 589 4123
apiObj = api.MtwmAPI
}
address, err := apiObj.GetOrderAddress(utils.Str2Int64(order.VendorOrderID), 3)
if err != nil {
return nil, err
}
addressList := strings.Split(order.ConsigneeAddress, "@#")
order.ConsigneeAddress = address + "@#" + addressList[1]
dao.UpdateEntity(db, order, "ConsigneeAddress")
}
// 美团配送订单兑现
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()
}
store, _ := dao.GetStoreDetail(db, order.JxStoreID, order.VendorID, order.VendorOrgCode)
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 {
// 获取订单配送费用
feeInfo, err = handler.Handler.GetWaybillFee(order)
if err != nil {
feeInfo = &partner.WaybillFeeInfo{
ErrCode: partner.WaybillFeeErrCodeCourierOthers,
ErrStr: err.Error(),
}
} else {
feeInfo.DeliveryFee += model.WayBillDeliveryMarkUp // 加收两毛
if storeCourier.VendorID == model.VendorIDFengNiao {
feeInfo.DeliveryFee += model.WayBillDeliveryMarkUp // 蜂鸟加
}
feeInfo.DeliveryFee += int64(store.FreightMarkup)
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,280 +0,0 @@
package jcq
import (
"crypto/md5"
"encoding/hex"
"encoding/json"
"fmt"
"git.rosy.net.cn/baseapi"
"git.rosy.net.cn/baseapi/platformapi/jcqapi"
"git.rosy.net.cn/baseapi/platformapi/jdshopapi"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/business/partner/purchase/jdshop"
"sync"
)
const (
accessKey = "C0EB36912C652079DB111A922ACA406B" //京东第三方的AK
secretKey = "86B6330051ECC88391E2630D34C2CA13" //京东第三方的SK
consumerGroupID = "open_message_573819178445" //消费组ID
popOrderCreatTopic = "open_message_pop_order_create_E1D746D42474D5F1F1A10CECE75D99F6" //pop订单创建主题名称
popOrderChangeTopic = "open_message_pop_order_change_E1D746D42474D5F1F1A10CECE75D99F6" //pop订单修改主题名称
popOrderOutTopic = "open_message_pop_order_out_E1D746D42474D5F1F1A10CECE75D99F6" //pop订单出库主题名称
OrderOutTopic = "open_message_order_order_out_E1D746D42474D5F1F1A10CECE75D99F6" //订单出库主题名称
OrderCancelTopic = "open_message_order_order_cancel_E1D746D42474D5F1F1A10CECE75D99F6" //订单取消主题名称
OrderPayTopic = "open_message_order_order_pay_E1D746D42474D5F1F1A10CECE75D99F6" //订单支付主题名称
OrderCreatTopic = "open_message_order_order_create_E1D746D42474D5F1F1A10CECE75D99F6" //订单创建主题
DefaultSubscribeSize = 32 //默认拉取数量
popOrderCreatType = "popCreat" //存储到数据库pop订单创建类型
popOrderOutType = "popOut" //存储到数据库pop订单出库类型
popOrderChangeType = "popChange" //存储到数据库pop订单修改类型
OrderCreatType = "orderCreat" //订单创建类型
OrderPayType = "orderPay" //订单支付类型
OrderOutType = "orderOut" //订单出库主题
OrderCancelType = "orderCancel" //订单取消类型
)
var (
TopicList = []string{
popOrderCreatTopic, popOrderChangeTopic, popOrderOutTopic, OrderCreatTopic, OrderPayTopic, OrderOutTopic, OrderCancelTopic,
}
)
type JcqMessage struct { //model
ID int64 `orm:"column(id)" `
MessageID string `orm:"column(message_id)" `
MessageBody string `orm:"column(message_body)"`
BusinessID string `orm:"column(business_id)"`
PropertyRetryTimes string `orm:"column(property_retry_times)"`
Status string `orm:"column(status)"` //表示业务逻辑状态 n 表示业务为处理 y 表示已处理
MessageType string `orm:"column(message_type)" //消息类型 对应上面的枚举`
}
type JqcTask struct {
TopicId string
Wg *sync.WaitGroup
}
type PopCreatObject struct { //序列化属性首字母必须大写 否则会出现赋值问题 切记! 也可以考虑使用simplejson就需要这么多的struct
OrderCreateTime string `json:"orderCreateTime"`
OrderId int64 `json:"orderId"`
OrderPaymentType int `json:"orderPaymentType"`
OrderStatus string `json:"orderStatus"`
OrderType int `json:"orderType"`
VenderId int64 `json:"venderId"`
}
type PopChangeObject struct { //Pop修改
ErpOrderStatus int `json:"erpOrderStatus"`
Modified int `json:"modified"`
OrderCreateTime int `json:"orderCreateTime"`
OrderId int64 `json:"orderId"`
OrderPaymentType int `json:"orderPaymentType"`
OrderType int `json:"orderType"`
VenderId int `json:"venderId"`
Yn int `json:"yn"`
}
type PopCreatOrderMessage struct { //pop订单创建结构体
PopCreatObj PopCreatObject `json:"object"`
}
type CreatOrderMessage struct {
OrderCreatObj PopCreatObject `json:"object"`
}
type PayOrderMessage struct {
OrderPayObject OrderPayObject `json:"object"`
}
type OrderPayObject struct {
OrderId int64 `json:"orderId"`
OrderPaymentTime int `json:"orderPaymentTime"`
OrderPaymentType int `json:"orderPaymentType"`
OrderType int `json:"orderType"`
VenderId int `json:"venderId"`
OrderStatus int `json:"orderStatus"`
}
func (t *JqcTask) Do() {
handleTopic(t.TopicId)
t.Wg.Done()
}
var jcqApi *jcqapi.API
// JCQSchedule creat by Hang
// 用于jcq队列返回数据处理 以及业务逻辑 由于在consumeInfo2加了ack 所以不会存在重复拉取的可能性
// 使用ants 同时启动topic数量的携程 进行handle
func JCQSchedule() {
jcqApi = jcqapi.New(accessKey, secretKey)
currentTopic := OrderPayTopic
handleTopic(currentTopic)
/* p, _ := ants.NewPoolWithFunc(10, func(data interface{}) {
task := data.(*JqcTask)
task.Do()
})
defer p.Release()
var wg sync.WaitGroup
wg.Add(len(TopicList))
tasks := make([]*JqcTask, 0, len(TopicList))
for i := 0; i < len(TopicList); i++ {
task := &JqcTask{
TopicId: TopicList[i],
Wg: &wg,
}
tasks = append(tasks, task)
p.Invoke(task)
}
wg.Wait()*/
}
//处理topic 针对不同的topic进行存库操作
func handleTopic(topicId string) {
consumeResults, err := jcqApi.ConsumeInfo2(topicId, consumerGroupID, DefaultSubscribeSize)
if err == nil {
if len(consumeResults) != 0 {
entityList := make([]JcqMessage, 0)
//构建实体
for _, result := range consumeResults {
if topicId == popOrderCreatTopic {
var r PopCreatOrderMessage
//js, _ := simplejson.NewJson([]byte(result.MessageBody))
json.Unmarshal([]byte(result.MessageBody), &r)
fmt.Println(r)
}
jcq := JcqMessage{
MessageID: result.MessageID,
MessageBody: result.MessageBody,
BusinessID: result.Properties.BUSINESSID,
PropertyRetryTimes: result.Properties.PROPERTYRETRYTIMES,
Status: "n", //默认给定初始值 未做处理
MessageType: transType(topicId),
}
entityList = append(entityList, jcq)
}
db := dao.GetDB()
if err = dao.CreateMultiEntities(db, entityList); err != nil {
baseapi.SugarLogger.Warnf("saveMessage orderID:%s, save jqs_message failed with error:%v", entityList, err)
} else { //存库成功进行调用API操作
//定义菜市api
jdmcshopapi := jdshopapi.New("37d36b62c0d14bd4b872f948b335c95czinj", "E1D746D42474D5F1F1A10CECE75D99F6", "efa7e1d1a22640fa990e6cf164b28608")
//定义果园api
jdgyshopapi := jdshopapi.New("f9c5ce9a5ce24218936924f7c4864cc9owe1", "E1D746D42474D5F1F1A10CECE75D99F6", "efa7e1d1a22640fa990e6cf164b28608")
for _, result := range consumeResults {
//处理订单支付订单取消和pop订单出库的topic
if topicId == OrderPayTopic || topicId == OrderCancelTopic || topicId == popOrderOutTopic {
var r PayOrderMessage
//js, _ := simplejson.NewJson([]byte(result.MessageBody))
json.Unmarshal([]byte(result.MessageBody), &r)
orderResult, err := jdmcshopapi.GetOrderById(r.OrderPayObject.OrderId, true)
isGy := false
if orderResult == nil && err == nil {
isGy = true
orderResult, err = jdgyshopapi.GetOrderById(r.OrderPayObject.OrderId, true) //查询不到之后说明不是这个账号的 使用果园再查一遍
}
if err == nil { //确定返回结果
// TO DO 处理数据转换为原先回调的结果
if orderResult == nil {
baseapi.SugarLogger.Debug("未查询到订单ID", r.OrderPayObject.OrderId)
} else {
callBackResult := TransFormOrderResultToCallBackResult(orderResult, topicId, isGy)
jdshop.OnCallbackMsg(callBackResult) //进行处理
}
}
}
}
}
}
baseapi.SugarLogger.Debug("handle Topic the end")
}
}
// 用于转换类型
func transType(topic string) string {
switch topic {
case popOrderCreatTopic:
return popOrderCreatType
case popOrderChangeTopic:
return popOrderChangeType
case popOrderOutTopic:
return popOrderOutType
case OrderCreatTopic:
return OrderCreatType
case OrderPayTopic:
return OrderPayType
case OrderOutTopic:
return OrderOutType
case OrderCancelTopic:
return OrderCancelType
default:
return ""
}
}
// TransFormOrderResultToCallBackResult 转换数据类型 使其可以进入原先回调方法
func TransFormOrderResultToCallBackResult(getOrderResult *jdshopapi.GetEnOrderResult, topicId string, isGy bool) *jdshopapi.CallBackResult {
return &jdshopapi.CallBackResult{
OrderStateRemark: getOrderResult.OrderStateRemark,
OrderRemark: getOrderResult.OrderRemark,
OrderSellerPrice: getOrderResult.OrderSellerPrice,
OrderState: getOrderResult.OrderState,
OrderType: getOrderResult.OrderType,
OrderPayment: getOrderResult.OrderPayment,
PayType: getOrderResult.PayType,
StoreID: getOrderResult.StoreID,
OrderTotalPrice: getOrderResult.OrderTotalPrice,
OrderExt: getOrderResult.OrderExt,
StoreOrder: getOrderResult.StoreOrder,
OrderStartTime: getOrderResult.OrderStartTime,
OrderID: getOrderResult.OrderID,
OrderSource: getOrderResult.OrderSource,
FreightPrice: getOrderResult.FreightPrice,
MsgType: TransMsgType(topicId),
Pin:/*splitPin(getOrderResult.Pin),*/ "jd_temp",
IDSopShipmenttype: getOrderResult.IDSopShipmenttype,
ScDT: getOrderResult.ScDT,
SellerDiscount: getOrderResult.SellerDiscount,
ConsigneeInfo: getOrderResult.ConsigneeInfo,
ItemInfoList: getOrderResult.ItemInfoList,
VendorOrgCode: getVendorOrgCode(isGy),
MenDianID: getOrderResult.MenDianID,
BalanceUsed: getOrderResult.BalanceUsed}
}
// TransMsgType 目前业务处理函数仅对一下三种topic做了业务处理
func TransMsgType(topicId string) string {
switch topicId {
case OrderPayTopic:
return jcqapi.TopicOrderPay
case OrderCancelTopic:
return jcqapi.TopicOrderCancel
case popOrderOutTopic:
return jcqapi.TopicOrderOut
default:
return ""
}
}
//由于返回的pin长度过长 进行md5操作 压缩长度
func splitPin(pin string) string {
h := md5.New()
h.Write([]byte(pin))
s := hex.EncodeToString(h.Sum(nil))
return s
}
// 根据标识判断加密标识
func getVendorOrgCode(isGy bool) string {
if isGy {
return "2"
} else {
return "1"
}
}

View File

@@ -1,83 +0,0 @@
package jdslogin
// RefreshQRCode Creat By 2022/04/18
// RefreshQRCode Author By Hang xu
// RefreshQRCode 用于爬取京东的二维码链接 并持久化进入数据库中
//func RefreshQRCode() (retval string, err error) {
// baseapi.SugarLogger.Debug("BEGIN JD SHOP QRCODE SPIDER---------------------------------------------------")
// const (
// seleniumPath = `/usr/bin/chromedriver`
// port = 9515
// )
// opts := []selenium.ServiceOption{}
//
// selenium.SetDebug(true)
//
// service, err := selenium.NewChromeDriverService(seleniumPath, port, opts...)
// if nil != err {
// fmt.Println("start a chromedriver service falid", err.Error())
// return
// }
// ////server关闭之后chrome窗口也会关闭
// defer service.Stop()
// //链接本地的浏览器 chrome
// caps := selenium.Capabilities{
// //"browserName": "/Applications/Google Chrome Dev.app/Contents/MacOS/Google Chrome Dev",
// "browserName": "/opt/google/chrome",
// }
// //禁止图片加载,加快渲染速度
// imagCaps := map[string]interface{}{
// "profile.managed_default_content_settings.images": 2,
// }
// chromeCaps := chrome.Capabilities{
// Prefs: imagCaps,
// Path: "/opt/google/chrome",
// Args: []string{
// //静默执行请求
// "--headless", // 设置Chrome无头模式在linux下运行需要设置这个参数否则会报错
// "--no-sandbox",
// "--user-agent=Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36", // 模拟user-agent防反爬
// "--Host=porder.shop.jd.com",
// "--Connection=keep-alive",
// },
// }
// //以上是设置浏览器参数
// caps.AddChrome(chromeCaps)
//
// url := "https://porder.shop.jd.com/order/orderlist/allOrders"
// w_b1, err := selenium.NewRemote(caps, fmt.Sprintf("http://localhost:%d/wd/hub", port))
// if err != nil {
// fmt.Println("connect to the webDriver faild", err.Error())
// return
// }
//
// err = w_b1.Get(url)
// pageSource, err := w_b1.PageSource()
// baseapi.SugarLogger.Debug("pageSource", pageSource)
// qr, err := w_b1.FindElement("id", "js-login-qrcode")
// qrStr, err := qr.GetAttribute("src")
// baseapi.SugarLogger.Debug("qrStr:", qrStr) //当前qrcode sample:https://passport.shop.jd.com/login/json/qrcode_show.action?_timeStr=165026591404449b823cc58684d948d0e0ca8351adf64
// // 进行存库操作
// // save to database 存入 new_config表中
// db := dao.GetDB()
// txDB, _ := dao.Begin(db)
// defer func() {
// if r := recover(); r != nil {
// dao.Rollback(db, txDB)
// panic(r)
// }
// }()
// configList, err := dao.QueryConfigs(db, "jdsQRcode", "Cookie", "")
// if err != nil {
// dao.Rollback(db, txDB)
// return "", err
// }
// if _, err = dao.UpdateEntityLogically(db, configList[0], map[string]interface{}{
// "Value": qrStr,
// }, "", nil); err != nil {
// dao.Rollback(db, txDB)
// return "", err
// }
// baseapi.SugarLogger.Debug("THE JD SHOP QRCODE SPIDER THE END---------------------------------------------")
// return "", nil
//}

View File

@@ -1,50 +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("订单当前状态已满足当前操作")
ErrOrderStatusShippedCurOperation = errors.New("订单已发货,不允许再次执行发货")
ErrOrderStatusAlreadySatisfyCurOperationELM = errors.New("无需切自配送")
ErrOrderStatusAlreadySatisfyCurOperationMTWM = errors.New("非专送、快送、混合送订单不允许调用此接口 level:0, code:1047")
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,128 +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) {
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
}
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,34 +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)
}
}
func TestRefreshTiktokShopToken(t *testing.T) {
RefreshTiktokShopToken(nil)
}

View File

@@ -2,35 +2,17 @@ package cms
import ( import (
"fmt" "fmt"
"git.rosy.net.cn/baseapi/platformapi/tencent_map" "git.rosy.net.cn/baseapi/platformapi/mtunionapi"
"math"
"reflect" "reflect"
"regexp" "regexp"
"strconv" "strconv"
"strings"
"time" "time"
"git.rosy.net.cn/baseapi/platformapi/autonavi"
"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/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/jxcontext"
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch" "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"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/globals/api"
) )
const ( const (
@@ -46,64 +28,8 @@ type SysConfigLimit struct {
} }
var ( var (
serviceInfo map[string]interface{} serviceInfo map[string]interface{}
allowUpdatePlaceFieldsMap = map[string]bool{
"name": true,
"enabled": true,
"mtpsPrice": true,
}
regexpMsgContentOpID = regexp.MustCompile(`"openid":"(.*?)"`) 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
},
},
}
AutonaviKeyList = []string{autonavi.AMAPCyclingPlanKey1, autonavi.AMAPCyclingPlanKey2, autonavi.AMAPCyclingPlanKey3, autonavi.AMAPCyclingPlanKey4, autonavi.AMAPCyclingPlanKey5}
AutonaviKeyIndex = 0
) )
func InitServiceInfo(version string, buildTime time.Time, gitCommit string) { func InitServiceInfo(version string, buildTime time.Time, gitCommit string) {
@@ -117,49 +43,41 @@ func InitServiceInfo(version string, buildTime time.Time, gitCommit string) {
"buildTime": buildTimeStr, "buildTime": buildTimeStr,
"gitCommit": gitCommit, "gitCommit": gitCommit,
"metaData": map[string]interface{}{ "metaData": map[string]interface{}{
"skuNamePrefix": model.SkuNamePrefixNames, "vendorTypeName": model.VendorTypeName,
"skuNameUnit": model.UnitNames, "vendorName": model.VendorChineseNames,
"skuSpecUnit": model.SpecUnitNames, //"vendorImg": model.VendorImg,
"skuStatus": model.SkuStatusName, //"vendorColors": model.VendorColors,
"storeDeliveryRangeType": model.DeliveryRangeTypeName,
"storeDeliveryType": model.DeliveryTypeName,
"storeStatus": model.StoreStatusName,
"categoryType": model.CategoryTypeName,
"vendorTypeName": model.VendorTypeName,
"vendorName": model.VendorChineseNames,
"orderStatus": model.OrderStatusName, "orderStatus": model.OrderStatusName,
"waybillStatus": model.WaybillStatusName, "waybillStatus": model.WaybillStatusName,
"orderTypeName": model.OrderTypeName, "orderTypeName": model.OrderTypeName,
"taskStatusName": tasksch.TaskStatusName, "taskStatusName": tasksch.TaskStatusName,
"opRequestTypeName": model.RequestTypeName,
"opRequestStatusName": model.RequestStatusName,
"storeMsgSendStatusName": model.StoreMsgSendStatusName, "storeMsgSendStatusName": model.StoreMsgSendStatusName,
"shopChineseNames": model.ShopChineseNames,
"printerVendorInfo": model.PrinterVendorInfo, "printerVendorInfo": model.PrinterVendorInfo,
"printerStatusName": partner.PrinterStatusName,
"purchaseVendorInfo": model.PurchaseVendorInfo, "purchaseVendorInfo": model.PurchaseVendorInfo,
"afsReasonTypeName": model.AfsReasonTypeName, "afsReasonTypeName": model.AfsReasonTypeName,
"afsAppealTypeName": model.AfsAppealTypeName, "afsAppealTypeName": model.AfsAppealTypeName,
"actTypeName": model.ActTypeName,
"actStatusName": model.ActStatusName,
"actCreateTypeName": model.ActCreateTypeName,
"storeAuditStatusName": model.StoreAuditStatusName,
"configTypeName": model.ConfigTypeName, "configTypeName": model.ConfigTypeName,
"autoSaleAt": AutoSaleAtStr,
"userTypeName": model.UserTypeName, "userTypeName": model.UserTypeName,
"storePriceTypeName": model.StorePriceTypeName,
"payStatusName": model.PayStatusName,
"refundStatusName": model.RefundStatusName,
"autoReplyTypeName": model.AutoReplyTypeName,
"complaintReasons": model.ComplaintReasons, "complaintReasons": model.ComplaintReasons,
"supplementType": model.SupplementTypeName, "supplementType": model.SupplementTypeName,
"operateType": model.OperateTypeName, "operateType": model.OperateTypeName,
"thingType": model.ThingTypeName,
"apiFunctionName": model.ApiFunctionName, "apiFunctionName": model.ApiFunctionName,
"vendorStatus": model.VendorStatus, "vendorStatus": model.VendorStatus,
"couponsStatus": model.CouponStatusName, "unionActTypeNames": map[int]map[int]interface{}{
"ebaiSupplierID": ebai.EbaiSupplierIDMap, model.VendorIDMTWM: map[int]interface{}{
"ebaiSupplierInfo": ebai.EbaiSupplierInfo, mtunionapi.ActTypeQB: "券包推广",
},
//model.VendorIDTB: map[int]interface{}{
// tbunionapi.TbElmActTypeBDH: "本地化",
//},
//model.VendorIDPDD: map[int]interface{}{
// 1: "进行中的活动",
//},
model.VendorIDJDShop: map[int]interface{}{
2: "进行中",
},
},
"unionOrderStatusName": model.UnionOrderStatusName,
}, },
} }
} }
@@ -196,217 +114,20 @@ func GetPlaces(ctx *jxcontext.Context, keyword string, includeDisabled bool, par
sqlParams = append(sqlParams, params["level"]) sqlParams = append(sqlParams, params["level"])
} }
sql += " ORDER BY t1.level, t1.name" sql += " ORDER BY t1.level, t1.name"
// globals.SugarLogger.Debug(sql)
places := []*model.Place{} places := []*model.Place{}
return places, dao.GetRows(nil, &places, sql, sqlParams...) 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.TencentMapAPI.GetCoordinateDistrictCode(lng, lat), nil
}
func GetCoordinateCityInfo(ctx *jxcontext.Context, lng, lat float64) (name string, err error) {
name, _ = api.TencentMapAPI.GetCoordinateCityInfo(lng, lat)
return name, err
} }
func SendMsg2Somebody(ctx *jxcontext.Context, mobileNum, verifyCode, msgType, msgContent string) (err error) { 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 return err
} }
func AddConfig(ctx *jxcontext.Context, key, configType, value string) (err error) { func AddConfig(ctx *jxcontext.Context, key, configType, value string) (err error) {
if err = checkConfig(model.SyncFlagNewMask, configType, key, value); err != nil { // if err = checkConfig(model.SyncFlagNewMask, configType, key, value); err != nil {
return err // return err
} // }
db := dao.GetDB() db := dao.GetDB()
conf := &model.NewConfig{ conf := &model.NewConfig{
@@ -417,75 +138,7 @@ func AddConfig(ctx *jxcontext.Context, key, configType, value string) (err error
dao.WrapAddIDCULDEntity(conf, ctx.GetUserName()) dao.WrapAddIDCULDEntity(conf, ctx.GetUserName())
err = dao.CreateEntity(db, conf) err = dao.CreateEntity(db, conf)
if configType == model.ConfigTypeSys && err == nil { if configType == model.ConfigTypeSys && err == nil {
err = onSysConfigChanged(key, value) // 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, "")
} }
return err return err
} }
@@ -494,9 +147,6 @@ func UpdateConfig(ctx *jxcontext.Context, key, configType, value string) (hint s
if key == "" { if key == "" {
return "", fmt.Errorf("修改配置必须给定key") return "", fmt.Errorf("修改配置必须给定key")
} }
if err = checkConfig(model.SyncFlagModifiedMask, configType, key, value); err != nil {
return "", err
}
hint = "1" hint = "1"
db := dao.GetDB() db := dao.GetDB()
@@ -520,54 +170,12 @@ func UpdateConfig(ctx *jxcontext.Context, key, configType, value string) (hint s
} }
switch configType { switch configType {
case model.ConfigTypePricePack: 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: default:
dao.Commit(db, txDB) dao.Commit(db, txDB)
} }
if configType == model.ConfigTypeSys && err == nil { if configType == model.ConfigTypeSys && err == nil {
err = onSysConfigChanged(key, value) // err = onSysConfigChanged(key, value)
} }
return hint, err return hint, err
} }
@@ -575,198 +183,3 @@ func UpdateConfig(ctx *jxcontext.Context, key, configType, value string) (hint s
func QueryConfigs(key, configType, keyword string) (configList []*model.NewConfig, err error) { func QueryConfigs(key, configType, keyword string) (configList []*model.NewConfig, err error) {
return dao.QueryConfigs(dao.GetDB(), key, configType, keyword) 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
}
// GetSToURidingDistance 获取商家与用户间步行距离
func GetSToURidingDistance(sLng, sLat, uLng, uLat float64, orderId string) (stepInfo interface{}, err error) {
coordList, err := api.TencentMapAPI.TencentCoordinateChange(&tencent_map.TencentCoordinateChangeReq{
Locations: fmt.Sprintf("%.6f,%.6f;%.6f,%.6f", sLat, sLng, uLat, uLng),
Type: tencent_map.CoordinateChangeTypeBaidu,
})
if err == nil && len(coordList) == 2 {
param := &tencent_map.TencentCyclingPlanningReq{
From: fmt.Sprintf("%s,%s", coordList[0].Lat, coordList[0].Lng),
To: fmt.Sprintf("%s,%s", coordList[1].Lat, coordList[1].Lng),
}
if stepInfo, err = api.TencentMapAPI.WalkingDistance(param); err == nil {
return stepInfo, nil
}
}
return 0, err
}
// GetSToURidingDistance2 获取商家与用户间步行距离
func GetSToURidingDistance2(sLng, sLat, uLng, uLat float64, orderId string, vendors []int64) (wayBill *model.Waybill, err error) {
var (
db = dao.GetDB()
vendorMaps = map[int]int{model.VendorIDDada: 1, model.VendorIDFengNiao: 1, model.VendorIDMTPS: 1, model.VendorIDUUPT: 1, model.VendorIDSFPS: 1}
)
for {
// 骑手坐标
waybills, err := dao.GetWaybills(db, orderId, vendors)
if err != nil {
return nil, err
}
if len(waybills) == model.NO {
return nil, fmt.Errorf("请先创建运单,或者转自配送")
}
for _, v := range waybills {
// 获取骑行路线图
if v.OriginalData == "" && v.WaybillVendorID == model.VendorJXFakeWL {
originalData, distance, durationTime, err2 := GetCyclingLine(sLng, sLat, uLng, uLat)
if err2 == nil && len(originalData) != model.NO {
v.OriginalData = strings.Join(originalData, ";")
v.Distance = distance
v.DurationTime = durationTime + 500
}
}
if vendorMaps[v.WaybillVendorID] == model.YES {
// 如果是三方配送,更新骑手信息
if handler := partner.GetDeliveryPlatformFromVendorID(v.WaybillVendorID); handler != nil {
riderInfo, _ := handler.Handler.GetRiderInfo(v.VendorOrderID, v.ID+1000000, v.VendorWaybillID)
if riderInfo != nil {
if len(riderInfo.Longitude) < len("104.065861") || riderInfo.Longitude != "" {
riderInfo.Longitude += "0"
}
if len(riderInfo.Latitude) < len("27.934441") || riderInfo.Latitude != "" {
riderInfo.Latitude += "0"
}
v.CourierCoordinate = fmt.Sprintf("%s,%s", riderInfo.Longitude, riderInfo.Latitude)
if (v.CourierName == "" || v.CourierMobile == "") && riderInfo.CourierName != "" {
v.CourierName = riderInfo.CourierName
v.CourierMobile = riderInfo.CourierPhone
}
}
}
} else {
// 如果是平台配送,获取骑手信息
if handler := partner.GetPurchaseOrderHandlerFromVendorID(v.WaybillVendorID); handler != nil {
riderInfo, _ := handler.OrderLogisticsStatus(v.VendorOrderID)
if riderInfo != nil {
if len(riderInfo.Longitude) < len("104.065861") || riderInfo.Longitude != "" {
riderInfo.Longitude += "0"
}
if len(riderInfo.Latitude) < len("27.934441") || riderInfo.Latitude != "" {
riderInfo.Latitude += "0"
}
v.CourierCoordinate = fmt.Sprintf("%s,%s", riderInfo.Longitude, riderInfo.Latitude)
if (v.CourierName == "" || v.CourierMobile == "") && riderInfo.CourierName != "" {
v.CourierName = riderInfo.CourierName
v.CourierMobile = riderInfo.CourierPhone
}
}
}
}
// 当这个运单为假物流/门店真实自送/获取运单骑手信息为空的时候使用假的骑手信息
if (v.WaybillVendorID == model.VendorJXFakeWL || v.WaybillVendorID == model.VendorIDUnknown || v.CourierCoordinate == "") && v.OriginalData != "" {
riderLine := strings.Split(v.OriginalData, ";") // 路线坐标点
courierDistance := float64(time.Now().Unix()-v.WaybillCreatedAt.Unix()) * (float64(v.Distance) / float64(v.DurationTime)) // 当前骑手骑行距离
if courierDistance >= float64(v.Distance) {
courierDistance = float64(v.Distance)
}
nowCourierDrop := int64(math.Ceil((courierDistance / float64(v.Distance)) * float64(len(riderLine)))) // 当前骑手骑行距离,占中的骑行距离百分比.
if nowCourierDrop >= int64(len(riderLine)) {
v.CourierCoordinate = riderLine[nowCourierDrop-1]
}
if nowCourierDrop <= 0 {
v.CourierCoordinate = riderLine[0]
}
if v.Status >= model.WaybillStatusDelivered {
v.CourierCoordinate = riderLine[len(riderLine)-1]
}
if v.Status == model.WaybillStatusCourierArrived {
order, _ := partner.CurOrderManager.LoadOrder(orderId, v.OrderVendorID)
storeDetail, err := dao.GetStoreDetail2(dao.GetDB(), order.JxStoreID, order.VendorStoreID, order.VendorID)
if err == nil && storeDetail != nil {
v.CourierCoordinate = fmt.Sprintf("%s,%s", utils.Float64ToStr(jxutils.IntCoordinate2Standard(storeDetail.Lng)), utils.Float64ToStr(jxutils.IntCoordinate2Standard(storeDetail.Lat)))
}
}
if v.CourierCoordinate == "" {
v.CourierCoordinate = riderLine[nowCourierDrop]
}
} else if (v.WaybillVendorID == model.VendorJXFakeWL || v.WaybillVendorID == model.VendorIDUnknown || v.CourierCoordinate == "") && v.OriginalData == "" {
lng := utils.Str2Float64(fmt.Sprintf("%0.6f", (sLng-uLng)/float64(300)))
lat := utils.Str2Float64(fmt.Sprintf("%0.6f", (sLat-uLat)/float64(300)))
originalData := make([]string, 0, 0)
originalData = append(originalData, fmt.Sprintf("%.6f,%.6f", sLng, sLat))
var nLng float64
var nLat float64
for i := 1; i <= 300; i++ {
if sLng > uLng {
nLng = sLng - (lng * float64(i))
} else {
nLng = sLng + (lng * float64(i))
}
if sLat > uLat {
nLat = sLat - (lat * float64(i))
} else {
nLat = sLat + (lat * float64(i))
}
fakeCourier := fmt.Sprintf("%.6f,%.6f", nLng, nLat)
originalData = append(originalData, fakeCourier)
}
originalData = append(originalData, fmt.Sprintf("%.6f,%.6f", uLng, uLat))
v.Distance = 5001 // 距离,固定
v.DurationTime = 600 // 固定骑行时间
v.OriginalData = strings.Join(originalData, ";")
v.CourierCoordinate = originalData[0]
}
dao.UpdateEntity(db, v, "OriginalData", "CourierCoordinate", "Distance", "DurationTime")
if v.CourierName == "" || v.CourierMobile == "" {
v.CourierName = "暂无骑手"
v.CourierMobile = "暂无电话"
}
return v, nil
}
}
}
// GetCyclingLine 获取骑行路线
func GetCyclingLine(sLng, sLat, uLng, uLat float64) (polyLineList []string, distance, duration int64, err error) {
// 百度
/* var coords []*baidunavi.Coordinate
coords = append(coords, &baidunavi.Coordinate{
Lng: sLng,
Lat: sLat,
}, &baidunavi.Coordinate{
Lat: uLat,
Lng: uLng,
})*/
// 高德坐标转换成百度坐标
/*coords, err := api.TencentMapAPI.TencentCoordinateChange(&tencent_map.TencentCoordinateChangeReq{
Locations: fmt.Sprintf("%.6f,%.6f;%.6f,%.6f", sLat, sLng, uLat, uLng),
Type: tencent_map.CoordinateChangeTypeBaidu,
})
if err != nil || len(coords) <= model.NO {
return nil, 0, 0, err
}
*/
distance, duration, polyLineList, err = api.TencentMapAPI.TencentCyclingPlanning(&tencent_map.TencentCyclingPlanningReq{
From: fmt.Sprintf("%.6f,%.6f", sLat, sLng),
To: fmt.Sprintf("%.6f,%.6f", uLat, uLng),
})
return
}

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

@@ -0,0 +1,11 @@
package cms
import (
"fmt"
"testing"
)
func TestConn(t *testing.T) {
err := DelPrinterSeq(1000, "120220915001012")
fmt.Println(err)
}

View File

@@ -4,10 +4,10 @@ import (
"time" "time"
"git.rosy.net.cn/baseapi/utils" "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"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext" "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"
"git.rosy.net.cn/jx-callback/business/model/dao"
) )
type MessageStatusExt struct { type MessageStatusExt struct {
@@ -68,16 +68,17 @@ func GetStoreMessages(ctx *jxcontext.Context, msgIDs, storeIDs, types []int, fro
txDB, _ := dao.Begin(db) txDB, _ := dao.Begin(db)
defer dao.Commit(db, txDB) defer dao.Commit(db, txDB)
var msgList []*model.Message var msgList []*model.Message
// globals.SugarLogger.Debug(sql)
if err = dao.GetRowsTx(txDB, &msgList, sql, sqlParams...); err == nil { if err = dao.GetRowsTx(txDB, &msgList, sql, sqlParams...); err == nil {
pagedInfo = &model.PagedInfo{ pagedInfo = &model.PagedInfo{
TotalCount: dao.GetLastTotalRowCount2(db, txDB), TotalCount: dao.GetLastTotalRowCountTx(txDB),
Data: msgList, Data: msgList,
} }
} }
return pagedInfo, err 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 := ` sql := `
SELECT SQL_CALC_FOUND_ROWS SELECT SQL_CALC_FOUND_ROWS
t1.*, t1.*,
@@ -91,10 +92,6 @@ func GetStoreMessageStatuses(ctx *jxcontext.Context, msgIDs, storeIDs, confirmSt
sql += " AND t1.store_id IN (" + dao.GenQuestionMarks(len(storeIDs)) + ")" sql += " AND t1.store_id IN (" + dao.GenQuestionMarks(len(storeIDs)) + ")"
sqlParams = append(sqlParams, 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 { if len(msgIDs) > 0 {
sql += " AND t1.message_id IN (" + dao.GenQuestionMarks(len(msgIDs)) + ")" sql += " AND t1.message_id IN (" + dao.GenQuestionMarks(len(msgIDs)) + ")"
sqlParams = append(sqlParams, msgIDs) sqlParams = append(sqlParams, msgIDs)
@@ -126,9 +123,11 @@ func GetStoreMessageStatuses(ctx *jxcontext.Context, msgIDs, storeIDs, confirmSt
txDB, _ := dao.Begin(db) txDB, _ := dao.Begin(db)
defer dao.Commit(db, txDB) defer dao.Commit(db, txDB)
var msgStatusList []*MessageStatusExt var msgStatusList []*MessageStatusExt
// globals.SugarLogger.Debug(sql)
// globals.SugarLogger.Debug(utils.Format4Output(sqlParams, false))
if err = dao.GetRowsTx(txDB, &msgStatusList, sql, sqlParams...); err == nil { if err = dao.GetRowsTx(txDB, &msgStatusList, sql, sqlParams...); err == nil {
pagedInfo = &model.PagedInfo{ pagedInfo = &model.PagedInfo{
TotalCount: dao.GetLastTotalRowCount2(db, txDB), TotalCount: dao.GetLastTotalRowCountTx(txDB),
Data: msgStatusList, Data: msgStatusList,
} }
} }

View File

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

View File

@@ -1,292 +0,0 @@
package cms
//
//import (
// "encoding/json"
// "errors"
// "fmt"
// "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/purchase/jx/localjx"
// "github.com/360EntSecGroup-Skylar/excelize"
// "io"
// "mime/multipart"
// "strings"
//)
//
//// 根据excel新增待拣货订单
//func CreateOrderByExcel(ctx *jxcontext.Context, files []*multipart.FileHeader) (hint string, err error) {
// if len(files) == 0 {
// return "", errors.New("没有文件上传!")
// }
// fileHeader := files[0]
// file, err := fileHeader.Open()
// hint, err = RefreshJxPriceByExcelBin(ctx, file, true, true)
// file.Close()
// return hint, err
//}
//
//type CreateOrderByExcelStore struct {
// BuyerComment int // 备注
// StoreID int // 门店id
// Skus int // 商品列表
// ExpectedDeliveredTimestamp int // 预期送达时间
// TotalPrice int // 总价格
// FreightPrice int // 运费
// OrderPrice int // 订单价格
// ActualPayPrice int // 顾客实际支付
// OrderID int // 订单id
// StoreName int // 门店名称
// Weight int // 重量
// FromStoreID int // 物料ID
// EarningType int // 结算方式1为报价2为扣点,0无
// OrderType int // 订单类型
// IsBuyNowPrice int // 守价的值只有0和1
// IsPriceDefend int
// OrderID2 int
// UserID int // 用户id
// AddressID int // 收货地址id
// CreateType int // "创建类型, 0:预创建, 1:创建"
// IsDeliverySelf int // 自提
//}
//
//// 赋值excel表字段排序
//func SortExcelTable() *CreateOrderByExcelStore {
// return &CreateOrderByExcelStore{
// StoreID: 1,
// StoreName: 2,
// UserID: 3,
// AddressID: 4,
// Skus: 5,
// Weight: 6,
// TotalPrice: 7,
// FreightPrice: 8,
// OrderPrice: 9,
// ActualPayPrice: 10,
// ExpectedDeliveredTimestamp: 11,
// OrderType: 12,
// FromStoreID: 13,
// EarningType: 14,
// BuyerComment: 15,
//
// CreateType: 16,
// IsDeliverySelf: 17,
// IsPriceDefend: 18,
// IsBuyNowPrice: 19,
// OrderID: 20,
// OrderID2: 21,
// }
//}
//
//// 订单结构体
//type ExcelOrderStruct struct {
// BuyerComment string `json:"buyerComment"` // 备注
// StoreID int `json:"storeID"`
// Skus []*JxSkuInfo `json:"skus"`
// ExpectedDeliveredTimestamp int64 `json:"expectedDeliveredTimestamp"` // 预期送达时间
// TotalPrice int64 `json:"totalPrice"` // 单位为分 订单总价
// FreightPrice int64 `json:"freightPrice"` // 单位为分 订单配送费
// OrderPrice int64 `json:"orderPrice"` // 单位为分 订单商品价格
// ActualPayPrice int64 `json:"actualPayPrice"` // 单位为分 顾客实际支付
// OrderID int64 `json:"orderID"`
// StoreName string `json:"storeName"`
// Weight int `json:"weight"`
// FromStoreID int `json:"fromStoreID"` //
// EarningType int `json:"earningType"`
// OrderType int `json:"orderType"`
// IsBuyNowPrice int `json:"isBuyNowPrice"`
// IsPriceDefend int `json:"isPriceDefend"`
// OrderID2 string `json:"-"` // 订单id2
// UserID string `json:"userID"` // 用户id
// AddressId int64 `json:"address_id"` // 地址id
//}
//
//// 商品列表
//type JxSkuInfo struct {
// SkuID int `json:"skuID"`
// Count int `json:"count"`
// Price int64 `json:"price,omitempty"` // 原价
// SalePrice int64 `json:"salePrice,omitempty"` // 售卖价
// Name string `json:"name"`
// Weight int `json:"weight"`
// GroupSign bool `json:"groupSign"`
// DefendPrice int64 `json:"defendPrice"` //守价
//}
//
//// 解析excel到订单结构体当中
//func GetCellIntoOrder(rowNum int, row []string, sheetParam *CreateOrderByExcelStore, order *ExcelOrderStruct, nameMap map[string]string) (errMsg string) {
// address := make(map[string]int64, 0)
// for k, cell := range row {
// switch k {
// case sheetParam.StoreID:
// order.StoreID = utils.Str2Int(cell)
// case sheetParam.StoreName:
// order.StoreName = cell
// case sheetParam.UserID:
// order.UserID = cell
// case sheetParam.AddressID:
// order.AddressId = utils.Str2Int64(cell)
// case sheetParam.Skus:
// shop := make([]*JxSkuInfo, 0, 0)
// if err := json.Unmarshal([]byte(cell), shop); err != nil {
// return fmt.Sprintf("解析excel文档用户商品列表错,检查数据格式是否正确")
// }
// order.Skus = shop
// case sheetParam.Weight:
// order.Weight = utils.Str2Int(cell)
// case sheetParam.TotalPrice:
// order.TotalPrice = utils.Str2Int64(cell)
// case sheetParam.FreightPrice:
// order.FreightPrice = utils.Str2Int64(cell)
// case sheetParam.OrderPrice:
// order.OrderPrice = utils.Str2Int64(cell)
// case sheetParam.ActualPayPrice:
// order.ActualPayPrice = utils.Str2Int64(cell)
// case :
//
//
//
// }
//
// if k == sheetParam.SkuNameIDCol {
// cellReplace := strings.ReplaceAll(cell, "", ",")
// if cellReplace != "" {
// if cellReplace[len(cellReplace)-1:len(cellReplace)] == "," {
// cellReplace = cellReplace[0 : len(cellReplace)-1]
// }
// nameIDs := strings.Split(cellReplace, ",")
// for _, v := range nameIDs {
// if nameMap[v] != "" {
// return fmt.Sprintf(" Excel中含有重复的nameID[%v]列,[%v]行nameID [%v]\n", k+1, rowNum+1, v)
// } else {
// nameMap[v] = v
// }
// }
// }
// storeSkuNamePrice.NameIDGroup = cellReplace
// }
// if k == sheetParam.SkuPriceCol {
// if IsChineseChar(cell) {
// return fmt.Sprintf("Excel格式排版发生了变化在[%v]列,[%v]行附近可能增加或减少了一列", k+1, rowNum+1)
// }
// storeSkuNamePrice.Price = int(utils.Float64TwoInt64(utils.Str2Float64(cell) * 100))
// }
// if k == sheetParam.SkuUnitCol {
// storeSkuNamePrice.Unit = cell
// }
// }
// return errMsg
//}
//
//func AnalysisExcelOrder(ctx *jxcontext.Context, reader io.Reader, isAsync, isContinueWhenError bool) {
// excelSort := SortExcelTable()
// taskSeqFunc := func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
// switch step {
// case 0:
// xlsx, err := excelize.OpenReader(reader)
// if err != nil {
// return "", err
// }
// rows, _ := xlsx.GetRows(xlsx.GetSheetName(1))
// for rowNum, row := range rows {
// if rowNum < model.YES { // 第一行跳过
// continue
// }
// storeSkuNamePrice := &localjx.JxOrderInfo{}
// errMsg += GetCellIntoStruct(rowNum, row, excelSort, storeSkuNamePrice, nameMap)
// storeSkuNamePriceList = append(storeSkuNamePriceList, storeSkuNamePrice)
// }
// if errMsg != "" {
// return "", errors.New(errMsg)
// } else {
// isErr = true
// }
// case 1:
// db := dao.GetDB()
// storeSkuNamePriceListOrg, _ := dao.GetStoreSkuNamePrice(db)
// CreateOrUpdateStoreSkuNamePriceByExcel(db, ctx, storeSkuNamePriceList, storeSkuNamePriceListOrg)
// storeSkuNamePriceListNew, _ := dao.GetStoreSkuNamePrice(db)
// storeSkuNamePriceMapNew := StoreSkuNamePriceList2Map(ctx, storeSkuNamePriceListNew)
// for _, v := range storeSkuNamePriceList {
// if storeSkuNamePriceMapNew[v.OutSkuID] != nil {
// storeSkuNamePriceListUpdate = append(storeSkuNamePriceListUpdate, storeSkuNamePriceMapNew[v.OutSkuID])
// }
// }
// taskFunc := func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
// storeSkuNamePrice := batchItemList[0].(*model.StoreSkuNamePrice)
// var skuBindInfos []*StoreSkuBindInfo
// nameIDGroup := strings.Split(storeSkuNamePrice.NameIDGroup, ",")
// for _, v := range nameIDGroup {
// if v != "" {
// nameID := int(utils.Str2Int64(v))
// for _, vv := range storeIDs {
// skuList, err2 := dao.GetStoreSkusByNameIDs(db, []int{vv}, nameID)
// err = err2
// if len(skuList) > 0 {
// unitPrice := 0
// if skuList[0].Unit == model.UnitNames[0] {
// if storeSkuNamePrice.Unit == "KG" {
// unitPrice = storeSkuNamePrice.Price / 2
// } else {
// unitPrice = storeSkuNamePrice.Price
// }
// } else {
// unitPrice = storeSkuNamePrice.Price
// }
// storeSkuBindInfo := &StoreSkuBindInfo{
// NameID: nameID,
// UnitPrice: unitPrice,
// }
// skuBindInfos = append(skuBindInfos, storeSkuBindInfo)
// outSuccess := DataSuccess{
// NameID: nameID,
// Name: skuList[0].Name,
// Unit: storeSkuNamePrice.Unit,
// OrgPrice: utils.Str2Float64(utils.Int64ToStr(skuList[0].UnitPrice)) / 100,
// NowPrice: utils.Str2Float64(utils.Int64ToStr(int64(unitPrice))) / 100,
// MixPrice: utils.Str2Float64(utils.Int64ToStr(int64(unitPrice)-skuList[0].UnitPrice)) / 100,
// }
// dataLock.AppendDataSuccess(outSuccess)
// } else {
// //京西xx门店没有关注该商品
// outFailed := DataFailed{
// NameID: nameID,
// Name: storeSkuNamePrice.Name,
// Comment: fmt.Sprintf("京西[%v]门店没有关注该商品商品nameID[%v]Excel上商品名[%v]", vv, nameID, storeSkuNamePrice.Name),
// }
// dataLock.AppendDataFailed(outFailed)
// }
// }
// } else {
// //nameID为空还未填写nameID
// outFailed := DataFailed{
// NameID: 0,
// Name: storeSkuNamePrice.Name,
// Comment: fmt.Sprintf("商品nameID为空还未填写商品nameIDExcel上商品名[%v]", storeSkuNamePrice.Name),
// }
// dataLock.AppendDataFailed(outFailed)
// }
// }
// retVal = skuBindInfos
// return retVal, err
// }
// taskParallel := tasksch.NewParallelTask("刷新京西价", tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError), ctx, taskFunc, storeSkuNamePriceListUpdate)
// tasksch.HandleTask(taskParallel, task, true).Run()
// skuBindInfosInter, err = taskParallel.GetResult(0)
// case 2:
// //更新京西价
// for _, v := range skuBindInfosInter {
// skuBindInfoList = append(skuBindInfoList, v.(*StoreSkuBindInfo))
// }
// if isErr {
// UpdateStoresSkus(ctx, 0, storeIDs, skuBindInfoList, false, false, isAsync, isContinueWhenError)
// }
// case 3:
// //写Excel
// WriteToExcelJx(task, dataLock.dataSuccessList, dataLock.dataFailedList)
// }
// return result, err
// }
//}

View File

@@ -0,0 +1,467 @@
package cms
import (
"encoding/json"
"errors"
"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
}
}
}
// 简历连接
conn, err := net.Dial("tcp", "www.jxcs.net:8000")
if err != nil {
return err
}
clearPrint := fmt.Sprintf(`{"print_no_clear":%s}`, printNo)
// 发送数据
if _, err := conn.Write([]byte(clearPrint)); err != nil {
return err
}
// 等待数据
buf := make([]byte, 1024)
n, err := conn.Read(buf)
if err != nil {
return err
}
if string(buf[:n]) != "ok" {
return errors.New("缓存清理失败")
}
defer conn.Close()
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,216 +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/smsmsg"
"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"
)
type StoreAcctManager struct {
}
var (
FixedStoreAcctManager *StoreAcctManager
)
func init() {
FixedStoreAcctManager = &StoreAcctManager{}
partner.InitStoreAcctManager(FixedStoreAcctManager)
}
func InsertStoreAcctIncome(ctx *jxcontext.Context, storeID, price, acctType int, vendorOrderID, vendorWaybillId 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,
VendorWaybillID: vendorWaybillId,
}
dao.WrapAddIDCULEntity(storeAcctIncome, userName)
if expendID != 0 {
storeAcctIncome.ExpID = expendID
}
err = dao.CreateEntity(db, storeAcctIncome)
return err
}
func InsertStoreAcctExpend(ctx *jxcontext.Context, storeID, price, acctType int, vendorOrderID, vendorWaybillId 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,
VendorWaybillID: vendorWaybillId,
}
dao.WrapAddIDCULEntity(storeAcctExpend, userName)
if expendID != 0 {
storeAcctExpend.ExpID = expendID
}
err = dao.CreateEntity(db, storeAcctExpend)
return err
}
func (s *StoreAcctManager) UpdateStoreAcctBalance(ctx *jxcontext.Context, storeID, price int, isIncome bool) (err error) {
var (
db = dao.GetDB()
)
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 {
if isIncome {
storeAcct.AccountBalance += price
} else {
storeAcct.AccountBalance -= price
}
if _, err = dao.UpdateEntityTx(txDB, storeAcct, "AccountBalance"); err != nil {
dao.Rollback(db, txDB)
return err
}
}
dao.Commit(db, txDB)
return err
}
// 门店到账(老版本,修改门店的交易记录)
func (s *StoreAcctManager) InsertStoreAcctExpendAndUpdateStoreAcctBalance(ctx *jxcontext.Context, storeID, price, acctType int, vendorOrderID, vendorWaybillID string, expendID int) (err error) {
utils.CallFuncAsync(func() {
if err = InsertStoreAcctExpend(ctx, storeID, price, acctType, vendorOrderID, vendorWaybillID, expendID); err == nil {
s.UpdateStoreAcctBalance(ctx, storeID, price, false)
}
})
return err
}
func (s *StoreAcctManager) InsertStoreAcctIncomeAndUpdateStoreAcctBalance(ctx *jxcontext.Context, storeID, price, acctType int, vendorOrderID, vendorWaybillID string, expendID int) (err error) {
utils.CallFuncAsync(func() {
if err = InsertStoreAcctIncome(ctx, storeID, price, acctType, vendorOrderID, vendorWaybillID, 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()
)
// 当前订单的支出金额(临时运费+真实运费)[小费] partner.StoreAcctTypeExpendCreateWaybillDeductFee 违约金不参与计算,本来就要扣除
expends, err = dao.GetStoreAcctExpendTotal(db, 0, []int{partner.StoreAcctTypeExpendCreateWaybillEx, partner.StoreAcctTypeExpendCreateWaybillTip, partner.StoreAcctTypeExpendCreateWaybill2ndMore, 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)
}
func (s *StoreAcctManager) GetBrandBalance(brandID int) (balance int, err error) {
return dao.GetBrandBalance(dao.GetDB(), brandID)
}
func (s *StoreAcctManager) InsertBrandBill(ctx *jxcontext.Context, brandID, price, billType, feeType int, vendorOrderID string, wayVendorOrderId string) (err error) {
utils.CallFuncAsync(func() {
var (
db = dao.GetDB()
)
if price == 0 {
return
}
brandBill := &model.BrandBill{
BrandID: brandID,
Price: price,
BillType: billType,
FeeType: feeType,
VendorOrderID: vendorOrderID,
OrderID: wayVendorOrderId,
}
dao.WrapAddIDCULEntity(brandBill, ctx.GetUserName())
//扣除后如果余额小于10元要发消息通知 ,每天通知一次
if err = dao.CreateEntity(db, brandBill); err == nil {
if mark := api.Cacher.Get("brandID" + utils.Int2Str(brandID)); mark == nil {
if balance, _ := s.GetBrandBalance(brandID); balance < model.BrandBalanceLimit {
smsmsg.NotifyBrandBalance(brandID)
}
}
}
})
return err
}

View File

@@ -1,65 +0,0 @@
package cms
import (
"encoding/json"
"git.rosy.net.cn/jx-callback/business/model/dao"
"strconv"
)
// 更新门店负责人信息
func UpdateStoreOperatorConfig() {
db := dao.GetDB()
store, err := dao.GetStoreList(db, nil, nil, []int{-1, 0, 1}, nil, nil, "")
if err != nil {
return
}
userData := make(map[string][][]interface{}, 0)
jx := make(map[string]string, 0)
jd := make(map[string]string, 0)
mt := make(map[string]string, 0)
eb := make(map[string]string, 0)
for _, v := range store {
storeDetail, err := dao.GetStoreDetail(dao.GetDB(), v.ID, 0, "")
if err != nil {
return
}
if storeDetail.MarketManPhone != "" { // 平台负责人jx
jx[storeDetail.MarketManName] = storeDetail.MarketManPhone
}
if storeDetail.OperatorPhone != "" { // 京东负责人电话
jd[storeDetail.OperatorName] = storeDetail.OperatorPhone
}
if storeDetail.OperatorPhone2 != "" { // 美团负责人电话
mt[storeDetail.OperatorName2] = storeDetail.OperatorPhone2
}
if storeDetail.OperatorPhone3 != "" { // 饿了么负责人电话
eb[storeDetail.OperatorName3] = storeDetail.OperatorPhone3
}
}
userData["jx"] = Map2Slice(jx)
userData["jd"] = Map2Slice(jd)
userData["mt"] = Map2Slice(mt)
userData["eb"] = Map2Slice(eb)
// 写入配置
byteData, err := json.Marshal(userData)
if err != nil {
return
}
if err := dao.UpdateOperatorConfig(string(byteData), "Sys", "FZR"); err != nil {
return
}
return
}
func Map2Slice(param map[string]string) [][]interface{} {
if len(param) <= 0 {
return nil
}
result := make([][]interface{}, 0, 0)
for k, v := range param {
phone, _ := strconv.Atoi(v)
result = append(result, []interface{}{k, phone})
}
return result
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,163 +0,0 @@
package cms
import (
"fmt"
"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"
"reflect"
"testing"
)
/*
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)
}
*/
func TestGetBrands(t *testing.T) {
var test bool = false
if test {
return
}
}
func TestAbs(t *testing.T) {
got := 1
if got != 1 {
t.Errorf("Abs(-1) = %d; want 1", got)
}
}
func TestGetBrands1(t *testing.T) {
type args struct {
ctx *jxcontext.Context
name string
brandID int
isManage bool
}
tests := []struct {
name string
args args
wantGetBrandsResult []*GetBrandsResult
wantErr bool
}{
// TODO: Add test cases.
}
var test bool = false
if test {
return
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gotGetBrandsResult, err := GetBrands(tt.args.ctx, tt.args.name, tt.args.brandID, tt.args.isManage)
if (err != nil) != tt.wantErr {
t.Errorf("GetBrands() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(gotGetBrandsResult, tt.wantGetBrandsResult) {
t.Errorf("GetBrands() gotGetBrandsResult = %v, want %v", gotGetBrandsResult, tt.wantGetBrandsResult)
}
})
}
}
func TestQueryPageStores2(t *testing.T) {
type args struct {
db *dao.DaoDB
pageSize int
offset int
keyword string
vendorStoreID string
brandName string
vendorID int
cityCode int
districtCode int
tel string
minShopScore float32
minRecentOrderNum int
minSkuCount int
lng1 float64
lat1 float64
lng2 float64
lat2 float64
cat string
}
dbt := dao.GetDB()
tests := []struct {
name string
args args
wantPagedInfo *model.PagedInfo
wantErr bool
}{
// TODO: Add test cases.
{
"测试1",
args{
dbt,
15,
0,
"",
"",
"", //缺
-1,
510000,
0, //缺
"",
0,
0,
0,
104.066301,
30.572961,
104.066301,
30.572961,
"",
},
nil,
true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gotPagedInfo, err := QueryPageStores2(tt.args.db, tt.args.pageSize, tt.args.offset, tt.args.keyword, tt.args.vendorStoreID, tt.args.brandName, tt.args.vendorID, tt.args.cityCode, tt.args.districtCode, tt.args.tel, tt.args.minShopScore, tt.args.minRecentOrderNum, tt.args.minSkuCount, tt.args.lng1, tt.args.lat1, tt.args.lng2, tt.args.lat2, tt.args.cat)
if (err != nil) != tt.wantErr {
t.Errorf("QueryPageStores2() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(gotPagedInfo, tt.wantPagedInfo) {
t.Errorf("QueryPageStores2() gotPagedInfo = %v, want %v", gotPagedInfo, tt.wantPagedInfo)
}
})
}
}
func TestUpdate(t *testing.T) {
UpdateStoreOperatorConfig()
}
func TestUpdateStorePoiStatus(t *testing.T) {
var ctx *jxcontext.Context
err := UpdateStorePoiStatus(ctx)
fmt.Println(err)
}

View File

@@ -1,135 +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/netprinter"
"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"
)
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) {
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,
}
}
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,
}
}
} else if storeDetail.Status <= storeStatus {
if storeDetail.VendorStatus != storeStatus {
storeMapKV = map[string]interface{}{
"Status": storeStatus,
}
}
}
}
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 {
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 {
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)
}
// 打印门第离线消息
if storeStatus < model.StoreStatusOpened && storeDetail.PrinterVendorID == model.VendorIDJxprint {
netprinter.PrintStoreStatus(jxcontext.AdminCtx, storeDetail, vendorID, 0)
}
}
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
}
}
return err
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,742 +0,0 @@
package cms
import (
"fmt"
"git.rosy.net.cn/jx-callback/business/partner/purchase/tiktok_store"
"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 {
if catVendorInfo.VendorID != model.VendorIDDD {
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) {
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) {
db := dao.GetDB()
skuList, err := dao.GetSkusWithVendor(db, vendorIDs, appOrgCodes, nameIDs, skuIDs, true)
cc := 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
}
//todo 暂时注释
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 {
if skuVendorInfo.VendorID != model.VendorIDDD {
err = fmt.Errorf("平台:%d不合法", skuVendorInfo.VendorID)
}
}
if len(failedList) > 0 {
task.AddFailedList(failedList)
} else {
dao.SetStoreSkuSyncStatus(dao.GetDB(), model.VendorIDJD, []int{skuVendorInfo.StoreID}, []int{skuVendorInfo.SkuID}, model.ThingTypeSyncSuccess)
}
if err = OnThingSync(ctx, dao.GetDB(), SkuVendor2ThingMap(skuVendorInfo), err); err == nil {
retVal = []int{1}
}
return retVal, err
}
if err == nil && len(skuList) > 0 {
task := tasksch.NewParallelTask(
fmt.Sprintf("同步商品:%v,%v", nameIDs, skuIDs),
tasksch.NewParallelConfig().SetIsContinueWhenError(true), ctx, cc, 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) {
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) {
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 OnCreateThing2Tiktok(ctx *jxcontext.Context, db *dao.DaoDB, appOrgCode string, vendorThingList []*tiktok_store.TiktokIdAndLocalSkuId, thingType, syncFlag int8, vendorFlag bool) (err error) {
if thingType == model.ThingTypeSkuName {
return nil
}
errList := errlist.New()
for _, v := range vendorThingList {
thingMap := &model.ThingMap{
ThingID: v.LocalSkuId,
ThingType: thingType,
VendorID: model.VendorIDDD,
VendorOrgCode: appOrgCode,
VendorThingID: v.MainId,
Remark: v.SkuAttrId,
}
if thingType == model.ThingTypeCategory && !vendorFlag {
syncFlag = 0
}
thingMap.SyncStatus = syncFlag
dao.WrapAddIDCULDEntity(thingMap, ctx.GetUserName())
if err2 := dao.CreateEntity(db, thingMap); err2 != nil {
if err2 := getThingMap(db, thingMap); err2 == nil {
thingMap.SyncStatus = 2
thingMap.LastOperator = ctx.GetUserName()
_, err2 = dao.UpdateEntity(db, thingMap)
errList.AddErr(err2)
}
}
}
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 DeleteThingByData(ctx *jxcontext.Context, db *dao.DaoDB, appOrgCode string, startTime time.Time, endTime time.Time) error {
sql := ` DELETE FROM thing_map WHERE vendor_org_code = ? AND created_at >= ? AND created_at < ? `
_, err := dao.ExecuteSQL(db, sql, []interface{}{appOrgCode, startTime, endTime})
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) {
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) {
err = OnCreateThing(ctx, db, vendorOrgCodes, int64(v.SkuID), model.ThingTypeSku, getSyncFlag(v.SkuID), false)
}
} else if isForceUpdate {
err = OnUpdateThing(ctx, db, vendorOrgCodes, int64(v.SkuID), model.ThingTypeSku)
}
}
} else {
//表示根据某门店的门店商品同步京东商品库中这个门店关注并可售了这个商品插到thingmap里同步标志是待创建SyncFlagNewMask才会创建
//若该门店没关注可售那插到thingmap里的话就该同步标志为0就不会创建
//getSyncFlag
err = 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) {
err = 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)
}
worker := 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
}
task := tasksch.NewParallelTask("FullSyncStoreSkuNew", tasksch.NewParallelConfig().SetParallelCount(1).SetIsContinueWhenError(false), ctx, worker, []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,328 +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)
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("更新门店商品价格2", 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)
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,207 +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;
// `
// 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())
// 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 {
// 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

@@ -1,121 +0,0 @@
package cms
import (
"fmt"
"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/partner"
"git.rosy.net.cn/jx-callback/business/partner/purchase/mtwm"
)
// GetMtSkuDetailInfo 获取美团商品信息,暂时只支持美团
func GetMtSkuDetailInfo(ctx *jxcontext.Context, vendorOrderID string, vendorSkuName string) (outSkuNameExt *model.SkuNameExt, err error) {
orderDetail, err := partner.CurOrderManager.LoadOrder(vendorOrderID, model.VendorIDMTWM)
if err != nil {
return nil, err
}
// 获取订单详情
mtApi := mtwm.GetAPI(orderDetail.VendorOrgCode, orderDetail.JxStoreID, orderDetail.VendorStoreID)
mtOrderDetail, err := mtApi.OrderGetOrderDetail(utils.Str2Int64(vendorOrderID), false)
if err != nil {
return nil, err
}
var detail []map[string]interface{}
if err = utils.UnmarshalUseNumber([]byte(mtOrderDetail["detail"].(string)), &detail); err != nil {
return nil, err
}
mtCode := ""
for _, product := range detail {
if product["food_name"].(string) == vendorSkuName {
if product["app_food_code"].(string) == "" {
return nil, fmt.Errorf("[%s] 未获取到商品的美团code,无法创建商品", vendorSkuName)
}
mtCode = product["app_food_code"].(string)
break
}
}
if mtCode == "" {
return nil, fmt.Errorf("[%s] 未获取到商品的美团code,无法创建商品", vendorSkuName)
}
// 获取美团商品详情
mtSkuDetail, err := mtApi.RetailGet(orderDetail.VendorStoreID, mtCode)
if err != nil {
return nil, err
}
skuName := &model.SkuNameExt{
SkuName: model.SkuName{
Prefix: "",
Name: mtSkuDetail.Name,
Upc: utils.String2Pointer(mtSkuDetail.UpcCode),
Status: 1,
CategoryID: 291, // ?
IsGlobal: 1,
Unit: mtSkuDetail.Unit,
Price: utils.Float64TwoInt(mtSkuDetail.Price * float64(100)),
DescImg: mtSkuDetail.PictureContents,
JdsStockSwitch: 1,
PreparationTime: 0,
MtAttribute: "",
// 京西创建是传入的属性
// [{"attr_id":"1200000088","attr_name":"品牌","valueList":[{"value":"其他"}]},{"attr_id":"1200000135","attr_name":"包装方式","valueList":[{"value_id":"1300000231","value":"袋装"}]}]
// 美团获取的属性,不太好转换,暂时不弄
// [{"attrId":1200000202,"attrName":"品种","setAttrId":true,"setAttrName":true,"setValueList":true,"valueList":[{"setValue":true,"setValueId":true,"value":"二荆条","valueId":1300015565}],"valueListIterator":[{"$ref":"$[0].valueList[0]"}],"valueListSize":1},{"attrId":1200000135,"attrName":"包装方式","setAttrId":true,"setAttrName":true,"setValueList":true,"valueList":[{"setValue":true,"setValueId":true,"value":"散装","valueId":1300000232}],"valueListIterator":[{"$ref":"$[1].valueList[0]"}],"valueListSize":1}]
},
Skus: nil,
MtwmCategoryID: utils.Int2Str(mtSkuDetail.TagID),
}
skus := make([]*model.SkuWithVendor, 0, 0)
for _, mtSks := range mtSkuDetail.SkuList {
sku := &model.SkuWithVendor{
Sku: &model.Sku{
MinOrderCount: utils.Str2Int(mtSks.MinOrderCount),
LadderBoxNum: utils.Str2Int(mtSks.LadderBoxNum),
LadderBoxPrice: utils.Float64TwoInt(utils.Str2Float64(mtSks.Price) * float64(100)),
SpecQuality: float32(utils.Str2Float64(mtSks.Weight)),
Weight: utils.Str2Int(mtSks.Weight),
SpecUnit: mtSks.Unit,
Status: 1,
Comment: "",
EclpID: "",
},
}
skus = append(skus, sku)
}
skuName.Skus = skus
mTImg2Jx(skuName, mtSkuDetail.PictureList)
return AddSkuName(ctx, skuName, ctx.GetUserName())
}
func mTImg2Jx(sku *model.SkuNameExt, pictureList []string) {
switch len(pictureList) {
case 0:
return
case 1:
sku.Img = pictureList[0]
case 2:
sku.Img = pictureList[0]
sku.Img2 = pictureList[1]
case 3:
sku.Img = pictureList[0]
sku.Img2 = pictureList[1]
sku.Img3 = pictureList[2]
case 4:
sku.Img = pictureList[0]
sku.Img2 = pictureList[1]
sku.Img3 = pictureList[2]
sku.Img4 = pictureList[3]
case 5:
sku.Img = pictureList[0]
sku.Img2 = pictureList[1]
sku.Img3 = pictureList[2]
sku.Img4 = pictureList[3]
sku.Img5 = pictureList[4]
}
}

View File

@@ -2,14 +2,14 @@ package common
import ( import (
"fmt" "fmt"
"git.rosy.net.cn/baseapi/platformapi/tencent_map"
"sort" "sort"
"git.rosy.net.cn/baseapi/platformapi/autonavi"
"git.rosy.net.cn/baseapi/utils" "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"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext" "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"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/globals/api" "git.rosy.net.cn/jx-callback/globals/api"
) )
@@ -40,7 +40,6 @@ type Store4User struct {
Distance int `json:"distance"` Distance int `json:"distance"`
WalkDistance int `json:"walkDistance"` WalkDistance int `json:"walkDistance"`
DeliverySelf int `json:"deliverySelf"`
} }
type Store4UserList []*Store4User type Store4UserList []*Store4User
@@ -68,7 +67,7 @@ func GetNearSupplyGoodsStoreByStoreID(ctx *jxcontext.Context, storeID int) (stor
stores []*model.Store stores []*model.Store
db = dao.GetDB() db = dao.GetDB()
) )
store2, _ := dao.GetStoreDetail(db, storeID, model.VendorIDJX, "") store2, _ := dao.GetStoreDetail(db, storeID, model.VendorIDJX)
if store2 == nil { if store2 == nil {
return nil, fmt.Errorf("该门店未绑定京西平台storeID: %v", storeID) return nil, fmt.Errorf("该门店未绑定京西平台storeID: %v", storeID)
} }
@@ -91,7 +90,7 @@ func GetNearSupplyGoodsStoreByStoreID(ctx *jxcontext.Context, storeID int) (stor
utils.DefaultTimeValue, utils.DefaultTimeValue, utils.DefaultTimeValue, utils.DefaultTimeValue,
model.VendorIDJX, model.YES, model.StoreStatusOpened, model.VendorIDJX, model.YES, model.StoreStatusOpened,
} }
err = dao.GetRows(db, &stores, sql, sqlParams...) err = dao.GetRows(db, &stores, sql, sqlParams)
if len(stores) > 0 { if len(stores) > 0 {
realDistance := float64(0) realDistance := float64(0)
for _, v := range stores { for _, v := range stores {
@@ -110,7 +109,7 @@ func GetNearSupplyGoodsStoreByStoreID(ctx *jxcontext.Context, storeID int) (stor
return store, err 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 ( const (
maxStoreCount4User = 5 maxStoreCount4User = 5
) )
@@ -124,34 +123,29 @@ func GetStoreListByLocation(ctx *jxcontext.Context, lng, lat float64, maxRadius
_, lat2 := jxutils.ConvertDistanceToLogLat(lng, lat, float64(maxRadius), 0) _, lat2 := jxutils.ConvertDistanceToLogLat(lng, lat, float64(maxRadius), 0)
lng1 := lng - (lng2 - lng) lng1 := lng - (lng2 - lng)
lat1 := lat - (lat2 - lat) lat1 := lat - (lat2 - lat)
// globals.SugarLogger.Debugf("%f,%f,%f,%f\n", lng1, lng2, lat1, lat2)
if !isJds { if !isJds {
sql = ` sql = `
SELECT t1.*, SELECT t1.*,
city.name city_name,sm.delivery_self city.name city_name
FROM store t1 FROM store t1
JOIN place city ON city.code = t1.city_code JOIN place city ON city.code = t1.city_code
JOIN store_map sm ON sm.store_id = t1.id AND sm.vendor_id = ? AND sm.deleted_at = ? AND sm.status <> ? JOIN store_map sm ON sm.store_id = t1.id AND sm.vendor_id = ? AND sm.deleted_at = ? AND sm.status <> ?
WHERE t1.deleted_at = ? AND t1.status <> ? AND t1.lng > ? AND t1.lng < ? AND t1.lat > ? AND t1.lat < ? WHERE t1.deleted_at = ? AND t1.status <> ? AND t1.lng > ? AND t1.lng < ? AND t1.lat > ? AND t1.lat < ?
AND sm.is_order <> ? AND sm.is_order <> ?
AND t1.id <> ? AND t1.id <> ?
ORDER BY t1.id
` `
sqlParams = append(sqlParams, sqlParams = []interface{}{
model.VendorIDJX, utils.DefaultTimeValue, model.StoreStatusDisabled, model.VendorIDJX, utils.DefaultTimeValue, model.StoreStatusDisabled,
utils.DefaultTimeValue, model.StoreStatusDisabled, jxutils.StandardCoordinate2Int(lng1), jxutils.StandardCoordinate2Int(lng2), jxutils.StandardCoordinate2Int(lat1), jxutils.StandardCoordinate2Int(lat2), utils.DefaultTimeValue, model.StoreStatusDisabled, jxutils.StandardCoordinate2Int(lng1), jxutils.StandardCoordinate2Int(lng2), jxutils.StandardCoordinate2Int(lat1), jxutils.StandardCoordinate2Int(lat2),
model.YES, model.YES,
model.MatterStoreID, model.MatterStoreID,
)
if len(brandID) != 0 {
sql += " AND t1.brand_id IN (" + dao.GenQuestionMarks(len(brandID)) + ")"
sqlParams = append(sqlParams, brandID)
} }
sql += `
ORDER BY t1.id
`
} else { } else {
sql = ` sql = `
SELECT t1.*, SELECT t1.*,
city.name city_name,sm.delivery_self city.name city_name
FROM store t1 FROM store t1
JOIN place city ON city.code = t1.city_code JOIN place city ON city.code = t1.city_code
JOIN store_map sm ON sm.store_id = t1.id AND sm.vendor_id = ? AND sm.deleted_at = ? AND sm.status = ? JOIN store_map sm ON sm.store_id = t1.id AND sm.vendor_id = ? AND sm.deleted_at = ? AND sm.status = ?
@@ -185,12 +179,12 @@ func GetStoreListByLocation(ctx *jxcontext.Context, lng, lat float64, maxRadius
city.name city_name city.name city_name
FROM store t1 FROM store t1
JOIN place city ON city.code = t1.city_code 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{}{ sqlParams2 := []interface{}{
// model.VendorIDJX, utils.DefaultTimeValue, model.StoreStatusDisabled, // model.VendorIDJX, utils.DefaultTimeValue, model.StoreStatusDisabled,
utils.DefaultTimeValue, utils.DefaultTimeValue,
// model.StoreStatusDisabled, model.StoreStatusDisabled,
// jxutils.StandardCoordinate2Int(0), // jxutils.StandardCoordinate2Int(0),
// jxutils.StandardCoordinate2Int(10000), // jxutils.StandardCoordinate2Int(10000),
// jxutils.StandardCoordinate2Int(0), // jxutils.StandardCoordinate2Int(0),
@@ -206,14 +200,14 @@ func GetStoreListByLocation(ctx *jxcontext.Context, lng, lat float64, maxRadius
// 如果要求以步行距离来算 // 如果要求以步行距离来算
if needWalkDistance { if needWalkDistance {
var coordList []*tencent_map.Coordinate var coordList []*autonavi.Coordinate
for _, v := range storeList2 { for _, v := range storeList2 {
coordList = append(coordList, &tencent_map.Coordinate{ coordList = append(coordList, &autonavi.Coordinate{
Lng: v.FloatLng, Lng: v.FloatLng,
Lat: v.FloatLat, Lat: v.FloatLat,
}) })
} }
if distanceList, err2 := api.TencentMapAPI.BatchWalkingDistance(lng, lat, coordList); err2 == nil { if distanceList, err2 := api.AutonaviAPI.BatchWalkingDistance(lng, lat, coordList); err2 == nil {
for k, v := range storeList2 { for k, v := range storeList2 {
v.WalkDistance = int(distanceList[k]) v.WalkDistance = int(distanceList[k])
} }
@@ -230,69 +224,3 @@ func GetStoreListByLocation(ctx *jxcontext.Context, lng, lat float64, maxRadius
} }
return storeList, err 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 {
vendorOrgCode.ID = list[0].ID
_, err = dao.UpdateEntity(db, vendorOrgCode, "token", "updated_at", "app_key", "app_secret", "comment", "vendor_org_code")
return err
}
var userName string
if ctx != nil {
userName = ctx.GetUserName()
} else {
userName = "system"
}
dao.WrapAddIDCULDEntity(vendorOrgCode, userName)
dao.CreateEntity(db, vendorOrgCode)
return err
}

View File

@@ -1,34 +1,29 @@
package event package event
import ( import (
"errors"
"fmt"
"regexp" "regexp"
"strings" "strings"
"time" "time"
"git.rosy.net.cn/baseapi/utils" "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"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext" "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"
"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 ( var (
NoUseEventMap = map[string]string{ NoUseEventMap = map[string]string{
"CreateQrOrBarCode": "CreateQrOrBarCode", "CreateQrOrBarCode": "CreateQrOrBarCode",
"StatisticsReportForOrders": "StatisticsReportForOrders", "StatisticsReportForOrders": "StatisticsReportForOrders",
"UpdateUser": "UpdateUser",
} }
regexpToken = regexp.MustCompile(`,"token":".*"`) regexpToken = regexp.MustCompile(`,"token":".*"`)
) )
type CheckCookie struct { const (
VendorID int `json:"vendorID"` sysMessageTitle = ""
VendorOrgCode string `json:"vendorOrgCode"` )
Status string `json:"status"`
}
func AddOperateEvent(ctx *jxcontext.Context, accessUUID, jsonData string, errCode, errMsg string, useTime int, apiFunctionSpec string) (err error) { func AddOperateEvent(ctx *jxcontext.Context, accessUUID, jsonData string, errCode, errMsg string, useTime int, apiFunctionSpec string) (err error) {
var ( var (
@@ -48,7 +43,7 @@ func AddOperateEvent(ctx *jxcontext.Context, accessUUID, jsonData string, errCod
} }
if apiFunction != "" { if apiFunction != "" {
if apiFunction[0:3] == "Get" || NoUseEventMap[apiFunction] != "" { if apiFunction[0:3] == "Get" || NoUseEventMap[apiFunction] != "" {
return errors.New("未知错误") return err
} }
} }
if accessUUID != "" { if accessUUID != "" {
@@ -68,7 +63,7 @@ func AddOperateEvent(ctx *jxcontext.Context, accessUUID, jsonData string, errCod
ErrMsg: errMsg, ErrMsg: errMsg,
UseTime: useTime, UseTime: useTime,
} }
txDB, err := dao.Begin(db) txDB, _ := dao.Begin(db)
defer func() { defer func() {
if r := recover(); r != nil { if r := recover(); r != nil {
dao.Rollback(db, txDB) dao.Rollback(db, txDB)
@@ -134,67 +129,3 @@ func GetOperateEvents(ctx *jxcontext.Context, name string, apiFunctions []string
} }
return pageInfo, err 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无效了", v)
flag = true
}
}
case model.VendorIDMTWM:
_, err := api.MtwmAPI.PackagePriceGet(mtStoreID)
if err != nil {
if strings.Contains(err.Error(), mtErr) {
errMsg += fmt.Sprintf(" 美团账号:[%v]的Cookie无效了", v)
flag = true
}
}
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无效了", v)
flag = true
}
}
case model.VendorIDJDShop:
_, err := api.JdShopAPI.OrderDetail("124350112427")
if err != nil {
if strings.Contains(err.Error(), "登录") {
errMsg += fmt.Sprintf("京东商城:[%v]的Cookie无效了", v)
flag = true
}
}
}
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,122 +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) {
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))
// 果园和菜市账号冲突,果园门店ID调整变大
//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)
storeDetail, _ := dao.GetStoreDetail(db, storeID, 0, "")
if storeDetail != nil && storeDetail.PushBill == 1 {
return retVal, err
}
file, err := fileHeader.Open()
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/tencent_map"
"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 *tencent_map.District, placeList []*tencent_map.District) (err error) {
for _, v := range placeList {
if v.Level <= tencent_map.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) {
// 这个地方是更新全国的place表,因为两个不兼容且上传时间不会发送改变,暂时不做返回
placeList, err2 := api.TencentMapAPI.GetDistricts(tencent_map.DistrictLevelDistrict, "", 0)
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)
}

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