Compare commits

1991 Commits

Author SHA1 Message Date
邹宗楠
9d19b162cc 1 2026-05-12 17:54:40 +08:00
邹宗楠
de1c4d00de 1 2026-05-12 17:51:23 +08:00
邹宗楠
eaa27cbaa7 1 2026-05-12 17:28:46 +08:00
邹宗楠
f2ce2db029 1 2026-05-12 17:00:36 +08:00
邹宗楠
29634ad17f : 2026-05-12 16:38:52 +08:00
邹宗楠
3cb53546f8 1 2026-05-12 16:30:39 +08:00
邹宗楠
35c8468789 1 2026-05-11 10:03:21 +08:00
邹宗楠
040f0b7d8d 1 2026-05-09 17:25:32 +08:00
邹宗楠
d339ebb47b 1 2026-05-09 16:02:04 +08:00
邹宗楠
637a878808 1 2026-02-03 17:52:04 +08:00
邹宗楠
999c3d7ebe 1 2026-01-30 10:00:57 +08:00
邹宗楠
8a8f545656 1 2025-12-24 17:03:16 +08:00
邹宗楠
ce6b120f23 1 2025-12-24 16:54:27 +08:00
邹宗楠
3651bf0e1d 1 2025-12-24 16:41:46 +08:00
邹宗楠
2e261aab4b 1 2025-12-24 16:18:23 +08:00
邹宗楠
5d76781965 1 2025-12-24 16:13:32 +08:00
邹宗楠
bf44d2b733 1 2025-12-24 15:55:55 +08:00
邹宗楠
c8e1500892 1 2025-12-24 15:48:12 +08:00
邹宗楠
4e1c338bec 1 2025-12-24 15:43:34 +08:00
邹宗楠
e3fdcd179a 添加count 2025-12-24 14:57:46 +08:00
邹宗楠
b4c5df3616 1 2025-12-23 14:43:26 +08:00
邹宗楠
505e347939 打印机添加查询接口 2025-12-23 14:30:54 +08:00
邹宗楠
1380b581bc 域名修改回来了 2025-11-21 09:13:51 +08:00
邹宗楠
f99ef659e0 1 2025-11-20 14:36:23 +08:00
邹宗楠
829c546a52 修改git.rosy.net.cn->gitrosy.jxc4.com 主要是因为改变了git服务器 2025-11-20 14:28:53 +08:00
邹宗楠
f520b3e2e0 1 2025-11-20 11:28:12 +08:00
邹宗楠
f74945fab9 修改导包错误 2025-11-18 09:36:15 +08:00
邹宗楠
88f6e70fc8 rsm提交测试 2025-11-17 18:16:08 +08:00
邹宗楠
200cefcfb3 1 2025-10-21 09:36:07 +08:00
邹宗楠
d5bea30024 1 2025-09-18 10:23:18 +08:00
邹宗楠
a9e521eaf2 1 2025-09-02 09:40:00 +08:00
邹宗楠
2055c4bb3b 1 2025-05-30 09:52:43 +08:00
邹宗楠
e0b26ea5b8 1 2025-03-21 10:11:00 +08:00
邹宗楠
1f779012a2 1 2025-03-03 11:21:10 +08:00
邹宗楠
2df383a788 1 2025-03-03 10:18:32 +08:00
邹宗楠
1f40c96cfe 1 2025-03-03 10:09:47 +08:00
邹宗楠
2b9135903b 1 2025-02-13 09:17:38 +08:00
邹宗楠
7660eeca92 1 2025-02-10 09:16:40 +08:00
邹宗楠
a6bee06006 1 2025-02-08 14:12:35 +08:00
邹宗楠
3cb005011c 1 2025-02-08 09:46:48 +08:00
邹宗楠
93aaf0f58a 1 2025-02-07 09:40:30 +08:00
邹宗楠
ab090a9fee 1 2025-02-07 09:36:46 +08:00
邹宗楠
d70f73b541 1 2025-02-06 14:23:34 +08:00
邹宗楠
810eefd386 1 2025-02-06 13:36:53 +08:00
邹宗楠
3251816066 1 2024-11-04 10:53:16 +08:00
邹宗楠
90ff64452a 1 2024-08-27 14:58:44 +08:00
邹宗楠
544e64dc29 1 2024-08-27 14:09:21 +08:00
邹宗楠
8f590d0239 1 2024-07-29 09:00:09 +08:00
邹宗楠
6cc389cd0f 1 2024-07-25 09:39:51 +08:00
邹宗楠
4ae054de73 1 2024-07-23 18:00:38 +08:00
邹宗楠
53abbb82d6 1 2024-07-22 16:17:30 +08:00
邹宗楠
7eb06a41ae 1 2024-07-22 15:08:52 +08:00
邹宗楠
1186935d7d 1 2024-07-22 15:00:03 +08:00
邹宗楠
f3b7e22f23 1 2024-07-19 13:30:18 +08:00
邹宗楠
8613ac0861 1 2024-07-19 09:26:21 +08:00
邹宗楠
fa87217b90 1 2024-07-19 09:18:50 +08:00
邹宗楠
2a0d749ef5 1 2024-07-19 09:11:22 +08:00
邹宗楠
2151ea27a9 1 2024-07-19 09:06:17 +08:00
邹宗楠
cffad3c660 1 2024-07-15 15:41:05 +08:00
邹宗楠
e7e7729715 1 2024-07-15 15:30:48 +08:00
邹宗楠
de98b0f88a 1 2024-07-15 15:24:52 +08:00
邹宗楠
1565ed626b 1 2024-07-15 15:20:22 +08:00
邹宗楠
df9e1ae124 1 2024-07-15 15:13:20 +08:00
邹宗楠
42360e124f 1 2024-07-15 14:01:38 +08:00
邹宗楠
3bbd241264 1 2024-07-10 13:31:27 +08:00
邹宗楠
10b7aa3bc7 1 2024-07-10 12:47:56 +08:00
邹宗楠
2e3b7d31ca 1 2024-07-10 12:43:03 +08:00
邹宗楠
a077b5b8d2 1 2024-07-10 12:37:31 +08:00
邹宗楠
c17fe6022f 1 2024-07-10 11:52:57 +08:00
邹宗楠
27c870ff4d 1 2024-07-10 11:43:44 +08:00
邹宗楠
28aea06a4c 1 2024-07-10 11:26:11 +08:00
邹宗楠
5530ab4d01 1 2024-07-10 11:17:00 +08:00
邹宗楠
e3fedfdcd2 1 2024-07-10 10:59:43 +08:00
邹宗楠
2de089f09a 1 2024-07-10 10:42:29 +08:00
邹宗楠
eee469ca48 1 2024-07-10 10:35:10 +08:00
邹宗楠
0a9699d764 1 2024-07-10 10:23:31 +08:00
邹宗楠
6e4d330d35 1 2024-07-10 10:13:33 +08:00
邹宗楠
113212b1dd 1 2024-07-10 09:45:29 +08:00
邹宗楠
680c2030ec 1 2024-04-08 18:02:43 +08:00
邹宗楠
e0c1a93d66 1 2024-02-28 10:10:06 +08:00
邹宗楠
e17e9db240 1 2024-01-25 10:54:18 +08:00
邹宗楠
a3b8183585 1 2024-01-17 18:04:34 +08:00
邹宗楠
3f5ad2d1ff 1 2024-01-17 15:56:36 +08:00
邹宗楠
774e7c2579 1 2024-01-17 15:52:46 +08:00
邹宗楠
c19efa359e 1 2024-01-17 15:50:17 +08:00
邹宗楠
1439e701ac 1 2024-01-15 10:58:56 +08:00
邹宗楠
3ff6d7bd8b 1 2024-01-10 16:36:30 +08:00
邹宗楠
ca1f95297c 1 2024-01-10 11:01:03 +08:00
邹宗楠
a83617e477 1 2024-01-10 10:45:32 +08:00
邹宗楠
5cd7764c6e 1 2024-01-10 09:28:12 +08:00
邹宗楠
31ca7605c8 1 2024-01-08 17:44:00 +08:00
邹宗楠
d19d4573b9 1 2024-01-08 17:13:36 +08:00
邹宗楠
0c52053739 1 2024-01-08 16:47:32 +08:00
邹宗楠
ca6df068a6 1 2024-01-08 16:43:53 +08:00
邹宗楠
46868e633c 1 2024-01-08 14:51:42 +08:00
邹宗楠
54a6939d0b 1 2024-01-08 11:39:27 +08:00
邹宗楠
601e146ba9 1 2024-01-08 11:32:45 +08:00
邹宗楠
f95d55a8d2 1 2024-01-08 10:35:33 +08:00
邹宗楠
b2b52b336c 1 2024-01-08 10:17:43 +08:00
邹宗楠
6a04c366bf 1 2024-01-08 10:11:22 +08:00
邹宗楠
2e904f3719 1 2024-01-08 10:04:28 +08:00
邹宗楠
06b225aff3 1 2024-01-08 10:00:34 +08:00
邹宗楠
5278ba7739 1 2024-01-08 09:50:46 +08:00
邹宗楠
3db704f235 1 2024-01-08 09:45:49 +08:00
邹宗楠
1ed5e7e259 1 2024-01-08 09:36:51 +08:00
邹宗楠
5ce817e327 1 2024-01-08 09:34:35 +08:00
邹宗楠
be829b7399 1 2024-01-08 09:23:28 +08:00
邹宗楠
c8b9eb7eff 1 2024-01-08 09:14:58 +08:00
邹宗楠
a7232b6d3b 1 2024-01-08 09:09:37 +08:00
邹宗楠
f41547f7b7 1 2024-01-08 09:07:04 +08:00
邹宗楠
09806185d8 1 2024-01-05 16:53:18 +08:00
邹宗楠
10d7ed2a2c 1 2024-01-05 16:51:31 +08:00
邹宗楠
27da0e4c57 1 2024-01-05 16:24:27 +08:00
邹宗楠
69ad23a7dd 修改api 2024-01-05 16:19:35 +08:00
邹宗楠
fdc2736012 1 2024-01-05 16:10:04 +08:00
邹宗楠
ff968cbdcf 1 2024-01-05 15:10:59 +08:00
邹宗楠
20f11b0c4e 1 2024-01-05 10:27:20 +08:00
邹宗楠
1469168f90 1 2023-12-20 08:58:50 +08:00
邹宗楠
3fb979009b 1 2023-12-19 17:31:07 +08:00
邹宗楠
1c3eadf096 1 2023-12-19 17:05:32 +08:00
邹宗楠
a29a10152a 1 2023-12-19 13:45:24 +08:00
邹宗楠
0f781849b4 1 2023-12-19 09:29:50 +08:00
邹宗楠
3c4ffc3599 1 2023-08-31 10:54:02 +08:00
邹宗楠
7c2a2bbea1 1 2023-08-31 10:49:57 +08:00
邹宗楠
17ff0169b8 1 2023-08-30 16:23:34 +08:00
邹宗楠
82eba6b49c 暫存 2023-08-30 11:58:09 +08:00
邹宗楠
1c76565c02 1 2023-07-24 11:20:24 +08:00
邹宗楠
764f22b32c 1 2023-06-07 13:41:22 +08:00
邹宗楠
08f8c08c4d 1 2023-06-06 09:04:21 +08:00
邹宗楠
a067a9ad92 1 2023-06-05 15:37:19 +08:00
邹宗楠
ad54650303 1 2023-06-05 15:36:22 +08:00
邹宗楠
765517013c 1 2023-06-05 15:34:44 +08:00
邹宗楠
fec4011989 1 2023-06-05 15:04:38 +08:00
邹宗楠
92ec3f3b1f 1 2023-06-05 15:02:09 +08:00
邹宗楠
57ac67e874 1 2023-06-05 14:49:40 +08:00
邹宗楠
0efcc40b09 1 2023-06-05 14:47:37 +08:00
邹宗楠
71234f6b48 修改链接数据读取方式 2023-06-05 14:38:15 +08:00
邹宗楠
078ca7e9b2 1' 2023-06-01 17:11:12 +08:00
邹宗楠
44e0edc404 1 2023-06-01 16:37:59 +08:00
邹宗楠
f27a3ee5e2 1 2023-06-01 15:54:49 +08:00
邹宗楠
2be3fb329e 1 2023-06-01 12:49:50 +08:00
邹宗楠
944166496e 1 2023-06-01 10:11:04 +08:00
邹宗楠
5f1bf89743 1 2023-06-01 09:29:43 +08:00
邹宗楠
5f3f974d3e 1 2023-05-31 19:47:31 +08:00
邹宗楠
ff7ae26ce5 1 2023-05-31 19:45:27 +08:00
邹宗楠
a376e4b90d 1 2023-05-31 17:04:59 +08:00
邹宗楠
fc1cc16de6 1 2023-05-31 15:46:07 +08:00
邹宗楠
ca27491d14 1 2023-05-31 15:43:18 +08:00
邹宗楠
ed419d5a4d 1 2023-05-30 09:24:04 +08:00
邹宗楠
9e2b93b6cd 1 2023-05-30 09:17:38 +08:00
邹宗楠
f9913ead46 1 2023-05-30 09:13:00 +08:00
邹宗楠
70dfb81139 1 2023-05-30 09:10:47 +08:00
邹宗楠
4b9c783b9a 1 2023-05-30 09:06:09 +08:00
邹宗楠
d626fcf12d 1 2023-05-29 16:49:57 +08:00
邹宗楠
958ab4686d 1 2023-05-29 16:46:26 +08:00
邹宗楠
9fee44b6fd 1 2023-05-29 15:50:38 +08:00
邹宗楠
56b0774eb5 1 2023-05-29 15:26:41 +08:00
邹宗楠
f91749c17f 1 2023-05-29 15:24:18 +08:00
邹宗楠
98a52a7559 1 2023-05-29 15:21:20 +08:00
邹宗楠
49334fdb4c 1 2023-05-29 14:15:09 +08:00
邹宗楠
b081865c17 1 2023-04-14 18:32:25 +08:00
邹宗楠
7863aa3f56 1 2023-03-23 15:38:53 +08:00
邹宗楠
9a05bc9145 1 2023-03-22 14:58:11 +08:00
邹宗楠
6d1c31066e 1 2023-03-21 15:23:21 +08:00
邹宗楠
59e117ad7c 1 2023-03-17 10:07:07 +08:00
邹宗楠
9ebe42830f 1 2023-03-16 15:54:18 +08:00
邹宗楠
be1d4be19e 1 2023-03-16 15:39:06 +08:00
邹宗楠
c0c154e895 1 2023-03-16 15:36:24 +08:00
邹宗楠
a39558cac2 1 2023-03-16 15:34:34 +08:00
邹宗楠
84c1e6806c 1 2023-03-16 15:31:46 +08:00
邹宗楠
65a8cb72cb 1 2023-03-16 15:27:57 +08:00
邹宗楠
a0c528d299 1 2023-03-16 15:24:21 +08:00
邹宗楠
b4bac4ea17 1 2023-03-16 14:34:18 +08:00
邹宗楠
b42b66bc8f 1 2023-03-16 11:08:05 +08:00
邹宗楠
4f934b5bf0 1 2023-03-16 11:00:29 +08:00
邹宗楠
be3dbf920d 1 2023-03-16 10:31:34 +08:00
邹宗楠
49773cf84e 1 2023-03-16 10:24:57 +08:00
邹宗楠
6f4f89b0fb 1 2023-03-13 09:11:39 +08:00
邹宗楠
8dca771cca 1 2023-03-06 11:36:18 +08:00
邹宗楠
348f66c247 1 2023-03-06 11:26:32 +08:00
邹宗楠
065a037234 1 2023-03-06 11:22:56 +08:00
邹宗楠
82b3bad6a0 1 2023-03-06 11:08:58 +08:00
邹宗楠
8ffd05496a 1 2023-02-24 16:27:19 +08:00
邹宗楠
e15f83f913 1 2023-02-09 11:35:17 +08:00
邹宗楠
aedff383c6 1 2023-02-03 14:29:48 +08:00
邹宗楠
942f9f93b4 1 2023-01-27 14:29:33 +08:00
邹宗楠
d78f392625 1 2023-01-10 11:15:37 +08:00
邹宗楠
4b41b34833 1 2023-01-10 10:37:28 +08:00
邹宗楠
1bb18dfc46 1 2023-01-03 14:45:31 +08:00
邹宗楠
24b4c31037 1 2022-12-30 11:15:20 +08:00
邹宗楠
47bac8d2d9 1 2022-12-30 10:22:22 +08:00
邹宗楠
4ee80fafea 1 2022-12-30 10:10:25 +08:00
邹宗楠
8a4c145048 1 2022-12-30 10:00:55 +08:00
邹宗楠
9abe9a3a2c 1 2022-12-30 09:56:22 +08:00
邹宗楠
3167b67693 1 2022-12-30 09:53:06 +08:00
邹宗楠
c88f32cea3 1 2022-12-30 09:34:46 +08:00
邹宗楠
62b5f16fdb 1 2022-12-29 18:39:58 +08:00
邹宗楠
895774141e 1 2022-12-29 17:59:19 +08:00
邹宗楠
7720269bdc 1 2022-12-29 17:43:57 +08:00
邹宗楠
96129c6e31 1 2022-12-29 16:25:18 +08:00
邹宗楠
22e81eb28a 1 2022-12-27 13:53:23 +08:00
邹宗楠
bb830de073 1 2022-12-20 16:29:27 +08:00
邹宗楠
b3bc7a22c4 1' 2022-12-20 16:26:39 +08:00
邹宗楠
caf21632de 1 2022-12-20 11:19:51 +08:00
邹宗楠
192c922cbc 1 2022-12-16 23:40:32 +08:00
邹宗楠
ef8af52e53 1 2022-12-16 21:28:25 +08:00
邹宗楠
45ba9ccc7a 1 2022-12-16 21:19:42 +08:00
邹宗楠
2deef73518 1 2022-12-16 20:30:45 +08:00
邹宗楠
8193186dcd 1 2022-12-16 15:51:49 +08:00
邹宗楠
836947df64 1 2022-12-16 15:48:59 +08:00
邹宗楠
00147fe136 1 2022-12-16 15:48:31 +08:00
邹宗楠
203affee16 1 2022-12-16 15:43:40 +08:00
邹宗楠
6a115c5b9b 1 2022-12-16 15:31:33 +08:00
邹宗楠
edcd9c6ffb 1 2022-12-16 15:25:39 +08:00
邹宗楠
599430d88a 1 2022-12-16 15:21:56 +08:00
邹宗楠
4874f93056 1 2022-12-16 15:11:52 +08:00
邹宗楠
f207641021 1 2022-12-16 15:10:27 +08:00
邹宗楠
d8664534e4 1 2022-12-16 14:58:31 +08:00
邹宗楠
b60ab910d7 1 2022-12-16 14:48:49 +08:00
邹宗楠
2ccef476ea 1 2022-12-16 14:46:13 +08:00
邹宗楠
0c3b2239c1 1 2022-12-16 14:39:37 +08:00
邹宗楠
966d98c732 1 2022-12-16 14:27:42 +08:00
邹宗楠
55b9e629cd 1 2022-12-16 14:20:40 +08:00
邹宗楠
914eff9a1f 1 2022-12-16 13:53:03 +08:00
邹宗楠
43f8d0e623 1 2022-12-16 13:46:03 +08:00
邹宗楠
d8a223e360 1 2022-12-16 11:20:05 +08:00
邹宗楠
c75d1a66c5 1 2022-12-16 11:04:14 +08:00
邹宗楠
2ca0df3f40 1 2022-12-16 10:41:56 +08:00
邹宗楠
c92f7c9955 1 2022-12-16 10:38:45 +08:00
邹宗楠
9161338c9f 1 2022-12-12 09:41:58 +08:00
邹宗楠
be84e7c384 1 2022-12-07 13:51:06 +08:00
邹宗楠
2ba2117f2a 1 2022-11-25 14:16:51 +08:00
邹宗楠
21b0927c53 1 2022-11-24 18:25:44 +08:00
邹宗楠
c3f43c899f 1 2022-11-24 17:12:24 +08:00
邹宗楠
d974a2ff1d 1 2022-11-24 16:26:34 +08:00
邹宗楠
57d94f82ed 1 2022-11-24 13:48:52 +08:00
邹宗楠
3200ebd799 1 2022-11-17 17:57:57 +08:00
邹宗楠
2babd47866 1 2022-11-04 16:29:43 +08:00
邹宗楠
a478fee735 1 2022-11-04 15:57:32 +08:00
邹宗楠
6c05e98c6e 1 2022-11-04 15:48:14 +08:00
邹宗楠
283c53b343 1 2022-11-04 15:16:05 +08:00
邹宗楠
25e5e0f38d 1 2022-11-04 15:12:45 +08:00
邹宗楠
cc8b1a6fc0 1 2022-11-04 15:12:28 +08:00
邹宗楠
722997a64b 1 2022-11-04 15:06:35 +08:00
邹宗楠
bab030bf39 1' 2022-11-04 14:58:14 +08:00
邹宗楠
6fdec929f5 1 2022-11-04 14:45:51 +08:00
邹宗楠
dc55a9e747 1 2022-11-04 14:15:00 +08:00
邹宗楠
308801a465 1 2022-11-02 10:52:47 +08:00
邹宗楠
e7b8c7a510 1 2022-11-01 15:17:25 +08:00
邹宗楠
f57cea0164 1 2022-11-01 14:23:00 +08:00
邹宗楠
559e5ab7fa 1 2022-11-01 11:35:30 +08:00
邹宗楠
136acd2b32 1 2022-11-01 11:09:22 +08:00
邹宗楠
dd96cf4180 1 2022-10-25 15:18:14 +08:00
邹宗楠
718b9991c1 1 2022-10-21 16:18:56 +08:00
邹宗楠
c219086e7e 1 2022-10-21 15:42:05 +08:00
邹宗楠
80e8bbcda8 1 2022-10-21 15:36:45 +08:00
邹宗楠
14a1403936 1 2022-10-21 15:34:45 +08:00
邹宗楠
947682cf88 1 2022-10-21 14:44:29 +08:00
邹宗楠
c0093bf58d 1 2022-10-21 14:31:00 +08:00
邹宗楠
1b320f1dd5 1 2022-10-21 14:30:53 +08:00
邹宗楠
9ba24e16c3 1 2022-10-21 11:47:10 +08:00
邹宗楠
4fd10a3fcc 1 2022-10-20 09:31:50 +08:00
邹宗楠
0bb84957f0 1 2022-10-19 18:23:45 +08:00
邹宗楠
f83be684f6 1' 2022-10-18 16:50:06 +08:00
richboo111
eedbe38535 1 2022-09-21 09:19:01 +08:00
richboo111
e95886f47d 1 2022-09-20 17:49:32 +08:00
richboo111
eaab50c8b2 1 2022-09-20 17:40:06 +08:00
richboo111
40ab9dc95d 1 2022-09-20 17:30:58 +08:00
richboo111
17d45a0ea1 1 2022-09-20 17:28:53 +08:00
richboo111
aee9586fd5 mixpay优化 2022-09-19 15:54:38 +08:00
richboo111
c94ee61690 mixpay优化 2022-09-19 15:53:06 +08:00
86d0619e9e 1 2022-09-11 16:31:11 +08:00
85e5ae4a27 地址不修改 2022-09-11 14:18:42 +08:00
邹宗楠
df5b862b36 1 2022-08-29 14:02:27 +08:00
邹宗楠
3333e9b343 1 2022-08-29 13:52:07 +08:00
邹宗楠
265a1b91e6 1 2022-08-29 13:46:50 +08:00
邹宗楠
4f5aeb4abb 1 2022-08-29 09:25:33 +08:00
邹宗楠
1cf28423bb 修改 2022-08-24 14:19:53 +08:00
邹宗楠
831857418b 添加打印机心跳监听,心跳监听成功,表示打印机激活,用户可以绑定! 2022-08-23 17:22:05 +08:00
邹宗楠
8303af4e32 暂存 2022-08-23 16:52:04 +08:00
邹宗楠
9651e0344d 1 2022-08-23 16:33:32 +08:00
邹宗楠
d2fef3a336 1 2022-08-22 15:39:10 +08:00
邹宗楠
27bbaf83d2 1 2022-08-22 15:15:13 +08:00
邹宗楠
d276510301 1 2022-08-22 15:06:11 +08:00
邹宗楠
ebb09f2cf0 1 2022-08-22 15:02:21 +08:00
邹宗楠
eeb48fa769 1 2022-08-22 13:40:19 +08:00
邹宗楠
ae0dfd4cf4 1 2022-08-22 11:35:15 +08:00
邹宗楠
dc6db2db8e 1 2022-08-22 11:27:24 +08:00
邹宗楠
027ffa19ca 1 2022-08-18 09:15:26 +08:00
邹宗楠
949b070f03 1 2022-08-17 17:52:02 +08:00
richboo111
80c380ce7a a 2022-08-15 17:57:01 +08:00
richboo111
d4529675f0 a 2022-08-15 17:19:22 +08:00
richboo111
10569b34f8 a 2022-08-15 17:15:29 +08:00
richboo111
1600a275be a 2022-08-15 17:09:49 +08:00
richboo111
817d44a693 a 2022-08-15 16:49:19 +08:00
richboo111
2e28867bc7 a 2022-08-15 16:45:36 +08:00
richboo111
48e4753a2a 快递地址前缀 2022-08-15 15:54:31 +08:00
richboo111
5595fd5ad9 快递地址前缀 2022-08-15 14:48:11 +08:00
richboo111
65a530b33b 快递地址前缀 2022-08-15 14:38:38 +08:00
邹宗楠
25730745b8 1 2022-08-11 13:44:21 +08:00
邹宗楠
8350944f7a 1 2022-08-11 11:03:57 +08:00
邹宗楠
9dfcd9091b 1 2022-08-11 10:30:50 +08:00
邹宗楠
b0cf2fbe62 1 2022-08-08 15:55:45 +08:00
richboo111
2812fa1f08 add 充值到余额订单 2022-08-08 14:23:17 +08:00
richboo111
7cc14319ee add 充值到余额订单 2022-08-08 14:11:00 +08:00
richboo111
9476a98b69 add 充值到余额订单 2022-08-08 14:04:42 +08:00
邹宗楠
b393bd17b8 Merge branch 'rsm' of e.coding.net:rosydev/jx-callback into rsm 2022-08-08 10:31:12 +08:00
邹宗楠
24fec9b4a7 添加打印机设置 2022-08-08 10:31:06 +08:00
richboo111
5128d2b100 1 2022-08-08 09:13:41 +08:00
邹宗楠
0830cc75e8 添加模板 2022-08-05 15:09:57 +08:00
邹宗楠
13da7ceafc 1 2022-08-05 11:27:31 +08:00
邹宗楠
ca1f6fccbe 1 2022-08-05 09:54:17 +08:00
邹宗楠
5984d5a475 修改冲突 2022-08-05 09:39:35 +08:00
邹宗楠
7176f00b9d Merge branch 'rsm' of e.coding.net:rosydev/jx-callback into rsm 2022-08-05 09:36:01 +08:00
邹宗楠
6ddcd52c20 提交数据 2022-08-05 09:35:53 +08:00
richboo111
5f91a82539 query 2022-08-04 18:31:28 +08:00
richboo111
bd03bebf66 Merge branch 'rsm' of https://e.coding.net/rosydev/jx-callback into rsm 2022-08-04 18:31:08 +08:00
richboo111
3e7800551a query 2022-08-04 18:30:59 +08:00
邹宗楠
84e54bf4d7 1 2022-08-04 18:27:23 +08:00
richboo111
2451d1ca29 query 2022-08-04 18:13:21 +08:00
邹宗楠
bc1e059d32 Merge branch 'rsm' of e.coding.net:rosydev/jx-callback into rsm 2022-08-04 18:08:55 +08:00
邹宗楠
9286e28acc 1 2022-08-04 18:08:48 +08:00
richboo111
fb90a96f65 pay 2022-08-04 17:43:42 +08:00
邹宗楠
f1761fa154 修改语音配置 2022-08-04 17:26:19 +08:00
richboo111
61a994023d pay 2022-08-04 17:25:19 +08:00
richboo111
e8deb61cad pay 2022-08-04 16:17:28 +08:00
richboo111
89b30a3830 pay 2022-08-04 15:39:14 +08:00
邹宗楠
48b46da333 1 2022-08-04 15:17:29 +08:00
邹宗楠
d294481d5a 1 2022-08-04 14:51:36 +08:00
richboo111
f328d74b38 pay 2022-08-04 14:48:03 +08:00
richboo111
3af95bd88f pay 2022-08-04 14:43:18 +08:00
邹宗楠
8f9e334e0b 1 2022-08-04 14:44:02 +08:00
richboo111
f3848a6a65 pay 2022-08-04 14:38:00 +08:00
richboo111
bb49c91799 Merge branch 'rsm' of https://e.coding.net/rosydev/jx-callback into rsm 2022-08-04 14:31:01 +08:00
邹宗楠
efeb2ac31d 获取数据 2022-08-04 14:32:16 +08:00
richboo111
e1905cfccc pay 2022-08-04 14:30:44 +08:00
邹宗楠
c73f22ab60 1 2022-08-04 14:27:08 +08:00
richboo111
8b6349c187 pay 2022-08-04 14:23:38 +08:00
richboo111
ced6ba0951 pay 2022-08-04 13:34:51 +08:00
richboo111
96adca6623 Merge branch 'rsm' of https://e.coding.net/rosydev/jx-callback into rsm 2022-08-04 11:46:53 +08:00
邹宗楠
e0e5cbdae5 1 2022-08-04 11:46:56 +08:00
richboo111
e754065a5d pay 2022-08-04 11:46:43 +08:00
邹宗楠
b3ced58e91 1 2022-08-04 11:25:04 +08:00
richboo111
33f0594a6e pay 2022-08-04 11:20:52 +08:00
richboo111
263c155acb pay 2022-08-04 11:17:49 +08:00
richboo111
9da4fd8d2f pay 2022-08-04 11:07:02 +08:00
richboo111
5040922b5d pay 2022-08-04 11:04:46 +08:00
richboo111
fd6ef8aaa3 Merge branches 'rsm' and 'rsm' of https://e.coding.net/rosydev/jx-callback into rsm 2022-08-04 11:01:02 +08:00
richboo111
c172e726d4 pay 2022-08-04 11:00:43 +08:00
邹宗楠
beee8def03 修改orderno取值范围 2022-08-04 10:46:16 +08:00
richboo111
df9b60c921 pay 2022-08-04 10:34:24 +08:00
邹宗楠
f250957e0f 1 2022-08-04 10:26:34 +08:00
邹宗楠
2867386ea1 1 2022-08-04 10:00:30 +08:00
邹宗楠
f9e1bb21af 更新打印机数据db 2022-08-04 09:55:23 +08:00
邹宗楠
090369c02e Merge branch 'rsm' of e.coding.net:rosydev/jx-callback into rsm
# Conflicts:
#	globals/beegodb/beegodb.go
2022-08-04 09:54:39 +08:00
邹宗楠
6310f7b494 1 2022-08-04 09:52:35 +08:00
richboo111
97baf97d97 pay 2022-08-04 09:42:51 +08:00
richboo111
5eff50358a pay 2022-08-03 17:59:44 +08:00
richboo111
f102b2753c pay 2022-08-03 17:39:35 +08:00
richboo111
3dd5cf5910 pay 2022-08-03 17:19:55 +08:00
richboo111
dd9b616371 pay 2022-08-03 17:10:30 +08:00
richboo111
766a35d2f3 pay 2022-08-03 17:05:31 +08:00
richboo111
8cd0816719 pay 2022-08-03 17:00:54 +08:00
richboo111
d7c472372e pay 2022-08-03 16:27:06 +08:00
richboo111
a73dfb6527 pay 2022-08-03 16:17:45 +08:00
richboo111
0494432fa1 pay 2022-08-03 15:30:04 +08:00
richboo111
2176e32aec pay 2022-08-03 15:23:24 +08:00
richboo111
ff0ac93af1 pay 2022-08-03 15:14:10 +08:00
richboo111
a243efcd74 pay 2022-08-03 15:04:35 +08:00
richboo111
74212b0456 pay 2022-08-03 15:03:57 +08:00
richboo111
74c36d2691 pay 2022-08-03 14:58:54 +08:00
richboo111
2d20a2b5c7 pay 2022-08-03 14:53:36 +08:00
richboo111
b78d5c4ca2 pay 2022-08-03 14:49:41 +08:00
richboo111
a3b888c2c5 pay 2022-08-03 14:45:29 +08:00
richboo111
92ef9b145f pay 2022-08-03 14:43:12 +08:00
richboo111
31cb674994 pay 2022-08-03 14:40:28 +08:00
richboo111
618f83ba52 pay 2022-08-03 14:27:54 +08:00
richboo111
6bea930477 pay 2022-08-03 14:15:05 +08:00
richboo111
63f96ca426 pay 2022-08-03 14:09:27 +08:00
richboo111
302ff68ab6 pay 2022-08-03 13:58:03 +08:00
richboo111
c2fe05bd5d pay 2022-08-03 13:52:49 +08:00
richboo111
f03a46a0da pay 2022-08-03 13:49:55 +08:00
richboo111
7e7859c45e pay 2022-08-03 13:47:44 +08:00
richboo111
cbc471ac93 pay 2022-08-03 13:42:27 +08:00
richboo111
c06d648a04 pay 2022-08-03 11:47:36 +08:00
richboo111
c457f143b3 pay 2022-08-03 11:44:52 +08:00
richboo111
0901922618 pay 2022-08-03 11:39:07 +08:00
richboo111
a1a080b68e pay 2022-08-03 11:30:02 +08:00
richboo111
9baac98681 pay 2022-08-03 11:20:47 +08:00
richboo111
ad062f5355 pay 2022-08-03 11:16:16 +08:00
richboo111
3ab6fd6b21 pay 2022-08-03 11:11:28 +08:00
richboo111
6eaf2b37c9 pay 2022-08-03 11:03:20 +08:00
richboo111
37337b9611 pay 2022-08-03 10:44:30 +08:00
richboo111
bfdc340a77 pay 2022-08-03 10:09:52 +08:00
richboo111
bc6ec1e498 pay 2022-08-03 10:01:08 +08:00
richboo111
0d27fb7bd5 pay 2022-08-03 09:46:18 +08:00
richboo111
396d123b4f pay 2022-08-03 09:03:26 +08:00
richboo111
c705214b94 pay 2022-08-02 18:26:17 +08:00
richboo111
adbc9d83b2 pay 2022-08-02 18:18:24 +08:00
richboo111
59085a5b13 pay 2022-08-02 18:09:54 +08:00
richboo111
7dbfd75944 pay 2022-08-02 17:58:17 +08:00
richboo111
6c625c4592 pay 2022-08-02 17:53:02 +08:00
richboo111
2b948d7d35 pay 2022-08-02 17:22:15 +08:00
richboo111
979769669f pay 2022-08-02 17:21:08 +08:00
richboo111
9a9be62928 pay 2022-08-02 17:07:37 +08:00
richboo111
b21b94beca pay 2022-08-02 16:55:03 +08:00
richboo111
78796da29a pay 2022-08-02 16:48:01 +08:00
richboo111
f98f900550 add pay 2022-08-01 15:58:33 +08:00
richboo111
5213725aeb add pay 2022-08-01 15:47:54 +08:00
richboo111
648f0c8b18 add pay 2022-08-01 15:46:51 +08:00
richboo111
65a96e5dfb add pay 2022-08-01 15:43:55 +08:00
richboo111
03d3b5a581 add pay 2022-08-01 15:39:16 +08:00
richboo111
e9225a2a2f add pay 2022-08-01 15:35:20 +08:00
richboo111
e9f9a68c61 add pay 2022-08-01 15:28:10 +08:00
richboo111
edd7949cf4 add pay 2022-08-01 15:10:21 +08:00
richboo111
577823a804 add pay 2022-08-01 14:17:11 +08:00
richboo111
07ae683b22 mixpay 2022-07-29 18:16:41 +08:00
richboo111
23165bd5d2 mixpay 2022-07-29 15:55:13 +08:00
richboo111
e11b4f4611 mixpay 2022-07-29 15:23:21 +08:00
richboo111
4bbf80c7a4 pay log 2022-07-28 18:05:27 +08:00
邹宗楠
990101655e Merge branch 'rsm' of e.coding.net:rosydev/jx-callback into rsm 2022-07-28 18:05:48 +08:00
邹宗楠
a47113288b 1 2022-07-28 18:05:37 +08:00
richboo111
64178e8bdf pay log 2022-07-28 17:37:25 +08:00
邹宗楠
46c422aee5 Merge branch 'rsm' of e.coding.net:rosydev/jx-callback into rsm 2022-07-28 17:14:05 +08:00
邹宗楠
6b327a830a 1 2022-07-28 17:13:55 +08:00
richboo111
6b4e3d4e5e pay log 2022-07-28 17:09:00 +08:00
richboo111
b06bccd277 pay log 2022-07-28 17:05:04 +08:00
邹宗楠
334eaef18e 1 2022-07-28 14:50:04 +08:00
richboo111
5e2c0e035e pay log 2022-07-28 14:39:51 +08:00
richboo111
9a8abf0a60 pay log 2022-07-28 14:31:47 +08:00
邹宗楠
0a435db932 Merge branch 'rsm' of e.coding.net:rosydev/jx-callback into rsm 2022-07-28 14:32:25 +08:00
邹宗楠
10653b50c5 1 2022-07-28 14:32:19 +08:00
richboo111
c5e0474fd6 pay log 2022-07-28 14:10:39 +08:00
邹宗楠
5933a585cd 修改指令 2022-07-28 14:09:33 +08:00
邹宗楠
714d618550 1 2022-07-28 13:54:46 +08:00
邹宗楠
24341f5d1c 1 2022-07-28 13:52:20 +08:00
richboo111
16fa4f09ed pay log 2022-07-28 13:46:14 +08:00
邹宗楠
7476e9a721 语音暂停 2022-07-28 13:44:00 +08:00
邹宗楠
63f3fbadad Merge branch 'rsm' of e.coding.net:rosydev/jx-callback into rsm 2022-07-28 11:59:49 +08:00
邹宗楠
5a75d81980 1 2022-07-28 11:59:40 +08:00
richboo111
2f184ee50a pay log 2022-07-28 11:55:44 +08:00
richboo111
7fccdd507b pay log 2022-07-28 11:48:07 +08:00
邹宗楠
2c765f7547 1 2022-07-28 11:15:29 +08:00
邹宗楠
8c2e0ab70f 调试 2022-07-28 10:48:18 +08:00
邹宗楠
9b18e6c175 音频 2022-07-28 10:38:22 +08:00
邹宗楠
db8da30d67 1 2022-07-28 09:24:53 +08:00
邹宗楠
07e21a6dec 1 2022-07-27 18:49:37 +08:00
邹宗楠
fc56434e55 1 2022-07-27 18:45:42 +08:00
richboo111
c7ef385ba0 取消后更新订单状态 2022-07-27 18:13:39 +08:00
邹宗楠
cb72da4031 Merge branch 'rsm' of e.coding.net:rosydev/jx-callback into rsm 2022-07-27 18:13:53 +08:00
邹宗楠
6ce9c708dc 1 2022-07-27 18:13:41 +08:00
richboo111
7036c87d09 取消后更新订单状态 2022-07-27 18:09:30 +08:00
邹宗楠
d02fc8f93b 修改音频补位 2022-07-27 18:05:06 +08:00
richboo111
e7d6da9e1d 取消后更新订单状态 2022-07-27 18:05:05 +08:00
richboo111
c3dcae9427 取消后更新订单状态 2022-07-27 17:57:35 +08:00
richboo111
2d008b822a 取消后更新订单状态 2022-07-27 17:49:38 +08:00
邹宗楠
f077bf4283 修改语音调试 2022-07-27 17:48:44 +08:00
邹宗楠
d5848e415c Merge branch 'rsm' of e.coding.net:rosydev/jx-callback into rsm 2022-07-27 17:46:37 +08:00
邹宗楠
9d0d0f5e21 1 2022-07-27 17:46:26 +08:00
邹宗楠
de5bff6892 1 2022-07-27 17:35:39 +08:00
richboo111
43242124c0 取消后更新订单状态 2022-07-27 17:35:10 +08:00
richboo111
2f02aef723 取消后更新订单状态 2022-07-27 17:31:47 +08:00
邹宗楠
b5fe22f908 1 2022-07-27 16:47:15 +08:00
邹宗楠
660c30602c 修改了ansible.yml文件shell搅拌 2022-07-27 16:43:49 +08:00
richboo111
b7e26a3843 取消快递订单 2022-07-27 16:40:14 +08:00
邹宗楠
a7315ffa36 1 2022-07-27 16:31:31 +08:00
邹宗楠
c95ff61c20 1 2022-07-27 16:31:06 +08:00
richboo111
69cead265b log 2022-07-27 16:24:20 +08:00
richboo111
73cdbb1426 log 2022-07-27 16:20:17 +08:00
richboo111
f2e9fef592 log 2022-07-27 16:16:08 +08:00
richboo111
a4c1c1dc75 log 2022-07-27 16:12:29 +08:00
邹宗楠
2a73940961 1 2022-07-27 16:13:05 +08:00
richboo111
6a06a29e54 log 2022-07-27 16:09:01 +08:00
richboo111
e8eac75f71 log 2022-07-27 15:54:18 +08:00
邹宗楠
2d5c6c2090 1 2022-07-27 15:43:22 +08:00
richboo111
5b8ee36a6e log 2022-07-27 15:40:26 +08:00
richboo111
423185fbe5 log 2022-07-27 15:38:05 +08:00
邹宗楠
d8d8445c3b 1 2022-07-27 15:34:46 +08:00
richboo111
b12901f0b8 log 2022-07-27 15:21:55 +08:00
richboo111
3a17f3a5bb log 2022-07-27 15:18:57 +08:00
richboo111
e951df82c6 log 2022-07-27 15:17:13 +08:00
richboo111
35450fed80 log 2022-07-27 15:14:04 +08:00
richboo111
51c7ca4581 log 2022-07-27 15:10:49 +08:00
邹宗楠
c0f6c0f318 1 2022-07-27 15:06:25 +08:00
richboo111
610187ad44 log 2022-07-27 15:04:10 +08:00
邹宗楠
49a0132967 1 2022-07-27 15:00:52 +08:00
邹宗楠
bb6ade2684 1 2022-07-27 14:51:02 +08:00
richboo111
45a06c52cb log 2022-07-27 14:43:53 +08:00
richboo111
29a656d505 log 2022-07-27 14:41:41 +08:00
richboo111
ad87443232 log 2022-07-27 14:39:25 +08:00
richboo111
6339d6c305 log 2022-07-27 14:33:31 +08:00
richboo111
b9f8138ce4 log 2022-07-27 14:25:46 +08:00
邹宗楠
c86619a391 Merge remote-tracking branch 'origin/rsm' into rsm 2022-07-27 14:18:24 +08:00
邹宗楠
1d335d80de 1 2022-07-27 14:18:09 +08:00
richboo111
1831f4803c Merge branch 'rsm' of https://e.coding.net/rosydev/jx-callback into rsm 2022-07-27 14:12:22 +08:00
richboo111
c2a77313bf log 2022-07-27 14:12:09 +08:00
邹宗楠
994fd3c18b Merge remote-tracking branch 'origin/rsm' into rsm 2022-07-27 14:09:05 +08:00
邹宗楠
955b271eb3 1 2022-07-27 14:07:27 +08:00
richboo111
9214513cff rollback 2022-07-27 13:38:14 +08:00
richboo111
2a19d7a4a7 add 2022-07-27 10:48:29 +08:00
richboo111
e2b3637d9a log 2022-07-27 10:43:21 +08:00
richboo111
4a3f6b114c log 2022-07-27 10:26:53 +08:00
richboo111
18c27229e6 log 2022-07-27 10:23:48 +08:00
richboo111
dac9a6b805 log 2022-07-27 10:18:59 +08:00
richboo111
d0fb1bfd8d log 2022-07-27 10:09:47 +08:00
richboo111
10b69be9c8 log 2022-07-27 10:08:09 +08:00
richboo111
c276ffa0db log 2022-07-27 10:02:02 +08:00
邹宗楠
46905fa513 1 2022-07-26 18:52:25 +08:00
邹宗楠
44575685e9 1 2022-07-26 18:43:32 +08:00
邹宗楠
28365d1a99 1 2022-07-26 18:29:35 +08:00
richboo111
4ff61f9a39 修改获取快递订单详情验证 2022-07-26 18:14:26 +08:00
邹宗楠
d0b242e2ea 1 2022-07-26 18:14:28 +08:00
邹宗楠
9f7a64cbbe 1 2022-07-26 17:19:19 +08:00
邹宗楠
e7cc5c9932 1 2022-07-26 17:08:26 +08:00
邹宗楠
38c5f63334 1 2022-07-26 16:19:15 +08:00
richboo111
d103197d43 增加paybybalance路由 2022-07-26 15:44:04 +08:00
richboo111
50fde3330d log 2022-07-26 15:31:27 +08:00
邹宗楠
a7dc882512 语音 2022-07-26 15:25:05 +08:00
richboo111
7478be1de8 finish 2022-07-26 15:22:51 +08:00
邹宗楠
e2a42eac9b 1 2022-07-26 15:18:43 +08:00
邹宗楠
488e85bbaa 修改语音指令 2022-07-26 15:16:43 +08:00
richboo111
c9a8bc7415 log 2022-07-26 15:09:41 +08:00
邹宗楠
5a2505c4e3 修改语音 2022-07-26 15:06:50 +08:00
richboo111
e493f6d2f1 log 2022-07-26 14:57:31 +08:00
邹宗楠
c7ce59312c 1 2022-07-26 14:49:38 +08:00
richboo111
5ba84e7e10 log 2022-07-26 14:43:57 +08:00
邹宗楠
4c521ccbde 1 2022-07-26 14:41:06 +08:00
邹宗楠
53ef22f8e7 1 2022-07-26 14:30:23 +08:00
邹宗楠
89581a69b4 语音修改 2022-07-26 14:23:44 +08:00
richboo111
57d5af6108 log 2022-07-26 14:11:53 +08:00
richboo111
bf03d7cf19 Merge branch 'rsm' of https://e.coding.net/rosydev/jx-callback into rsm 2022-07-26 14:11:33 +08:00
richboo111
41a6594f8a log 2022-07-26 14:05:06 +08:00
邹宗楠
9fe8a0e29b 1 2022-07-26 14:02:53 +08:00
邹宗楠
44bedb490d 修改数据转化 2022-07-26 14:00:36 +08:00
richboo111
b3cd42eead auto 2022-07-26 13:49:30 +08:00
richboo111
f007eceba6 log 2022-07-26 13:32:46 +08:00
richboo111
f4527f4078 Merge branch 'rsm' of https://e.coding.net/rosydev/jx-callback into rsm 2022-07-26 11:55:44 +08:00
richboo111
17ef6c5170 新增混合支付+完善新会员充值 2022-07-26 11:55:20 +08:00
邹宗楠
6a409d113b 1 2022-07-26 11:47:37 +08:00
邹宗楠
1d2c5e7cb3 修改冲突 2022-07-26 11:40:30 +08:00
邹宗楠
fa903fe325 修改语音播报 2022-07-26 11:37:22 +08:00
richboo111
2b3349127d 删除旧充值方式 2022-07-25 11:00:56 +08:00
richboo111
12a5356fa6 删除旧充值会员 2022-07-25 10:59:23 +08:00
邹宗楠
273aa3164f 取消订单 2022-07-25 10:48:09 +08:00
邹宗楠
006fa482c9 1 2022-07-25 10:41:26 +08:00
邹宗楠
cff7df7bb0 1 2022-07-25 10:35:42 +08:00
邹宗楠
d43159df8e 1 2022-07-25 10:17:16 +08:00
邹宗楠
dd77bc44b9 1 2022-07-25 10:09:37 +08:00
邹宗楠
9a3c23cb93 添加打印 2022-07-25 09:41:42 +08:00
邹宗楠
dceafe02da 1 2022-07-22 19:29:26 +08:00
邹宗楠
4c8e27b68f 1 2022-07-22 18:53:48 +08:00
邹宗楠
99513042d1 1 2022-07-22 18:33:49 +08:00
邹宗楠
0085e0cb39 Merge branch 'rsm' of e.coding.net:rosydev/jx-callback into rsm 2022-07-22 18:21:00 +08:00
richboo111
11f4ae8140 count 2022-07-22 17:54:40 +08:00
richboo111
54d726f006 cnt 2022-07-22 17:33:27 +08:00
邹宗楠
31ba7bfe14 1 2022-07-22 17:16:33 +08:00
richboo111
d546e5a880 add 2022-07-22 17:11:48 +08:00
richboo111
6cc34d2a6d add 2022-07-22 16:45:44 +08:00
richboo111
09477a093e add 2022-07-22 16:32:18 +08:00
richboo111
4bfb4666cd add 2022-07-22 16:05:03 +08:00
richboo111
0012b7ed4f add 2022-07-22 14:36:43 +08:00
richboo111
ed5deec4f4 add 2022-07-22 14:05:15 +08:00
richboo111
92dffeba1d add 2022-07-22 11:46:41 +08:00
richboo111
eba9e2c250 增加微信方式充值会员 2022-07-22 11:32:15 +08:00
richboo111
4b6a1a7172 Merge branch 'rsm' of https://e.coding.net/rosydev/jx-callback into rsm 2022-07-21 18:05:12 +08:00
richboo111
76c7faa927 增加微信支付处理业务 2022-07-21 18:04:54 +08:00
邹宗楠
8c48c93e6d Merge branch 'rsm' of e.coding.net:rosydev/jx-callback into rsm 2022-07-21 17:20:36 +08:00
邹宗楠
7c5aefe607 1 2022-07-21 09:41:36 +08:00
richboo111
6191973f13 删除日志检测 2022-07-20 18:21:00 +08:00
richboo111
81fca6fb44 修改为活动价 2022-07-20 17:44:04 +08:00
richboo111
7f894c9cef 开通会员修改为活动价 2022-07-20 16:58:50 +08:00
richboo111
c34535b638 debug address 2022-07-20 14:24:35 +08:00
richboo111
6ad5157cdc debug address 2022-07-20 14:13:08 +08:00
邹宗楠
4607c29b79 1 2022-07-20 11:34:11 +08:00
邹宗楠
f9a0f52982 1' 2022-07-13 17:50:11 +08:00
邹宗楠
6c0d4755e2 1 2022-07-12 17:52:03 +08:00
邹宗楠
7ddb256847 1 2022-07-12 17:41:22 +08:00
邹宗楠
6c68fcabd5 1 2022-07-12 17:36:19 +08:00
邹宗楠
2c3bb20bdd 1 2022-07-12 17:34:33 +08:00
邹宗楠
9e1624a25f 1 2022-07-12 17:27:46 +08:00
邹宗楠
1d018a2357 1 2022-07-12 17:21:11 +08:00
邹宗楠
a8dc2f72df 1 2022-07-12 17:15:09 +08:00
邹宗楠
7fe320cded 1 2022-07-12 17:09:52 +08:00
邹宗楠
0eb5642742 1 2022-07-12 17:02:03 +08:00
邹宗楠
3611481176 1 2022-07-12 16:39:21 +08:00
邹宗楠
1f8ddd9121 1 2022-07-12 16:22:31 +08:00
邹宗楠
59e27b0cee 1 2022-07-12 16:06:19 +08:00
邹宗楠
c1a523f84b 1 2022-07-12 16:01:11 +08:00
邹宗楠
6bb1f91bcc 1 2022-07-12 15:05:29 +08:00
邹宗楠
7d31cf9a70 1 2022-07-12 14:53:10 +08:00
邹宗楠
4636417016 1 2022-07-12 14:44:34 +08:00
邹宗楠
c22137d83b 1 2022-07-12 14:39:20 +08:00
邹宗楠
9ecc91077b 1 2022-07-12 14:29:46 +08:00
邹宗楠
c262cdf644 1 2022-07-12 09:40:05 +08:00
邹宗楠
4c0f341523 1 2022-07-12 09:23:13 +08:00
邹宗楠
670f536586 1 2022-07-12 09:19:29 +08:00
邹宗楠
9887bd9a8c 1 2022-07-11 15:40:44 +08:00
邹宗楠
94bb3a14e7 1 2022-07-11 15:37:49 +08:00
邹宗楠
21fc18b006 1 2022-07-11 15:29:15 +08:00
邹宗楠
ac2e6f3964 修改 2022-07-11 15:25:07 +08:00
邹宗楠
780fca768e 添加用户提现操作 2022-07-11 15:16:10 +08:00
邹宗楠
efc987d932 1 2022-07-11 09:52:25 +08:00
邹宗楠
b67d3556cf 1 2022-07-08 18:23:25 +08:00
邹宗楠
846e548d2c 1 2022-07-07 19:14:12 +08:00
邹宗楠
5bb4e23773 1 2022-07-07 16:35:10 +08:00
邹宗楠
a674ddd8d9 1 2022-07-06 17:16:08 +08:00
邹宗楠
85e8a8c980 1 2022-07-06 17:11:53 +08:00
邹宗楠
289ced8fbb 天假支付宝提现操作 2022-07-06 16:49:15 +08:00
邹宗楠
6c26e35a23 1 2022-07-06 15:19:40 +08:00
邹宗楠
4f1a7167cf 1 2022-07-05 10:45:43 +08:00
邹宗楠
4b196bf5be 1 2022-07-05 10:39:44 +08:00
邹宗楠
030bc04fa5 1 2022-07-05 10:09:51 +08:00
邹宗楠
7c9d01071c 1 2022-07-05 09:50:21 +08:00
邹宗楠
b87d00bae4 1 2022-07-05 09:20:34 +08:00
邹宗楠
9f208b9a9c 1 2022-07-04 19:49:31 +08:00
邹宗楠
18b54a0c07 1 2022-07-04 19:42:49 +08:00
邹宗楠
91f2f223e4 1 2022-07-04 19:36:22 +08:00
邹宗楠
f397526a8d 1 2022-07-04 19:24:18 +08:00
邹宗楠
c26586433e 1 2022-07-04 19:15:04 +08:00
邹宗楠
33c7ad037b 1 2022-07-04 19:10:35 +08:00
邹宗楠
8e589a4dd0 1 2022-07-04 18:59:51 +08:00
邹宗楠
c14c7939b1 1 2022-07-04 18:00:07 +08:00
邹宗楠
ded8d505fb 1 2022-07-04 17:28:10 +08:00
邹宗楠
3424bd2c6a 1 2022-07-04 17:27:53 +08:00
邹宗楠
a967777ce1 1 2022-07-04 17:17:02 +08:00
邹宗楠
0d413b02fa 1 2022-07-04 17:12:08 +08:00
邹宗楠
818b21781d 1 2022-07-04 17:04:15 +08:00
邹宗楠
706d653c31 1 2022-07-04 16:46:03 +08:00
邹宗楠
b5f0c2b724 1 2022-07-04 16:34:23 +08:00
邹宗楠
821762be29 1 2022-07-04 16:28:00 +08:00
邹宗楠
11f4265954 1 2022-07-04 15:43:49 +08:00
邹宗楠
05b904919c 1 2022-07-04 15:28:50 +08:00
邹宗楠
78dc569b70 1 2022-07-04 15:06:00 +08:00
邹宗楠
22f3112a37 支付测试 2022-07-04 14:56:31 +08:00
邹宗楠
9b28749d54 1 2022-07-04 14:54:29 +08:00
邹宗楠
9a79890e9d 1 2022-07-04 14:37:08 +08:00
邹宗楠
e821a6a6db 1 2022-07-04 14:32:01 +08:00
邹宗楠
33cb580c06 1 2022-07-04 14:18:56 +08:00
邹宗楠
32fc1b1193 1 2022-07-04 14:07:53 +08:00
邹宗楠
c1abd8c810 1 2022-07-04 11:59:11 +08:00
邹宗楠
84aacc5287 1 2022-07-04 11:52:05 +08:00
邹宗楠
ee7620ff22 1 2022-07-04 11:50:58 +08:00
邹宗楠
e96ede8614 添加总条数 2022-07-04 11:48:33 +08:00
邹宗楠
42a8ac0dc9 1 2022-07-04 11:45:10 +08:00
邹宗楠
10298bf1ee kongge 2022-07-04 11:30:33 +08:00
邹宗楠
13339b1cfe 1 2022-07-04 11:26:40 +08:00
邹宗楠
9db497336d 1 2022-07-04 11:12:35 +08:00
邹宗楠
0f18f58f5d 1 2022-07-04 09:35:53 +08:00
邹宗楠
c504026fd9 1 2022-07-04 09:29:26 +08:00
邹宗楠
467661c738 1 2022-07-01 18:56:50 +08:00
邹宗楠
8d8ad8939e 1 2022-07-01 18:54:47 +08:00
邹宗楠
528aa3e9b8 1 2022-07-01 18:44:34 +08:00
邹宗楠
44eb36a952 1 2022-07-01 18:44:04 +08:00
邹宗楠
3e0f3fcaa7 1 2022-07-01 18:38:56 +08:00
邹宗楠
e786ad4bdc 新增删除订单,已经轮询修改订单状态,没两个小时更新一次 2022-07-01 18:34:27 +08:00
邹宗楠
6d871f85a0 1 2022-07-01 17:09:19 +08:00
邹宗楠
2886cac6bc 添加快递公司 2022-07-01 17:02:10 +08:00
邹宗楠
1ad9113e11 1 2022-07-01 13:48:57 +08:00
邹宗楠
3f8d4b0b08 1 2022-07-01 13:44:06 +08:00
邹宗楠
6aa5e34c63 1 2022-07-01 12:01:23 +08:00
邹宗楠
bce0f97c1c 1 2022-07-01 11:37:37 +08:00
邹宗楠
0e759d05e5 1 2022-07-01 11:28:37 +08:00
邹宗楠
d7a234e4af 修改详情 2022-07-01 11:25:48 +08:00
邹宗楠
e45f461bfb 1 2022-07-01 10:57:11 +08:00
邹宗楠
d571f4b0dd 天假总条数 2022-07-01 10:10:42 +08:00
邹宗楠
a43aaad852 1 2022-06-30 18:45:58 +08:00
邹宗楠
30129f3fe3 1 2022-06-30 18:44:21 +08:00
邹宗楠
d4e2be2e42 1 2022-06-30 18:33:38 +08:00
邹宗楠
77547b258f 1 2022-06-30 18:31:38 +08:00
邹宗楠
0e7e9ec818 1 2022-06-30 18:26:56 +08:00
邹宗楠
d6b8097626 添加返回值 2022-06-30 18:02:30 +08:00
邹宗楠
b4d94c7979 1 2022-06-30 17:47:22 +08:00
邹宗楠
9339f35c11 1 2022-06-30 09:34:14 +08:00
邹宗楠
4e5246cbda 物流笑嘻嘻 2022-06-29 15:59:47 +08:00
邹宗楠
301a430666 1 2022-06-28 15:31:25 +08:00
邹宗楠
86f18cc35f 1 2022-06-28 14:10:05 +08:00
邹宗楠
d5fa7c2a36 添加快递 2022-06-28 10:13:21 +08:00
邹宗楠
c84b67d67e 1 2022-06-27 18:26:38 +08:00
邹宗楠
f3d4a9e496 1 2022-06-27 17:15:45 +08:00
邹宗楠
1400845af3 添加下单接口 2022-06-27 15:36:47 +08:00
邹宗楠
1eb31e2b92 暂存 2022-06-24 18:11:34 +08:00
邹宗楠
09fd5e8762 添加快递渠道 2022-06-24 17:33:26 +08:00
邹宗楠
24be6bcab3 1 2022-06-23 15:28:33 +08:00
suyl
aa2a2d4668 aa 2021-10-19 18:19:58 +08:00
suyl
175b81d0fd aa 2021-08-27 16:45:08 +08:00
suyl
97cb95647b aa 2021-08-26 15:22:07 +08:00
suyl
b375c08422 aa 2021-08-26 14:30:23 +08:00
suyl
398eb6ef78 aa 2021-08-26 14:19:15 +08:00
suyl
0754010594 a 2021-08-26 14:13:55 +08:00
suyl
5dea4eea14 aa 2021-08-26 14:01:57 +08:00
suyl
88ef2c9190 aa 2021-08-26 13:58:44 +08:00
suyl
51850b93ed aa 2021-08-13 15:12:09 +08:00
suyl
2c6337fa21 aa 2021-08-13 11:12:56 +08:00
suyl
fcfc9e744d aa 2021-08-13 11:09:16 +08:00
suyl
5ae442993e aa 2021-08-10 16:58:41 +08:00
suyl
c595835777 aa 2021-08-10 16:20:27 +08:00
suyl
eeed665278 aa 2021-08-10 15:55:31 +08:00
suyl
120cbfff11 aa 2021-08-10 15:52:26 +08:00
suyl
7b8489fa50 aa 2021-08-10 15:49:54 +08:00
suyl
2843356057 aa 2021-08-10 15:44:28 +08:00
suyl
7ed142c1a9 aa 2021-08-10 15:37:09 +08:00
suyl
69e13203e6 aa 2021-08-10 15:33:13 +08:00
suyl
0b2d728ae3 aa 2021-08-10 15:32:40 +08:00
suyl
c82ee269cd aa 2021-08-10 15:25:29 +08:00
suyl
5b3d26c061 aa 2021-08-10 15:20:08 +08:00
suyl
9889a2ca29 aa 2021-08-10 15:17:59 +08:00
suyl
73aeaee494 aa 2021-08-10 15:15:17 +08:00
suyl
d63c7b8fcd aa 2021-08-10 15:12:27 +08:00
suyl
20909edad8 aa 2021-08-10 15:08:08 +08:00
suyl
f1914aad10 aa 2021-08-10 15:07:22 +08:00
suyl
6fed882155 aa 2021-08-10 15:00:36 +08:00
suyl
05936783de aa 2021-08-10 14:57:10 +08:00
suyl
60ae59f801 aa 2021-08-10 10:45:38 +08:00
suyl
e746693d93 aa 2021-08-10 10:27:55 +08:00
suyl
65e4d2907f aa 2021-08-10 10:07:59 +08:00
suyl
e3753dacca 尝试直接用link加水印 2021-08-10 09:45:53 +08:00
suyl
69883c0944 分享链接的链接失效了? 2021-08-10 09:40:27 +08:00
suyl
09627451a1 jobid 2021-08-10 09:34:14 +08:00
suyl
3a907781ca aa 2021-08-04 16:30:30 +08:00
suyl
c60d5d6bfd aa 2021-08-04 15:14:56 +08:00
suyl
2d75a94b24 aa 2021-08-04 15:11:12 +08:00
suyl
d2e06c0231 aa 2021-08-03 17:54:46 +08:00
suyl
1331f22052 aa 2021-08-03 17:51:48 +08:00
suyl
3dc511f26b aa 2021-08-03 15:45:26 +08:00
suyl
8de2b13d5f aa 2021-08-03 15:39:38 +08:00
suyl
eeddcf214e aa 2021-08-03 15:25:21 +08:00
suyl
5a2bb4aacd aa 2021-08-03 15:04:26 +08:00
suyl
2af4dc7327 aa 2021-08-03 14:59:21 +08:00
suyl
9b8bc1c240 aa 2021-08-03 14:52:08 +08:00
suyl
aeee9731cd aa 2021-08-03 14:51:27 +08:00
suyl
7a6f3b20d7 aa 2021-08-03 14:28:38 +08:00
suyl
930c3908e1 aa 2021-08-03 14:10:12 +08:00
suyl
4974568f5a aa 2021-08-03 14:04:55 +08:00
suyl
9581139b91 aa 2021-08-03 13:59:19 +08:00
suyl
d7525a0bae aa 2021-08-03 13:50:33 +08:00
suyl
e11c25444c aa 2021-08-03 13:50:10 +08:00
suyl
ef3f7ff68b aa 2021-08-03 11:46:56 +08:00
suyl
9969299821 aa 2021-08-03 11:35:18 +08:00
suyl
464783d2ff aa 2021-08-03 11:33:09 +08:00
suyl
f3aaacae0a aa 2021-08-03 11:28:16 +08:00
suyl
8e44870cbf aa 2021-08-03 11:26:45 +08:00
suyl
b3e86e8e63 aa 2021-08-03 11:15:58 +08:00
suyl
55400e0b9e aa 2021-08-03 11:04:58 +08:00
suyl
9bbcfbe1dc a 2021-08-03 10:53:25 +08:00
suyl
d248870393 aa 2021-08-03 10:50:19 +08:00
suyl
41fc7ba11e aa 2021-08-03 10:08:16 +08:00
suyl
5c5a34aab7 aa 2021-08-02 17:35:35 +08:00
suyl
e44a4d854e aa 2021-08-02 17:33:01 +08:00
suyl
bc2ac8bed1 aa 2021-08-02 17:31:20 +08:00
suyl
b87b12f548 aa 2021-08-02 17:24:54 +08:00
suyl
895a17a46b aa 2021-08-02 17:20:25 +08:00
suyl
5231be8236 aa 2021-08-02 17:16:15 +08:00
suyl
a441c28bf5 aa 2021-08-02 16:03:39 +08:00
suyl
90d441d02f aa 2021-08-02 15:56:04 +08:00
suyl
63b9692adb aa 2021-08-02 15:48:06 +08:00
suyl
35eddc42a6 aa 2021-08-02 15:40:22 +08:00
suyl
468ffffe88 aa 2021-08-02 15:34:22 +08:00
suyl
51db0eee9f aa 2021-08-02 15:30:31 +08:00
suyl
0aa369db48 aa 2021-08-02 15:26:48 +08:00
suyl
dae0d38364 aa 2021-08-02 15:22:32 +08:00
suyl
b524dcc890 aa 2021-08-02 15:18:42 +08:00
suyl
fbc3c7ec8c aa 2021-08-02 15:06:15 +08:00
suyl
48a1b0d210 aa 2021-08-02 14:48:59 +08:00
suyl
5534fe5fb6 aa 2021-08-02 14:48:09 +08:00
suyl
051539f936 aa 2021-08-02 14:45:10 +08:00
suyl
f35d9d69ed aa 2021-08-02 14:44:33 +08:00
suyl
882d8eee59 aa 2021-08-02 14:35:34 +08:00
suyl
18f9feb2de aa 2021-08-02 14:25:26 +08:00
suyl
ddd9258a20 aa 2021-08-02 14:03:03 +08:00
suyl
1d894b763e aa 2021-08-02 13:54:18 +08:00
suyl
489c6b36d2 aa 2021-08-02 13:41:15 +08:00
suyl
a4b956c963 aa 2021-07-30 18:56:48 +08:00
suyl
9861e3edc5 aa 2021-07-30 18:48:03 +08:00
suyl
e55d4dfd4f aa 2021-07-30 18:42:17 +08:00
suyl
472508634a aagit 2021-07-30 18:36:33 +08:00
suyl
b38a5a7520 aa 2021-07-30 18:34:45 +08:00
suyl
6cd3be8dba a 2021-07-30 18:30:26 +08:00
suyl
b14c41722f a 2021-07-30 18:28:10 +08:00
suyl
9dbb64073a a 2021-07-30 18:24:53 +08:00
suyl
e99af06e67 aa 2021-07-30 18:18:35 +08:00
suyl
a1201f8fc9 a 2021-07-30 18:10:21 +08:00
suyl
922b3ab1d2 a 2021-07-30 18:07:13 +08:00
suyl
24505a930d aa 2021-07-30 18:01:05 +08:00
suyl
a7b790f37c aa 2021-07-30 17:57:28 +08:00
suyl
7bc76205eb aa 2021-07-30 17:56:24 +08:00
suyl
948cabcf52 aa 2021-07-30 17:40:45 +08:00
suyl
9f4786de45 a 2021-07-30 17:37:39 +08:00
suyl
6668ce23c7 aa 2021-07-30 17:28:50 +08:00
suyl
14de70f911 aa 2021-07-30 17:22:51 +08:00
suyl
d1c0a06730 aa 2021-07-30 14:36:04 +08:00
suyl
ee5f58f6f9 aa 2021-07-30 11:02:23 +08:00
suyl
143d3dc858 aa 2021-07-30 10:55:09 +08:00
suyl
e092178d32 aa 2021-07-30 10:49:44 +08:00
suyl
cceb2db107 aa 2021-07-30 10:05:25 +08:00
suyl
59d71369a9 aa 2021-07-30 09:40:23 +08:00
suyl
2d3ccf1878 aa 2021-07-30 09:39:24 +08:00
suyl
6f27c9b395 aa 2021-07-30 09:33:18 +08:00
suyl
bc20c5a1a7 aa 2021-07-30 09:28:58 +08:00
suyl
67a8509ec4 aa 2021-07-30 09:25:18 +08:00
suyl
a57e665cc7 aa 2021-07-30 09:17:51 +08:00
suyl
fe68ba1dac aa 2021-07-30 08:59:43 +08:00
suyl
952c912dbf aa 2021-07-29 18:53:45 +08:00
suyl
032d106d89 aa 2021-07-29 18:46:59 +08:00
suyl
bd23a4d42a aa 2021-07-29 18:37:28 +08:00
suyl
37440aa104 aa 2021-07-29 18:25:00 +08:00
suyl
b18672e92d aa 2021-07-29 18:11:20 +08:00
suyl
c8a1d09ba4 aa 2021-07-29 16:38:39 +08:00
suyl
99cac55563 rang 2021-07-29 15:59:01 +08:00
suyl
b29bdba37f aa 2021-07-29 15:43:38 +08:00
suyl
89c4769b69 aa 2021-07-29 15:39:02 +08:00
suyl
ab54bbba0e aa 2021-07-29 15:24:12 +08:00
suyl
2fab08a747 aa 2021-07-29 15:15:10 +08:00
suyl
f7281ee9a9 aa 2021-07-29 15:10:01 +08:00
suyl
eaff3970a0 aa 2021-07-29 15:00:35 +08:00
suyl
bc299677ad aa 2021-07-29 14:53:07 +08:00
suyl
17dfe9e9df a 2021-07-29 14:49:22 +08:00
suyl
2bc8c04bc6 aa 2021-07-28 11:43:05 +08:00
suyl
961245c883 aa 2021-07-22 15:15:49 +08:00
suyl
dda8b5c209 aa 2021-07-22 15:06:08 +08:00
suyl
c8678143c1 aa 2021-07-22 15:03:53 +08:00
suyl
68b6324365 aa 2021-07-22 14:59:59 +08:00
suyl
5190e42002 aa 2021-07-22 14:58:41 +08:00
suyl
1d048d11f3 aa 2021-07-22 14:03:42 +08:00
suyl
18e6a0f6be aa 2021-07-22 14:00:58 +08:00
suyl
fa0a934737 aa 2021-07-22 13:58:53 +08:00
suyl
d528a9ec08 aa 2021-07-22 13:53:42 +08:00
suyl
41a96433d9 aa 2021-07-22 13:48:22 +08:00
suyl
1a21344d89 aa 2021-07-22 13:43:07 +08:00
suyl
06c0dece69 aa 2021-07-22 12:07:33 +08:00
suyl
03a0294e9c aa 2021-07-22 11:59:57 +08:00
suyl
30f59387e4 a 2021-07-22 11:59:16 +08:00
suyl
078bdedfa9 aa 2021-07-22 11:57:16 +08:00
suyl
83cf5d536b aa 2021-07-22 11:38:12 +08:00
suyl
688710fb1c aa 2021-07-22 11:32:46 +08:00
suyl
1dd3d024ac aa 2021-07-22 11:00:37 +08:00
suyl
6b84c1658e aa 2021-07-22 10:57:54 +08:00
suyl
c7bc1abe3c aa 2021-07-22 10:52:35 +08:00
suyl
df4b2ad904 aa 2021-07-22 10:49:02 +08:00
suyl
e15e3ea14b aa 2021-07-22 10:42:08 +08:00
suyl
468b238555 aa 2021-07-22 10:38:30 +08:00
suyl
8060bc5c85 aa 2021-07-22 10:28:17 +08:00
suyl
a8fac9e339 aa 2021-07-22 10:24:05 +08:00
suyl
e4e114e9d4 aa 2021-07-22 10:17:14 +08:00
suyl
c09b5f0d8a aa 2021-07-22 10:16:54 +08:00
suyl
74b84bd21f aa 2021-07-22 10:10:42 +08:00
suyl
8c1bbd795a aa 2021-07-22 09:29:28 +08:00
suyl
2776f7ee0a aa 2021-07-21 18:47:54 +08:00
suyl
60b9a5f215 aa 2021-07-21 18:45:03 +08:00
suyl
4dd08d5255 aa 2021-07-21 18:37:20 +08:00
suyl
5f5acb4063 aa 2021-07-21 18:29:20 +08:00
suyl
61a271b297 aa 2021-07-21 18:27:21 +08:00
suyl
6d6fc074ad aa 2021-07-21 18:19:14 +08:00
suyl
a6b1a43a86 aa 2021-07-21 17:51:55 +08:00
suyl
b572c36868 aa 2021-07-21 17:44:52 +08:00
suyl
975c150a57 aa 2021-07-21 16:18:58 +08:00
suyl
85781aa3dc aa 2021-07-21 16:15:53 +08:00
suyl
74b033f785 aa 2021-07-21 16:15:41 +08:00
suyl
5b1584fbe0 aa 2021-07-21 15:44:07 +08:00
suyl
1738d535cb aa 2021-07-21 15:25:51 +08:00
suyl
50ef7f89f9 aa 2021-07-21 15:20:56 +08:00
suyl
6e9d746b40 aa 2021-07-21 15:14:16 +08:00
suyl
7106636263 aa 2021-07-21 14:54:38 +08:00
suyl
5ee7e6326c aa 2021-07-20 17:43:28 +08:00
suyl
807f16107a a 2021-07-20 17:29:35 +08:00
suyl
0cb262dace aa 2021-07-15 16:20:04 +08:00
suyl
88c7ce9f49 a 2021-07-14 16:23:37 +08:00
suyl
d192847ae9 aa 2021-07-14 15:47:13 +08:00
suyl
c4061d4c2d aa 2021-07-14 15:37:04 +08:00
suyl
f2fcb46f48 aa 2021-07-14 15:29:12 +08:00
suyl
7c7542ba91 aa 2021-07-14 15:07:04 +08:00
suyl
74cd4f6727 aa 2021-07-14 15:03:51 +08:00
suyl
956600b68f aa 2021-07-14 14:58:16 +08:00
suyl
a31aede139 aa 2021-07-14 14:54:37 +08:00
suyl
9c9b450dc7 test hear 2021-07-14 14:46:35 +08:00
suyl
3b0af01f75 aa 2021-07-12 15:53:22 +08:00
suyl
9a2ef79491 aa 2021-07-12 15:00:08 +08:00
suyl
98d26c4c45 aa 2021-07-12 14:53:56 +08:00
suyl
a888d04200 aa 2021-07-12 14:52:21 +08:00
suyl
3148422d6f aa 2021-07-09 18:53:55 +08:00
suyl
44b67ac9d4 aa 2021-07-09 18:45:58 +08:00
suyl
86d99338ed aa 2021-07-09 18:26:05 +08:00
suyl
b270f5e452 aa 2021-07-09 18:18:07 +08:00
suyl
4f4414d4f3 aa 2021-07-09 18:11:19 +08:00
suyl
50b1b8b31f aa 2021-07-09 16:34:54 +08:00
suyl
0304a3aa29 aa 2021-07-09 16:33:27 +08:00
suyl
35979a2e91 aa 2021-07-09 16:30:30 +08:00
suyl
f8af185573 aa 2021-07-09 16:22:40 +08:00
suyl
e2d447a56b aa 2021-07-09 16:20:13 +08:00
suyl
0a8211dd5b aa 2021-07-09 16:19:05 +08:00
suyl
e8ac03ce9c aa 2021-07-09 16:09:29 +08:00
suyl
88195e2216 aa 2021-07-09 16:06:36 +08:00
suyl
49a307744d aa 2021-07-09 16:03:35 +08:00
suyl
fee78529dd aa 2021-07-09 15:59:26 +08:00
suyl
756b904cb2 aa 2021-07-09 15:52:05 +08:00
suyl
1441394923 aa 2021-07-09 15:35:10 +08:00
suyl
65f3ac6330 aa 2021-07-09 15:22:25 +08:00
suyl
e392777487 test sound 2021-07-09 15:20:09 +08:00
suyl
b0e8104334 aa 2021-07-09 15:14:44 +08:00
suyl
4dfe19a9fb test sound 2021-07-09 15:11:04 +08:00
suyl
7076f09626 test sound 2021-07-09 15:08:08 +08:00
suyl
0a53f6b2b3 test sound 2021-07-09 15:01:46 +08:00
suyl
2ac8dcbdda aa 2021-07-09 11:40:54 +08:00
suyl
c23948b5fa aa 2021-07-09 11:09:35 +08:00
suyl
0fe256fc4e aa 2021-07-09 10:55:43 +08:00
suyl
671d3a676c aa 2021-07-09 10:52:12 +08:00
suyl
aad0c47ccf aa 2021-07-09 10:50:26 +08:00
suyl
c1c4af82e6 aa 2021-07-09 10:44:54 +08:00
suyl
42a60e8d04 aa 2021-07-09 10:40:55 +08:00
suyl
4fe9db5189 test v 2021-07-09 10:32:22 +08:00
suyl
71666ba57c aa 2021-07-09 10:21:59 +08:00
suyl
08c3e7b43c aa 2021-07-09 10:16:02 +08:00
suyl
3816a38538 aa 2021-07-09 10:15:30 +08:00
suyl
4fcc832f9d aa 2021-07-09 10:12:09 +08:00
suyl
bb3324e2c3 aa 2021-07-09 10:07:16 +08:00
suyl
2ab506d2e4 开机打印 2021-07-08 18:19:52 +08:00
suyl
eb731182fd 打印机服务器不建表 2021-07-07 16:57:15 +08:00
suyl
ac6882ef5e aa 2021-07-07 16:54:17 +08:00
suyl
a7b7a2aa3b Revert "aa"
This reverts commit 0ae9289386.
2021-07-07 16:43:19 +08:00
suyl
afac53027c aa 2021-07-06 11:55:20 +08:00
suyl
0ae9289386 aa 2021-07-05 14:37:21 +08:00
suyl
3e592bcbf2 qr test 2021-07-05 14:31:10 +08:00
suyl
10b4f5cdc6 aa 2021-07-05 14:14:33 +08:00
suyl
8f1694ee0d aa 2021-07-05 13:46:29 +08:00
suyl
f55c28b4be aa 2021-07-05 11:38:37 +08:00
suyl
de5c5f0c7f a 2021-07-05 10:58:07 +08:00
suyl
90d742771e aa 2021-07-05 10:52:29 +08:00
suyl
afb842bdc2 aa 2021-07-05 10:40:15 +08:00
suyl
bc85b2eb16 aa 2021-07-05 10:35:46 +08:00
suyl
4906344045 aa 2021-07-05 10:34:09 +08:00
suyl
6f300bd14f aa 2021-07-05 10:29:38 +08:00
suyl
17c696597c a 2021-07-05 10:28:07 +08:00
suyl
de4b215bd4 aa 2021-07-05 10:25:26 +08:00
suyl
aa99029c2a aa 2021-07-05 10:17:04 +08:00
suyl
73c3eea254 aa 2021-07-05 10:13:26 +08:00
suyl
4799c3c7c3 aa 2021-07-05 10:10:13 +08:00
suyl
f7cdf1dd00 aa 2021-07-05 10:08:44 +08:00
suyl
672d78ff0f aa 2021-07-05 10:04:56 +08:00
suyl
4b562dc015 aa 2021-07-05 10:01:15 +08:00
suyl
0567c6b063 aa 2021-07-05 09:56:38 +08:00
suyl
67aada2e62 aa 2021-07-05 09:54:47 +08:00
suyl
53569d3edc aa 2021-07-05 09:45:32 +08:00
suyl
490028e6b2 aa 2021-07-05 09:28:03 +08:00
suyl
75e8ee1422 aa 2021-07-05 09:25:36 +08:00
suyl
372b4e707a aa 2021-07-05 09:22:32 +08:00
suyl
eba64edbf3 aa 2021-07-05 09:19:06 +08:00
suyl
51fe6e674f aa 2021-07-05 09:15:39 +08:00
suyl
631c0d75ac aa 2021-07-05 09:10:45 +08:00
suyl
a456e97681 aa 2021-07-02 18:51:00 +08:00
suyl
a73a14f14f aa 2021-07-02 18:47:32 +08:00
suyl
7e3037bd0c aa 2021-07-02 18:42:01 +08:00
suyl
89c29c3b0c aa 2021-07-02 18:39:34 +08:00
suyl
905f06a045 aa 2021-07-02 18:36:01 +08:00
suyl
17895d4795 aa 2021-07-02 18:30:02 +08:00
suyl
48d0738488 aa 2021-07-02 18:18:45 +08:00
suyl
2fb6adb36f aa 2021-07-02 18:12:47 +08:00
suyl
0fde5836c3 aa 2021-07-02 18:06:33 +08:00
suyl
c40aa09330 aa 2021-07-02 17:51:37 +08:00
suyl
cae95cddb0 test qr 2021-07-02 17:48:31 +08:00
suyl
e1457fd94c test qr 2021-07-02 17:36:05 +08:00
suyl
7e7082aa7e test qr 2021-07-02 17:32:08 +08:00
suyl
983b9f0832 test qr 2021-07-02 17:25:12 +08:00
suyl
408a51c2aa test qr 2021-07-02 17:18:18 +08:00
suyl
19b95ef72e aa 2021-07-02 17:15:00 +08:00
suyl
4d84ea8764 aa 2021-07-02 17:07:32 +08:00
suyl
481de6b1b6 br 2021-07-02 16:56:58 +08:00
suyl
a9abdb257d aa 2021-07-02 16:51:58 +08:00
suyl
e776111d28 aa 2021-07-02 14:48:54 +08:00
suyl
92c12c9a37 aa 2021-07-02 14:21:19 +08:00
suyl
a2ff32ce31 试试不放语音 2021-07-02 13:51:07 +08:00
suyl
cf236cb103 aa 2021-07-02 10:13:51 +08:00
suyl
0505f67048 aa 2021-07-02 10:08:51 +08:00
suyl
dfbfcb576e aa 2021-07-02 10:05:21 +08:00
suyl
7c5072e086 aa 2021-07-02 09:52:39 +08:00
suyl
63a6250bfb aa 2021-07-02 09:30:50 +08:00
suyl
658c49c841 aa 2021-07-02 09:17:18 +08:00
suyl
c818001bfb aa 2021-07-01 17:37:06 +08:00
suyl
586b87916b aa 2021-07-01 17:27:40 +08:00
suyl
d01dc10ade aa 2021-07-01 17:23:10 +08:00
suyl
ddcf68f6d1 aa 2021-07-01 17:07:58 +08:00
suyl
46076df528 aa 2021-07-01 17:01:49 +08:00
suyl
31fa9cbb66 aa 2021-07-01 16:57:56 +08:00
suyl
a25daae4a1 aa 2021-07-01 16:55:00 +08:00
suyl
f26debfa1d aa 2021-07-01 16:36:15 +08:00
suyl
919bd7fa63 aa 2021-07-01 16:32:19 +08:00
suyl
f55afd8717 aa 2021-07-01 16:30:28 +08:00
suyl
ac03c5edbf aa 2021-07-01 16:27:46 +08:00
suyl
eeba4bef5a aa 2021-07-01 16:26:14 +08:00
suyl
843a6a272c aa 2021-07-01 16:23:46 +08:00
suyl
378084354d aa 2021-07-01 16:22:08 +08:00
suyl
65359b76d5 aa 2021-07-01 16:20:21 +08:00
suyl
22b7cc5f55 aa 2021-07-01 16:19:53 +08:00
suyl
3df772df44 aa 2021-07-01 16:18:06 +08:00
suyl
e7d06692fd test qr 2021-07-01 16:14:25 +08:00
suyl
35d4e813c4 aa 2021-07-01 15:56:19 +08:00
suyl
852baa28da test print 2021-07-01 15:54:37 +08:00
suyl
41937dde83 试试查状态 2021-07-01 15:24:22 +08:00
suyl
593716ee26 aa 2021-07-01 14:59:08 +08:00
suyl
315bad7e0d a 2021-07-01 14:40:42 +08:00
suyl
4dc034cde9 常量统一 2021-07-01 11:48:05 +08:00
suyl
d886b5191d parintmsg deleted 2021-07-01 11:13:00 +08:00
suyl
223b9b3acc aa 2021-06-30 18:22:02 +08:00
suyl
7871f8e82f aa 2021-06-30 18:18:45 +08:00
suyl
c265e62062 aa 2021-06-30 18:15:28 +08:00
suyl
3906afd51c aa 2021-06-30 18:14:02 +08:00
suyl
1d73a484d9 aa 2021-06-30 18:11:37 +08:00
suyl
702fa49cb5 aa 2021-06-30 18:09:52 +08:00
suyl
378de2c3b3 aa 2021-06-30 18:03:12 +08:00
suyl
56668169c6 aa 2021-06-30 17:51:53 +08:00
suyl
eb5ccea857 aa 2021-06-30 17:48:43 +08:00
suyl
05e727d091 aa 2021-06-30 17:36:26 +08:00
suyl
54e03ac047 aa 2021-06-30 17:34:43 +08:00
suyl
c96ecc37ac aa 2021-06-30 17:30:12 +08:00
suyl
b829467ab1 aa 2021-06-30 17:28:25 +08:00
suyl
4b7ac405c3 aa 2021-06-30 17:22:52 +08:00
suyl
91219ebc03 aa 2021-06-30 17:20:19 +08:00
suyl
cfad5bc3db aa 2021-06-30 17:11:54 +08:00
suyl
d7304d4591 aa 2021-06-30 17:10:24 +08:00
suyl
92827d1d01 testqr 2021-06-30 17:08:46 +08:00
suyl
03b951346b aa 2021-06-30 17:06:57 +08:00
suyl
c3033b1e86 test qr 2021-06-30 17:04:11 +08:00
suyl
491f9c6c57 aa 2021-06-30 17:00:12 +08:00
suyl
d2dd0812f5 aa 2021-06-30 16:57:51 +08:00
suyl
ff6fa11432 aa 2021-06-30 16:40:55 +08:00
suyl
1209a8d61d aa 2021-06-30 16:38:14 +08:00
suyl
d17a8a122a testqr 2021-06-30 16:35:43 +08:00
suyl
bd2a84ce19 aa 2021-06-30 16:25:27 +08:00
suyl
ee7b9cce08 aa 2021-06-30 16:22:11 +08:00
suyl
c20d538cf8 aa 2021-06-30 16:13:50 +08:00
suyl
f07db12d48 aa 2021-06-30 16:11:24 +08:00
suyl
b083aa7fcb aa 2021-06-30 16:09:18 +08:00
suyl
309549bc13 test qr 2021-06-30 15:53:07 +08:00
suyl
6dfa583ea0 test qr 2021-06-30 15:51:19 +08:00
suyl
0c66adb782 test qr 2021-06-30 15:48:19 +08:00
suyl
14584d9171 test qr 2021-06-30 15:40:37 +08:00
suyl
3f666ddb6b test qr 2021-06-30 15:04:26 +08:00
suyl
178a8ab4c4 aa 2021-06-30 15:02:03 +08:00
suyl
19290bebbe 测试二维码 2021-06-30 14:59:51 +08:00
suyl
83ae819b1a 标签替换测试 2021-06-30 13:50:39 +08:00
suyl
c80f85e43a aa 2021-06-30 11:23:25 +08:00
suyl
1d1759265a aa 2021-06-30 11:03:29 +08:00
suyl
e2f9e7ed38 aa 2021-06-30 10:44:24 +08:00
suyl
93d16237ba 尝试标签替换 2021-06-30 10:41:10 +08:00
suyl
fb42bb293e 标签替换 2021-06-30 10:22:38 +08:00
suyl
5d9ad35791 aa 2021-06-30 10:08:24 +08:00
suyl
482e48304c a 2021-06-29 13:45:08 +08:00
suyl
2ceabfc367 aa 2021-06-29 11:46:14 +08:00
suyl
1f2cc5172e data数据修改 2021-06-29 11:00:10 +08:00
suyl
8e7b4b56e1 aa 2021-06-29 10:49:46 +08:00
suyl
92aba744ff aa 2021-06-29 10:41:54 +08:00
suyl
688bd6e363 aa 2021-06-29 10:39:20 +08:00
suyl
8abcd3502b aa 2021-06-29 10:37:29 +08:00
suyl
0c312ecabc aa 2021-06-29 10:34:24 +08:00
suyl
b53eca2d3e test 2021-06-29 10:31:56 +08:00
suyl
b1b4d34eca aa 2021-06-29 10:27:34 +08:00
suyl
a1851188ad test 2021-06-29 10:19:58 +08:00
suyl
76996eca28 aa 2021-06-29 09:46:10 +08:00
suyl
a4d222a84e aa 2021-06-29 09:26:36 +08:00
suyl
9aae931af4 aa 2021-06-29 09:19:29 +08:00
suyl
ed7e2b2c69 aa 2021-06-29 09:16:47 +08:00
suyl
341afec0b7 aa 2021-06-29 09:13:43 +08:00
suyl
17aecd365f aa 2021-06-29 09:10:21 +08:00
suyl
91ac528f24 aa 2021-06-28 19:01:09 +08:00
suyl
ceb6411038 aa 2021-06-28 18:56:57 +08:00
suyl
ba1c3efcdb aa 2021-06-28 18:55:22 +08:00
suyl
fabdf33a3a aa 2021-06-28 18:51:29 +08:00
suyl
274b9c7cba aa 2021-06-28 18:46:37 +08:00
suyl
0540488e2f aa 2021-06-28 18:42:20 +08:00
suyl
360e274e60 修改一下配置? 2021-06-28 18:32:34 +08:00
suyl
7c2a8db309 aa 2021-06-28 18:27:03 +08:00
suyl
235b2264ef aa 2021-06-28 18:16:05 +08:00
suyl
53623954e7 aa 2021-06-28 17:56:34 +08:00
suyl
a2081c1384 aa 2021-06-28 17:54:23 +08:00
suyl
0cca12f938 打印机状态尝试改变 2021-06-28 17:48:24 +08:00
suyl
116e440e8f 心跳检测 2021-06-28 17:36:40 +08:00
suyl
2857b4fc22 xx 2021-06-28 16:55:17 +08:00
suyl
8ff6bdd064 准备打印 2021-06-28 16:52:15 +08:00
suyl
2552194dc1 处理打印信息 2021-06-28 16:38:43 +08:00
suyl
34f4368bc7 试着处理connmap 2021-06-28 14:39:38 +08:00
suyl
30f92b5384 aa 2021-06-28 14:28:04 +08:00
suyl
339829d73f 拿到eventtcp里 2021-06-28 13:33:19 +08:00
suyl
de004ee832 aa 2021-06-28 11:14:50 +08:00
suyl
d628da248d aa 2021-06-28 11:08:02 +08:00
suyl
d308e894c6 aa 2021-06-28 11:06:23 +08:00
suyl
6d3edda4bf aa 2021-06-28 11:05:26 +08:00
suyl
b95515675b aa 2021-06-28 10:44:13 +08:00
suyl
89ffc21a4c aa 2021-06-28 10:28:10 +08:00
suyl
c7b25b9f01 aa 2021-06-28 10:25:05 +08:00
suyl
2f5ecdf139 aa 2021-06-28 10:22:32 +08:00
suyl
c87a3c309a aa 2021-06-28 10:11:46 +08:00
suyl
2a36bb6896 aa 2021-06-28 10:01:53 +08:00
suyl
2a03e35f24 aa 2021-06-28 09:34:14 +08:00
suyl
49c2113a0a aa 2021-06-28 09:30:19 +08:00
suyl
5e15691604 aa 2021-06-28 09:28:37 +08:00
suyl
611fe395ff aa 2021-06-28 09:26:21 +08:00
suyl
7697e188ce aa 2021-06-28 09:09:16 +08:00
suyl
0ce55a7257 aa 2021-06-25 16:15:11 +08:00
suyl
c6ae872232 aa 2021-06-25 16:03:09 +08:00
suyl
6af6f4dcd5 aa 2021-06-24 15:20:37 +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
553 changed files with 35211 additions and 255014 deletions

3
.gitignore vendored
View File

@@ -14,5 +14,4 @@ param_parser.go
*.exe
*.exe~
.vscode
.idea
./swagger
.idea

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,8 +3,8 @@ package auth2
import (
"bytes"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"regexp"
"strings"
"time"
@@ -12,6 +12,7 @@ import (
"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"
"github.com/dchest/captcha"
)
@@ -32,18 +33,15 @@ const (
)
const (
AuthTypeNone = ""
AuthTypePassword = "localpass"
AuthTypeEmail = "email"
AuthTypeMobile = "mobile"
AuthTypeWXApp = "weixinapp" //微信小程序(商家版)
AuthTypeWXAppCaishi = "weixinappcs" //微信小程序(用户)
AuthTypeWXMini = "weixinmini" //微信小程序
AuthTypeNone = ""
AuthTypePassword = "localpass"
AuthTypeEmail = "email"
AuthTypeMobile = "mobile"
)
const (
DefTokenDuration = 7 * 24 * 2 * time.Hour // 正式TOKEN7天有效期
TmpTokenDuration = 30 * time.Minute // 临时TOKEN30分钟有效期
DefTokenDuration = 7 * 24 * time.Hour // 正式TOKEN7天有效期
TmpTokenDuration = 30 * time.Minute // 临时TOKEN30分钟有效期
MinCaptchaLen = 4
MaxCaptchaWidth = 400
MaxCaptchaHeight = 400
@@ -64,7 +62,6 @@ const (
UpdateUserTypeAdd = 1
UpdateUserTypeDelete = 2
UpdateUserTypeUpdate = 3
WeCartAppID = "wx4b5930c13f8b1170"
)
type IUserProvider interface {
@@ -162,7 +159,6 @@ func getFixedTokenName(token string) *AuthInfo {
func createAuthInfo(user IUser, authBindInfo *AuthBindEx) (authInfo *AuthInfo) {
token, tokenType := createToken(user, authBindInfo)
//user为空 tokenType=2
expireDuration := DefTokenDuration
authInfo = &AuthInfo{
AuthBindInfo: authBindInfo,
@@ -173,9 +169,11 @@ func createAuthInfo(user IUser, authBindInfo *AuthBindEx) (authInfo *AuthInfo) {
}
if user != nil {
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 {
expireDuration = TmpTokenDuration
authInfo.ExpiresAt = time.Now().Add(expireDuration).Unix()
globals.SugarLogger.Debugf("createAuthInfo authInfo:%s", utils.Format4Output(authInfo, true))
}
SetUserInfo(token, authInfo, expireDuration)
return authInfo
@@ -215,9 +213,6 @@ func SendVerifyCode(authToken, captchaID, captchaValue, authID string) (verfifyC
if handler := authers[authType]; handler == nil {
err = ErrIllegalAuthType
} else {
//if user, _ := dao.GetUserByID(dao.GetDB(), "mobile", authID); user != nil {
// return "", authInfo, fmt.Errorf("该用户已存在,请勿重复注册!")
//}
verfifyCode, err = handler.SendVerifyCode(authID)
}
}
@@ -248,8 +243,7 @@ func LoginInternal(ctx *Context, authType, authID, authIDType, authSecret string
}
realAuthID = user.GetID()
}
authBindEx, err = handler.VerifySecret(realAuthID, authSecret)
if err == nil {
if authBindEx, err = handler.VerifySecret(realAuthID, authSecret); err == nil {
if authBindEx == nil { // mobile, email会返回nil表示不会新建AuthBind实体
user = userProvider.GetUser(authID, authIDType)
authBindEx = &AuthBindEx{
@@ -263,18 +257,15 @@ func LoginInternal(ctx *Context, authType, authID, authIDType, authSecret string
// 返回authBind中UserID为空表示只是认证但本地没有记录这种情况会返回临时TOKEN
if authBindEx.UserHint != nil && authBindEx.UserID == "" {
// 利用得到受信任的信息查找用户
if authBindEx.UserHint.Mobile != "" {
user = userProvider.GetUser(authBindEx.UserHint.Mobile, UserIDMobile)
}
if user == nil && authBindEx.UserHint.Email != "" {
user = userProvider.GetUser(authBindEx.UserHint.Email, UserIDEmail)
}
if user != nil {
authBindEx.UserID = user.GetID()
}
if user2 := userProvider.GetUser(authBindEx.UserHint.Email, UserIDMobile); user2 != nil {
user = user2
}
// if authBindEx.UserHint.Mobile != "" {
// user = userProvider.GetUser(authBindEx.UserHint.Mobile, UserIDMobile)
// }
// if user == nil && authBindEx.UserHint.Email != "" {
// user = userProvider.GetUser(authBindEx.UserHint.Email, UserIDEmail)
// }
// if user != nil {
// authBindEx.UserID = user.GetID()
// }
} else if authBindEx.UserID != "" {
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())
}
//如果是小程序
if authType == AuthTypeWXMini { // || authType == AuthTypeWXApp 此处AuthTypeWXApp没用上
if authType == "weixinmini" || authType == "weixinapp" {
appID := strings.Split(authSecret, ",")[0]
// 菜市商家 // // // 京西商城
if appID == model.JXC4BusinessAppId || appID == "wx2d6949f724b2541d" || appID == "wx18111a41fd17f24f" || appID == model.JXC4AppId { //菜市或者果园
if authInfo.AuthBindInfo.UserID != "" {
binds, err := dao.GetUserBindAuthInfo(dao.GetDB(), authInfo.AuthBindInfo.UserID, 0, nil, "", "", []string{"wx2bb99eb5d2c9b82c", "wx4b5930c13f8b1170"})
if appID == "wxa4a76d7b4c88604e" || appID == "wx2d6949f724b2541d" || appID == "wx18111a41fd17f24f" { //菜市或者果园
if user != nil {
binds, err := dao.GetUserBindAuthInfo(dao.GetDB(), user.GetID(), 0, nil, "", "", "wx2bb99eb5d2c9b82c")
if err != nil {
return authInfo, err
}
@@ -298,29 +288,9 @@ func LoginInternal(ctx *Context, authType, authID, authIDType, authSecret string
} else {
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 {
err = ErrIllegalAuthType
@@ -335,59 +305,6 @@ func Login(ctx *Context, authType, authID, authIDType, authSecret string) (authI
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绑定新创建的用户
func BindUser(inauthInfo *AuthInfo, user IUser) (outauthInfo *AuthInfo, err error) {
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) {
globals.SugarLogger.Debugf("AddAuthBind user:%s, newAuthInfo:%s", utils.Format4Output(user, true), utils.Format4Output(newAuthInfo, true))
if user == nil || newAuthInfo == nil {
return ErrInternalErrror
}
@@ -424,10 +342,7 @@ func AddAuthBind(user IUser, newAuthInfo *AuthInfo) (err error) {
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】")
}
user, _ := dao.GetUserByID(dao.GetDB(), "mobile", mobile)
authInfo.AuthBindInfo.UserID = user.UserID
//handler.UnbindAuth(user.GetID(), newAuthInfo.GetAuthType(), newAuthInfo.GetAuthTypeID(), user.GetName())
err = handler.AddAuthBind(authInfo.AuthBindInfo, user.GetName())
@@ -438,6 +353,7 @@ func AddAuthBindWithMobile(authInfo *AuthInfo, mobile 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 {
err = handler.UnbindAuth(userID, authType, authTypeID, userName)
} else {
@@ -447,6 +363,7 @@ func UnbindAuth(userID, authType, authTypeID, userName string) (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 {
err = handler.Logout(authInfo)
}
@@ -488,6 +405,8 @@ func ClearUserToken(userID string) {
}
}
/////////////
func createToken(user IUser, authBindInfo *AuthBindEx) (token string, tokenType int) {
userID := TokenUserEmpty
userName := authBindInfo.AuthID
@@ -556,7 +475,7 @@ func DisableUser(userID, operatorUserName string) (err error) {
}
func GetUserBindAuthInfo(userID string) (authList []*model.AuthBind, err error) {
return dao.GetUserBindAuthInfo(dao.GetDB(), userID, model.AuthBindTypeAuth, nil, "", "", nil)
return dao.GetUserBindAuthInfo(dao.GetDB(), userID, model.AuthBindTypeAuth, nil, "", "", "")
}
func DeletedTokenInfoWithoutParam(authInfo *AuthInfo) (err error) {
@@ -569,3 +488,16 @@ func DeletedTokenInfoWithoutParam(authInfo *AuthInfo) (err error) {
}
return err
}
func CheckWeixinminiAuthBind(userID string) (err error) {
var (
db = dao.GetDB()
)
authBinds, err := dao.GetUserBindAuthInfo(db, userID, model.AuthBindTypeAuth, []string{"weixinmini", "weixinapp"}, "", "", "")
if len(authBinds) == 0 {
return fmt.Errorf("请绑定微信认证方式!")
} else {
return nil
}
return err
}

View File

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

View File

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

View File

@@ -4,13 +4,12 @@ import (
"git.rosy.net.cn/baseapi/platformapi/alipayapi"
"git.rosy.net.cn/jx-callback/business/auth2"
"git.rosy.net.cn/jx-callback/business/auth2/authprovider"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/globals/api"
)
const (
AuthType = "alipaycode"
AuthKey = "GHp3ojlVYRRu2XID4FX2ew=="
)
type Auther struct {
@@ -27,13 +26,17 @@ func init() {
}
func (a *Auther) VerifySecret(dummy, code string) (authBindEx *auth2.AuthBindEx, err error) {
globals.SugarLogger.Debugf("VerifySecret dummy:%s, code:%s", dummy, code)
tokenInfo, err := api.AliPayAPI.SystemAuthToken(alipayapi.GrantTypeCode, code, "")
if err == nil {
//userInfo, err2 := api.AliPayAPI.UserInfoShare(tokenInfo.AccessToken)
//if err = err2; err == nil {
if authBindEx, err = a.UnionFindAuthBind(AuthType, api.AliPayAPI.GetAppID(), nil, tokenInfo.UserID, tokenInfo.AlipayUserID, tokenInfo); err == nil {
authBindEx.AuthSecret = tokenInfo.AccessToken
authBindEx.AuthSecret2 = tokenInfo.RefreshToken
userInfo, err2 := api.AliPayAPI.UserInfoShare(tokenInfo.AccessToken)
if err = err2; err == nil {
if authBindEx, err = a.UnionFindAuthBind(AuthType, api.AliPayAPI.GetAppID(), nil, userInfo.UserID, "", userInfo); err == nil {
authBindEx.UserHint = &auth2.UserBasic{
Name: userInfo.NickName,
Avatar: userInfo.Avatar,
}
}
}
}
return authBindEx, err

View File

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

View File

@@ -4,6 +4,7 @@ import (
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/auth2"
"git.rosy.net.cn/jx-callback/business/auth2/authprovider"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/globals/api"
)
@@ -20,29 +21,17 @@ func init() {
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"]),
}
func (a *QRCodeAuther) VerifySecret(dummy, code string) (authBindEx *auth2.AuthBindEx, err error) {
globals.SugarLogger.Debugf("dingding qrcode VerifySecret code:%s", code)
userQRInfo, err := api.DingDingQRCodeAPI.GetUserInfoByCode(code)
if err == nil {
globals.SugarLogger.Debugf("dingding qrcode VerifySecret code:%s, userQRInfo:%s", code, utils.Format4Output(userQRInfo, false))
if authBindEx, err = a.UnionFindAuthBind(AuthTypeQRCode, api.DingDingQRCodeAPI.GetAppID(), []string{AuthTypeStaff, AuthTypeQRCode}, userQRInfo.OpenID, userQRInfo.UnionID, userQRInfo); err == nil {
authBindEx.UserHint = &auth2.UserBasic{
Name: userQRInfo.Nickname,
}
}
}
return authBindEx, err
}

View File

@@ -5,6 +5,7 @@ import (
"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"
)
@@ -22,6 +23,8 @@ func init() {
}
func (a *StaffAuther) VerifySecret(dummy, code string) (authBindEx *auth2.AuthBindEx, err error) {
globals.SugarLogger.Debugf("dingding staff VerifySecret code:%s", code)
userID, err := api.DingDingAPI.GetUserID(code)
if err == nil {
userDetail, err2 := api.DingDingAPI.GetUserDetail(userID.UserID)

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

@@ -3,6 +3,7 @@ package mobile
import (
"errors"
"fmt"
"math/rand"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/auth2"
@@ -44,7 +45,9 @@ func init() {
// 特殊接口
func (a *Auther) SendVerifyCode(mobileNumber string) (verifyCode string, err error) {
verifyCode = a.GenerateVerifyCode(mobileNumber)
verifyCode = fmt.Sprintf("%06d", rand.Intn(1000000))
globals.SugarLogger.Debugf("SendVerifyCode code: %v", 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,
@@ -68,10 +71,13 @@ func (a *Auther) SendVerifyCode(mobileNumber string) (verifyCode string, err err
}
func (a *Auther) VerifySecret(mobileNumber, code string) (authBindEx *auth2.AuthBindEx, err error) {
globals.SugarLogger.Debugf("VerifySecret mobileNumber:%s, code:%s", mobileNumber, code)
def := &authprovider.DefAuther{}
err = ErrVerifyCodeIsWrong
if (code == auth2.InternalAuthSecret ||
auth2.TestMobileMap[mobileNumber] == 1 && code == TestVerifyCode) ||
a.VerifyCode(mobileNumber, code) {
savedVerifyCode := def.LoadVerifyCode(mobileNumber)
if code == auth2.InternalAuthSecret ||
auth2.TestMobileMap[mobileNumber] == 1 && code == TestVerifyCode || (code != "" && savedVerifyCode != "" && code == savedVerifyCode) {
// || a.VerifyCode(mobileNumber, code)
err = nil
}
return nil, err

View File

@@ -10,6 +10,7 @@ import (
"git.rosy.net.cn/jx-callback/business/auth2/authprovider"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/globals"
)
const (
@@ -34,6 +35,7 @@ func init() {
}
func (a *Auther) VerifySecret(userID, passMD5 string) (authBindEx *auth2.AuthBindEx, err error) {
globals.SugarLogger.Debugf("localpass VerifySecret userID:%s", userID)
var authBind *model.AuthBind
if authBind, err = dao.GetAuthBind(dao.GetDB(), model.AuthBindTypeAuth, AuthType, userID); err == nil {
if err = a.checkPassword(authBind, passMD5); err == nil {

View File

@@ -7,15 +7,15 @@ import (
"git.rosy.net.cn/jx-callback/business/auth2"
"git.rosy.net.cn/jx-callback/business/auth2/authprovider"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/globals/api"
)
const (
AuthTypeWeixin = "wxqrcode" // 微信扫码
AuthTypeMP = "weixinsns" // 公众号
AuthTypeWXNative = "wxnative" // 微信APP
AuthTypeWxApp = "weixinapp" //app微信登录(商家版)
AuthTypeWxAppCaishi = "weixinappcs" //app微信登录(用户版)
AuthTypeWeixin = "wxqrcode" // 微信扫码
AuthTypeMP = "weixinsns" // 公众号
AuthTypeWXNative = "wxnative" // 微信APP
AuthTypeWxApp = "weixinapp" //app微信登录
)
type Auther struct {
@@ -24,11 +24,10 @@ type Auther struct {
}
var (
AutherObjWX *Auther
AutherObjMP *Auther
AutherObjNative *Auther
AutherObjApp *Auther
AutherObjCaiShiApp *Auther
AutherObjWX *Auther
AutherObjMP *Auther
AutherObjNative *Auther
AutherObjApp *Auther
)
var (
@@ -55,22 +54,15 @@ func init() {
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) {
globals.SugarLogger.Debugf("weixin VerifySecret id:%s secret:%s", secret, secret)
var openID, accessToken string
_, jsCode := SplitJsCode(secret)
if a.authType != AuthTypeWXNative {
state := id
code := jsCode
code := secret
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
@@ -86,7 +78,7 @@ func (a *Auther) VerifySecret(id, secret string) (authBindEx *auth2.AuthBindEx,
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 {
if authBindEx, err = a.UnionFindAuthBind(a.authType, a.getAPI().GetAppID(), []string{AuthTypeWeixin, AuthTypeMP, AuthTypeMini, AuthTypeWXNative, AuthTypeWxApp}, wxUserinfo.OpenID, wxUserinfo.UnionID, wxUserinfo); err == nil {
authBindEx.UserHint = &auth2.UserBasic{
Name: wxUserinfo.NickName,
Avatar: wxUserinfo.HeadImgURL,
@@ -104,23 +96,9 @@ func (a *Auther) getAPI() *weixinapi.API {
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

@@ -34,6 +34,8 @@ func init() {
}
func (a *MiniAuther) VerifySecret(dummy, jsCode string) (authBindEx *auth2.AuthBindEx, err error) {
globals.SugarLogger.Debugf("weixin mini VerifySecret jsCode:%s", jsCode)
appID, jsCode := SplitJsCode(jsCode)
sessionInfo, err := getWxApp(appID).SNSCode2Session(jsCode)
if err == nil {
@@ -48,15 +50,16 @@ func (a *MiniAuther) VerifySecret(dummy, jsCode string) (authBindEx *auth2.AuthB
// 特殊接口
func (a *MiniAuther) DecryptData(authInfo *auth2.AuthInfo, jsCode, encryptedData, iv string) (decryptedDataBase64 string, err error) {
globals.SugarLogger.Debugf("weixin mini DecryptData jsCode:%s, encryptedData:%s, iv:%s", jsCode, encryptedData, iv)
var sessionKey string
appID, jsCode := SplitJsCode(jsCode)
if jsCode != "" {
sessionInfo, err := getWxApp(appID).SNSCode2Session(jsCode)
if err == nil {
// if authBindEx, err := a.UnionFindAuthBind(AuthTypeMini, getWxApp(appID).GetAppID(), []string{AuthTypeMini}, sessionInfo.OpenID, "", nil); err == nil {
// if authBindEx.UserID != authInfo.GetID() {
// return "", fmt.Errorf("jsCode与token不匹配")
// }
// if authBindEx.UserID != authInfo.GetID() {
// return "", fmt.Errorf("jsCode与token不匹配")
// }
// } else {
// return "", err
// }
@@ -66,7 +69,7 @@ func (a *MiniAuther) DecryptData(authInfo *auth2.AuthInfo, jsCode, encryptedData
}
} else {
if authInfo.AuthBindInfo.Type != AuthTypeMini {
// return "", ErrAuthTypeShouldBeMini
return "", ErrAuthTypeShouldBeMini
}
sessionKey = authInfo.AuthBindInfo.UserData.(string)
}
@@ -85,15 +88,6 @@ func (a *MiniAuther) GetUserType() (userType int8) {
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
}

View File

@@ -2,6 +2,7 @@ package casbinauth
import (
jxmodel "git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/globals"
"github.com/astaxie/beego/client/orm"
"github.com/casbin/casbin/model"
"github.com/casbin/casbin/persist"
@@ -92,6 +93,7 @@ func (a *Adapter) clearAll(o orm.Ormer) (err error) {
// SavePolicy saves policy to database.
func (a *Adapter) SavePolicy(model model.Model) error {
globals.SugarLogger.Debugf("SavePolicy")
o := orm.NewOrm()
a.clearAll(o)

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*10 >= 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 "git.rosy.net.cn/重叠/相邻区间(如 [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))
}

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

@@ -0,0 +1,467 @@
package cms
import (
"encoding/json"
"errors"
"fmt"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxstore/event"
"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"
"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 QueryPrintList(printNo, printKey string, status, isOnline int64, page, size int64) ([]*model.Printer, int, error) {
prints, count, err := dao.QueryPrintList(dao.GetDB(), printNo, printKey, status, isOnline, page, size)
return prints, count, 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.GetPrintMsgs2(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,
Status: event.PrintMsgWait,
}
t, ok := event.PrintObject.GetPrintObj(printNo)
if ok {
t.Lock()
defer t.Unlock()
t.MsgMap[printNo] <- printMsg
printMsg.Status = event.PrintMsgAlreadyLoad
} /*else {
t = event.NewTcpClient()
event.BuildAllMap(t, printNo)
event.PrintObject[printNo] = t
t.Lock()
defer t.Unlock()
t.MsgMap[printNo] <- printMsg
printMsg.Status = event.PrintMsgAlreadyLoad
}*/
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.GetPrintMsgs2(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()
)
//看有没有
printers, _ := dao.GetPrinters(db, appID, printNo, 0, 0)
if 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
}
}

View File

@@ -14,6 +14,7 @@ import (
// todo 是否需要将Store.MarketManPhone与OperatorPhone成角色
func TransferLegacyWeixins(mobile string) (err error) {
globals.SugarLogger.Debugf("TransferLegacyWeixins mobile:%s", mobile)
if !globals.EnableWXAuth2 || globals.DisableWXAuth1 {
return nil
}
@@ -70,10 +71,11 @@ func TransferLegacyWeixins(mobile string) (err error) {
if user.Name == "" {
user.Name = user.GetMobile()
}
userList, _, err2 := dao.GetUsers(db, 0, "", nil, nil, []string{v.Tel}, 0, -1)
userList, _, err2 := dao.GetUsers(db, 0, "", "", nil, nil, []string{v.Tel}, 0, -1)
if err = err2; err != nil {
return err
}
// globals.SugarLogger.Debug(utils.Format4Output(user, false))
if len(userList) == 0 {
err = CreateUser(user, v.LastOperator)
} else {

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

@@ -1,31 +1,24 @@
package cms
import (
"encoding/json"
"fmt"
"git.rosy.net.cn/baseapi/platformapi/tencent_map"
"math"
"git.rosy.net.cn/baseapi/platformapi/mtunionapi"
"git.rosy.net.cn/baseapi/platformapi/tbunionapi"
"reflect"
"regexp"
"strconv"
"strings"
"time"
"git.rosy.net.cn/baseapi/platformapi/autonavi"
"git.rosy.net.cn/jx-callback/business/partner/purchase/ebai"
"git.rosy.net.cn/baseapi/platformapi/ejyapi"
"git.rosy.net.cn/baseapi/utils/errlist"
"git.rosy.net.cn/jx-callback/globals/api2"
"git.rosy.net.cn/baseapi/platformapi/dingdingapi"
"git.rosy.net.cn/jx-callback/business/auth2/authprovider/mobile"
"git.rosy.net.cn/jx-callback/business/authz/autils"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils/ddmsg"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
"git.rosy.net.cn/jx-callback/business/model"
@@ -46,64 +39,8 @@ type SysConfigLimit struct {
}
var (
serviceInfo map[string]interface{}
allowUpdatePlaceFieldsMap = map[string]bool{
"name": true,
"enabled": true,
"mtpsPrice": true,
}
serviceInfo map[string]interface{}
regexpMsgContentOpID = regexp.MustCompile(`"openid":"(.*?)"`)
receiveMsgUsersMap = map[string][]string{
SendMsgTypeOpenStoreRequest: []string{
"石锋",
// "x",
// "周扬",
},
SendMsgTypeSuggestRequest: []string{
"石锋",
// "x",
// "周扬",
// "苏尹岚",
},
}
needConfirmRequestMap = map[string]int{
SendMsgTypeOpenStoreRequest: 1,
}
SysConfigLimitMap = map[string]*SysConfigLimit{
model.ConfigSysEbaiBoxFee: &SysConfigLimit{
ValueType: reflect.Int,
MinValue: 0,
MaxValue: 500,
AfterChanged: func() (err error) {
_, err = dao.SetStoreMapSyncStatus(dao.GetDB(), []int{model.VendorIDEBAI}, nil, model.SyncFlagModifiedMask)
return err
},
},
model.ConfigSysMtwmBoxFee: &SysConfigLimit{
ValueType: reflect.Int,
MinValue: 0,
MaxValue: 500,
AfterChanged: func() (err error) {
_, err = dao.SetStoreMapSyncStatus(dao.GetDB(), []int{model.VendorIDMTWM}, nil, model.SyncFlagModifiedMask)
return err
},
},
model.ConfigSysMtwmSkuBoxFee: &SysConfigLimit{
ValueType: reflect.Int,
MinValue: 0,
MaxValue: 50,
AfterChanged: func() (err error) {
_, err = dao.SetStoreSkuSyncStatus(dao.GetDB(), model.VendorIDMTWM, nil, nil, model.SyncFlagModifiedMask)
return err
},
},
}
AutonaviKeyList = []string{autonavi.AMAPCyclingPlanKey1, autonavi.AMAPCyclingPlanKey2, autonavi.AMAPCyclingPlanKey3, autonavi.AMAPCyclingPlanKey4, autonavi.AMAPCyclingPlanKey5}
AutonaviKeyIndex = 0
)
func InitServiceInfo(version string, buildTime time.Time, gitCommit string) {
@@ -117,49 +54,65 @@ func InitServiceInfo(version string, buildTime time.Time, gitCommit string) {
"buildTime": buildTimeStr,
"gitCommit": gitCommit,
"metaData": map[string]interface{}{
"skuNamePrefix": model.SkuNamePrefixNames,
"skuNameUnit": model.UnitNames,
"skuSpecUnit": model.SpecUnitNames,
"skuStatus": model.SkuStatusName,
"storeDeliveryRangeType": model.DeliveryRangeTypeName,
"storeDeliveryType": model.DeliveryTypeName,
"storeStatus": model.StoreStatusName,
"categoryType": model.CategoryTypeName,
"vendorTypeName": model.VendorTypeName,
"vendorName": model.VendorChineseNames,
"vendorImg": model.VendorImg,
"vendorColors": model.VendorColors,
"orderStatus": model.OrderStatusName,
"waybillStatus": model.WaybillStatusName,
"orderTypeName": model.OrderTypeName,
"taskStatusName": tasksch.TaskStatusName,
"opRequestTypeName": model.RequestTypeName,
"opRequestStatusName": model.RequestStatusName,
"storeMsgSendStatusName": model.StoreMsgSendStatusName,
"shopChineseNames": model.ShopChineseNames,
"printerVendorInfo": model.PrinterVendorInfo,
"printerStatusName": partner.PrinterStatusName,
"purchaseVendorInfo": model.PurchaseVendorInfo,
"afsReasonTypeName": model.AfsReasonTypeName,
"afsAppealTypeName": model.AfsAppealTypeName,
"actTypeName": model.ActTypeName,
"actStatusName": model.ActStatusName,
"actCreateTypeName": model.ActCreateTypeName,
"storeAuditStatusName": model.StoreAuditStatusName,
"configTypeName": model.ConfigTypeName,
"autoSaleAt": AutoSaleAtStr,
"userTypeName": model.UserTypeName,
"storePriceTypeName": model.StorePriceTypeName,
"payStatusName": model.PayStatusName,
"refundStatusName": model.RefundStatusName,
"autoReplyTypeName": model.AutoReplyTypeName,
"complaintReasons": model.ComplaintReasons,
"supplementType": model.SupplementTypeName,
"operateType": model.OperateTypeName,
"thingType": model.ThingTypeName,
"apiFunctionName": model.ApiFunctionName,
"vendorStatus": model.VendorStatus,
"couponsStatus": model.CouponStatusName,
"ebaiSupplierID": ebai.EbaiSupplierIDMap,
"ebaiSupplierInfo": ebai.EbaiSupplierInfo,
"jobLimitCountType": `[{
"id":` + utils.Int2Str(model.JobLimitCountTypePO) +
`,"value": "每人一次"
},{
"id":` + utils.Int2Str(model.JobLimitCountTypePDO) +
`,"value": "每人每天一次"
},{
"id":` + utils.Int2Str(model.JobLimitCountTypePWO) +
`,"value": "每人每周一次"
},{
"id":` + utils.Int2Str(model.JobLimitCountTypeNoLimit) +
`,"value": "不限次"
}]`,
"billTypeNames": model.BillTypeNames,
"deliveryStatusName": model.DeliveryStatusName,
"cashbackName": model.CashbackName,
"consumeName": model.ConsumeName,
"txWaybillNames": model.TxWaybillNames,
"unionActTypeNames": map[int]map[int]interface{}{
model.VendorIDMTWM: map[int]interface{}{
mtunionapi.ActTypeQB: "券包推广",
},
model.VendorIDTB: map[int]interface{}{
tbunionapi.TbElmActTypeBDH: "本地化",
},
model.VendorIDPDD: map[int]interface{}{
1: "进行中的活动",
},
model.VendorIDJDShop: map[int]interface{}{
2: "进行中",
},
},
"unionOrderStatusName": model.UnionOrderStatusName,
},
}
}
@@ -169,7 +122,7 @@ func GetServiceInfo(ctx *jxcontext.Context) map[string]interface{} {
}
func GetPlaces(ctx *jxcontext.Context, keyword string, includeDisabled bool, params map[string]interface{}) ([]*model.Place, error) {
sql := `
sql := `
SELECT *
FROM place t1
WHERE 1 = 1
@@ -196,217 +149,29 @@ func GetPlaces(ctx *jxcontext.Context, keyword string, includeDisabled bool, par
sqlParams = append(sqlParams, params["level"])
}
sql += " ORDER BY t1.level, t1.name"
// globals.SugarLogger.Debug(sql)
places := []*model.Place{}
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)
return places, dao.GetRows(nil, &places, sql, sqlParams)
}
func GetCoordinateDistrictCode(ctx *jxcontext.Context, lng, lat float64) (code int, err error) {
return api.TencentMapAPI.GetCoordinateDistrictCode(lng, lat), nil
return api.AutonaviAPI.GetCoordinateDistrictCode(lng, lat), nil
}
func GetCoordinateCityInfo(ctx *jxcontext.Context, lng, lat float64) (name string, err error) {
name, _ = api.TencentMapAPI.GetCoordinateCityInfo(lng, lat)
name, _ = api.AutonaviAPI.GetCoordinateCityInfo(lng, lat)
return name, err
}
func SendMsg2Somebody(ctx *jxcontext.Context, mobileNum, verifyCode, msgType, msgContent string) (err error) {
if needConfirmRequestMap[msgType] == 1 {
if _, err = mobile.AutherObj.VerifySecret(mobileNum, verifyCode); err != nil {
return err
}
}
db := dao.GetDB()
//获取门店信息
var (
stores []*model.Store
authBinds []*model.AuthBind
order *model.GoodsOrder
storeName string
storeID int
vendorOrderID string
)
if mobileNum != "" {
sql := `
SELECT * FROM store WHERE (tel1 = ? OR tel2 = ?) AND deleted_at = ?
`
sqlParams := []interface{}{mobileNum, mobileNum, utils.DefaultTimeValue}
err = dao.GetRows(db, &stores, sql, sqlParams)
if len(stores) > 0 {
storeName = stores[0].Name
storeID = stores[0].ID
}
if storeID == 0 {
results := regexpMsgContentOpID.FindStringSubmatch(msgContent)
if len(results) > 0 {
sql3 := `
SELECT * FROM auth_bind WHERE auth_id = ? OR auth_id2 = ?
`
sqlParams3 := []interface{}{results[1], results[1]}
err = dao.GetRows(db, &authBinds, sql3, sqlParams3)
if len(authBinds) > 0 {
user, _ := dao.GetUserByID(db, "user_id", authBinds[0].UserID)
mobileNum = *user.Mobile
sqlParams4 := []interface{}{mobileNum, mobileNum, utils.DefaultTimeValue}
err = dao.GetRows(db, &stores, sql, sqlParams4)
if len(stores) > 0 {
storeName = stores[0].Name
storeID = stores[0].ID
}
}
}
}
} else {
results := regexpMsgContentOpID.FindStringSubmatch(msgContent)
if len(results) > 0 {
sql3 := `
SELECT * FROM auth_bind WHERE auth_id = ? OR auth_id2 = ?
`
sqlParams3 := []interface{}{results[1], results[1]}
err = dao.GetRows(db, &authBinds, sql3, sqlParams3)
if len(authBinds) > 0 {
user, _ := dao.GetUserByID(db, "user_id", authBinds[0].UserID)
mobileNum = *user.Mobile
sql4 := `
SELECT * FROM store WHERE (tel1 = ? OR tel2 = ?) AND deleted_at = ?
`
sqlParams4 := []interface{}{mobileNum, mobileNum, utils.DefaultTimeValue}
err = dao.GetRows(db, &stores, sql4, sqlParams4)
if len(stores) > 0 {
storeName = stores[0].Name
storeID = stores[0].ID
}
}
}
}
sql2 := `
SELECT *
FROM goods_order
WHERE IF(store_id <> '', store_id, jx_store_id) = ?
ORDER BY order_created_at DESC
LIMIT 1
`
sqlParams2 := []interface{}{storeID}
err = dao.GetRow(db, &order, sql2, sqlParams2)
if order != nil {
vendorOrderID = order.VendorOrderID
}
if storeID == 0 {
vendorOrderID = ""
}
msgContent = msgContent + " 门店名称:" + storeName + " 门店ID" + utils.Int2Str(storeID) + " 最新订单号:" + vendorOrderID
for _, v := range receiveMsgUsersMap[msgType] {
user, err2 := dao.GetUserByID(db, "name", v)
if err2 == nil {
ddmsg.SendUserMessage(dingdingapi.MsgTyeText, user.GetID(), msgType, msgContent)
} else if err == nil {
err = err2
}
}
return err
}
func checkSysConfig(key, value string) (err error) {
if limit := SysConfigLimitMap[key]; limit != nil {
if limit.ValueType == reflect.Int {
int64Value, err2 := strconv.ParseInt(value, 10, 64)
if err = err2; err == nil {
if int64Value < limit.MinValue || int64Value > limit.MaxValue {
err = fmt.Errorf("配置%s,值%s超范围[%d,%d]", key, value, limit.MinValue, limit.MaxValue)
}
}
}
}
return err
}
func onSysConfigChanged(key, value string) (err error) {
if limit := SysConfigLimitMap[key]; limit != nil && limit.AfterChanged != nil {
err = limit.AfterChanged()
}
return err
}
func checkConfig(opFlag int, configType, key, value string) (err error) {
switch configType {
case model.ConfigTypePricePack:
if value != "" {
pricePack := dao.PricePercentagePack2Obj(value)
if pricePack == nil {
err = fmt.Errorf("配置:%s不合法", value)
}
}
case model.ConfigTypeFreightPack:
if value != "" {
freightPack := dao.FreightDeductionPack2Obj(value)
if freightPack == nil {
err = fmt.Errorf("配置:%s不合法", value)
} else {
var lastStage *model.FreightDeductionItem
for _, v := range freightPack.FreightDeductionList {
if lastStage != nil && lastStage.DeductFreight > v.DeductFreight {
err = fmt.Errorf("免运设置不合理:门槛:%s,免运金额:%s,门槛:%s,免运金额:%s",
jxutils.IntPrice2StandardString(int64(lastStage.BeginPrice)), jxutils.IntPrice2StandardString(int64(lastStage.DeductFreight)),
jxutils.IntPrice2StandardString(int64(v.BeginPrice)), jxutils.IntPrice2StandardString(int64(v.DeductFreight)))
return err
}
lastStage = v
}
}
}
case model.ConfigTypeBank:
if value != "" {
if model.BankName[key] == "" {
err = fmt.Errorf("此银行代码:%s不支持请联系开发", value)
}
}
case model.ConfigTypeRole:
case model.ConfigTypeSys:
if opFlag&( /*model.SyncFlagNewMask|*/ model.SyncFlagDeletedMask) != 0 {
err = fmt.Errorf("系统参数只支持修改或添加,不支持删除")
} else {
err = checkSysConfig(key, value)
}
case model.ConfigTypeJxStore:
case model.ConfigTypeCookie:
case model.ConfigTypeDiscountCard:
default:
err = fmt.Errorf("当前只支持配置:%s, 传入的配置类型:%s", utils.Format4Output(model.ConfigTypeName, true), configType)
}
return err
}
func AddConfig(ctx *jxcontext.Context, key, configType, value string) (err error) {
if err = checkConfig(model.SyncFlagNewMask, configType, key, value); err != nil {
return err
}
// if err = checkConfig(model.SyncFlagNewMask, configType, key, value); err != nil {
// return err
// }
db := dao.GetDB()
conf := &model.NewConfig{
@@ -417,41 +182,21 @@ func AddConfig(ctx *jxcontext.Context, key, configType, value string) (err error
dao.WrapAddIDCULDEntity(conf, ctx.GetUserName())
err = dao.CreateEntity(db, conf)
if configType == model.ConfigTypeSys && err == nil {
err = onSysConfigChanged(key, value)
// 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
}
// 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("暂不支持删除银行")
@@ -459,7 +204,7 @@ func DeleteConfig(ctx *jxcontext.Context, key, configType string) (err error) {
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)
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")))
@@ -467,14 +212,7 @@ func DeleteConfig(ctx *jxcontext.Context, key, configType string) (err error) {
}
}
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()
}
@@ -485,7 +223,7 @@ func DeleteConfig(ctx *jxcontext.Context, key, configType string) (err error) {
})
}
if configType == model.ConfigTypeSys && err == nil {
err = onSysConfigChanged(key, "")
// err = onSysConfigChanged(key, "")
}
return err
}
@@ -494,9 +232,6 @@ func UpdateConfig(ctx *jxcontext.Context, key, configType, value string) (hint s
if key == "" {
return "", fmt.Errorf("修改配置必须给定key")
}
if err = checkConfig(model.SyncFlagModifiedMask, configType, key, value); err != nil {
return "", err
}
hint = "1"
db := dao.GetDB()
@@ -520,54 +255,12 @@ func UpdateConfig(ctx *jxcontext.Context, key, configType, value string) (hint s
}
switch configType {
case model.ConfigTypePricePack:
storeMapList, err := dao.GetStoresMapList(db, nil, nil, nil, model.StoreStatusAll, model.StoreIsSyncYes, key, "", "")
if err != nil {
dao.Rollback(db, txDB)
return "", err
}
dao.Commit(db, txDB)
vendorStoreMap := make(map[int][]int)
for _, v := range storeMapList {
vendorStoreMap[v.VendorID] = append(vendorStoreMap[v.VendorID], v.StoreID)
}
for vendorID, storeIDs := range vendorStoreMap {
if vendorID != model.VendorIDJX {
dao.SetStoreSkuSyncStatus(db, vendorID, storeIDs, nil, model.SyncFlagPriceMask)
} else {
hint, err = ReCalculateJxPrice(db, ctx, storeIDs)
}
}
case model.ConfigTypeFreightPack:
dao.Commit(db, txDB)
storeMapList, err := dao.GetStoresMapList(db, nil, nil, nil, model.StoreStatusAll, model.StoreIsSyncYes, "", "", "")
if err != nil {
return "", err
}
for _, v := range storeMapList {
var storeMapList2 []*model.StoreMap
if v.FreightDeductionPack == key {
storeMapList2 = append(storeMapList2, v)
}
if len(storeMapList2) > 0 {
task := tasksch.NewParallelTask("同步门店配送免运", tasksch.NewParallelConfig().SetIsContinueWhenError(true), ctx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
storeMap := batchItemList[0].(*model.StoreMap)
_, err = CurVendorSync.SyncStore(ctx, db, storeMap.VendorID, storeMap.StoreID, false, ctx.GetUserName())
return retVal, err
}, storeMapList2)
tasksch.HandleTask(task, nil, true).Run()
if len(storeMapList2) < 5 {
_, err = task.GetResult(0)
} else {
hint = task.GetID()
}
}
}
default:
dao.Commit(db, txDB)
}
if configType == model.ConfigTypeSys && err == nil {
err = onSysConfigChanged(key, value)
// err = onSysConfigChanged(key, value)
}
return hint, err
}
@@ -576,197 +269,105 @@ func QueryConfigs(key, configType, keyword string) (configList []*model.NewConfi
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) {
func InitStation(ctx *jxcontext.Context) (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}
db = dao.GetDB()
stationMap = make(map[string]*model.StationInfo)
stationEjyMap = make(map[string]*ejyapi.GetStationListResult)
addList []*model.StationInfo
updateList []*model.StationInfo
deleteList []*model.StationInfo
)
for {
// 骑手坐标
waybills, err := dao.GetWaybills(db, orderId, vendors)
if err != nil {
return nil, err
api.EjyAPI.SetTimestamp(time.Now().Unix())
if stations, err := dao.GetStationList(db); len(stations) > 0 && err == nil {
for _, v := range stations {
stationMap[v.StationID] = v
}
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
}
}
}
}
if getStationListResult, err := api.EjyAPI.GetStationList(); len(getStationListResult) > 0 && err == nil {
for _, v := range getStationListResult {
stationEjyMap[v.StationID] = v
if stationMap[v.StationID] == nil {
addList = append(addList, EjyStationToStationInfo(v))
} 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
}
}
}
updateList = append(updateList, stationMap[v.StationID])
}
// 当这个运单为假物流/门店真实自送/获取运单骑手信息为空的时候使用假的骑手信息
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
}
}
for _, v := range stationMap {
if stationEjyMap[v.StationID] == nil {
deleteList = append(deleteList, v)
}
}
task := tasksch.NewParallelTask("InitStation", tasksch.NewParallelConfig().SetParallelCount(1).SetIsContinueWhenError(true), ctx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
step := batchItemList[0].(int)
switch step {
case 0:
if len(addList) > 0 {
err = dao.CreateMultiEntities(db, addList)
}
case 1:
if len(updateList) > 0 {
task := tasksch.NewParallelTask("updateList", tasksch.NewParallelConfig().SetParallelCount(1).SetIsContinueWhenError(true), ctx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
station := batchItemList[0].(*model.StationInfo)
dao.UpdateEntity(db, station)
return retVal, err
}, updateList)
tasksch.HandleTask(task, nil, true).Run()
_, err = task.GetResult(0)
}
case 2:
if len(deleteList) > 0 {
task := tasksch.NewParallelTask("deleteList", tasksch.NewParallelConfig().SetParallelCount(1).SetIsContinueWhenError(true), ctx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
station := batchItemList[0].(*model.StationInfo)
dao.DeleteEntity(db, station)
return retVal, err
}, deleteList)
tasksch.HandleTask(task, nil, true).Run()
_, err = task.GetResult(0)
}
}
return retVal, err
}, []int{0, 1, 2})
tasksch.HandleTask(task, nil, true).Run()
_, err = task.GetResult(0)
return err
}
// 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
func EjyStationToStationInfo(station *ejyapi.GetStationListResult) (stationInfo *model.StationInfo) {
stationInfo = &model.StationInfo{
StationID: station.StationID,
StationName: station.StationName,
ProvinceName: station.ProvinceName,
ProvinceID: station.ProvinceID,
CityName: station.CityName,
Latitude: utils.Str2Float64(station.Latitude),
Longitude: utils.Str2Float64(station.Longitude),
Location: station.Location,
StarNum: station.StarNum,
Phone: station.Phone,
StationPic: station.StationPic,
StationBannerPic: station.StationBannerPic,
District: station.District,
CityID: station.CityID,
StationType: station.StationType,
}
*/
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
if station.Prices != nil {
if data, err := json.Marshal(station.Prices); err == nil {
stationInfo.Prices = string(data)
}
}
if station.Adverts != nil {
if data, err := json.Marshal(station.Adverts); err == nil {
stationInfo.Adverts = string(data)
}
}
return stationInfo
}
func GetStationList(ctx *jxcontext.Context, stationName string, cityCode int, lat, lng float64, oilCode string, sortType, offset, pageSize int) (pageInfo *model.PagedInfo, err error) {
return dao.GetStationInfoList(dao.GetDB(), stationName, cityCode, lat, lng, oilCode, sortType, offset, pageSize)
}

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()
}

2303
business/jxstore/cms/job.go Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -68,16 +68,17 @@ func GetStoreMessages(ctx *jxcontext.Context, msgIDs, storeIDs, types []int, fro
txDB, _ := dao.Begin(db)
defer dao.Commit(db, txDB)
var msgList []*model.Message
// globals.SugarLogger.Debug(sql)
if err = dao.GetRowsTx(txDB, &msgList, sql, sqlParams...); err == nil {
pagedInfo = &model.PagedInfo{
TotalCount: dao.GetLastTotalRowCount2(db, txDB),
TotalCount: dao.GetLastTotalRowCountTx(txDB),
Data: msgList,
}
}
return pagedInfo, err
}
func GetStoreMessageStatuses(ctx *jxcontext.Context, msgIDs, storeIDs, confirmStatuss []int, fromReadCount, toReadCount int, fromTime, toTime time.Time, keyword string, offset, pageSize int) (pagedInfo *model.PagedInfo, err error) {
func GetStoreMessageStatuses(ctx *jxcontext.Context, msgIDs, storeIDs []int, fromReadCount, toReadCount int, fromTime, toTime time.Time, keyword string, offset, pageSize int) (pagedInfo *model.PagedInfo, err error) {
sql := `
SELECT SQL_CALC_FOUND_ROWS
t1.*,
@@ -91,10 +92,6 @@ func GetStoreMessageStatuses(ctx *jxcontext.Context, msgIDs, storeIDs, confirmSt
sql += " AND t1.store_id IN (" + dao.GenQuestionMarks(len(storeIDs)) + ")"
sqlParams = append(sqlParams, storeIDs)
}
if len(confirmStatuss) > 0 {
sql += " AND t1.confirm_status IN (" + dao.GenQuestionMarks(len(confirmStatuss)) + ")"
sqlParams = append(sqlParams, confirmStatuss)
}
if len(msgIDs) > 0 {
sql += " AND t1.message_id IN (" + dao.GenQuestionMarks(len(msgIDs)) + ")"
sqlParams = append(sqlParams, msgIDs)
@@ -126,9 +123,11 @@ func GetStoreMessageStatuses(ctx *jxcontext.Context, msgIDs, storeIDs, confirmSt
txDB, _ := dao.Begin(db)
defer dao.Commit(db, txDB)
var msgStatusList []*MessageStatusExt
// globals.SugarLogger.Debug(sql)
// globals.SugarLogger.Debug(utils.Format4Output(sqlParams, false))
if err = dao.GetRowsTx(txDB, &msgStatusList, sql, sqlParams...); err == nil {
pagedInfo = &model.PagedInfo{
TotalCount: dao.GetLastTotalRowCount2(db, txDB),
TotalCount: dao.GetLastTotalRowCountTx(txDB),
Data: msgStatusList,
}
}

View File

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

View File

@@ -0,0 +1,519 @@
package cms
import (
"errors"
"fmt"
"git.rosy.net.cn/baseapi/platformapi/recharge_phone_bill"
"git.rosy.net.cn/baseapi/platformapi/tonglianpayapi"
"git.rosy.net.cn/jx-callback/business/jxstore/event"
"git.rosy.net.cn/jx-callback/business/q_bida"
"regexp"
"strings"
"time"
"git.rosy.net.cn/jx-callback/business/auth2"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxstore/financial"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/model"
)
func CreateOrder(ctx *jxcontext.Context, type1, orderType int, way string, price int, lng, lat float64, mobile, flowCode string) (orderID, errCode string, err error) {
var (
db = dao.GetDB()
order *model.Order
DayTimeBegin, DayTimeEnd = jxutils.GetDayTime()
)
if err = auth2.CheckWeixinminiAuthBind(ctx.GetUserID()); err != nil {
return "", errCode, err
}
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, txDB)
panic(r)
}
}()
if type1 == model.OrderTypeCash {
//如果用户没有对应账单信息就给他生成一条
userBill, err := dao.GetUserBill(db, ctx.GetUserID(), "")
if userBill == nil {
err = financial.AddUserBill(txDB, jxutils.GenBillID(), ctx.GetUserID())
}
if userBill.AccountBalance < price {
return "", model.ErrCodeAccountBalanceNotEnough, fmt.Errorf("用户余额不足!")
}
//用户一天只能提现一次
billExpends, err := dao.GetBillExpend(db, ctx.GetUserID(), model.BillTypeCash, DayTimeBegin, DayTimeEnd)
if err != nil {
return "", "", err
}
if len(billExpends) > 0 {
return "", "", fmt.Errorf("抱歉,一天只能提现一次!")
}
}
address, dCode, cCode, err := getAddressInfoFromCoord(db, lng, lat)
order = &model.Order{
OrderID: utils.Int64ToStr(jxutils.GenOrderNo()),
UserID: ctx.GetUserID(),
Type: type1,
OrderType: orderType,
Way: way,
Status: model.OrderStatusWait4Pay,
PayPrice: price,
Lng: lng,
Lat: lat,
Address: address,
DistrictCode: dCode,
CityCode: cCode,
}
// 话费充值
if order.OrderType == 7 {
// 校验充值编号
have, err := CheckMobileAndFlowCode(mobile, flowCode)
if err != nil {
return "", "", err
}
if !have {
return "", "", errors.New("充值模板错误")
}
order.Mobile = mobile
order.FlowCode = flowCode
order.RechargeStatus = 3 // 当前系统待充值
}
dao.WrapAddIDCULEntity(order, ctx.GetUserName())
if err = dao.CreateEntityTx(txDB, order); err != nil {
dao.Rollback(db, txDB)
}
dao.Commit(db, txDB)
return order.OrderID, errCode, err
}
func CheckMobileAndFlowCode(mobile, flowCode string) (bool, error) {
// 校验业务电话和充值号码是否正确
if mobile == "" || flowCode == "" {
return false, errors.New("充值电话费用号码/业务代码不能为空")
}
regRuler := "^1[3456789]{1}\\d{9}$"
if !regexp.MustCompile(regRuler).MatchString(mobile) {
return false, errors.New("电话号码格式校验错误")
}
switch mobile[0:4] {
case "1703", "1705", "1706": // 中国移动
if flowCode == recharge_phone_bill.FlowCodeY10Y100 || flowCode == recharge_phone_bill.FlowCodeY10Y200 {
return true, nil
}
case "1704", "1707", "1708", "1709": // 中国联通
if flowCode == recharge_phone_bill.FlowCodeL10Y50 || flowCode == recharge_phone_bill.FlowCodeL10Y100 || flowCode == recharge_phone_bill.FlowCodeL10Y200 {
return true, nil
}
case "1700", "1701", "1702 ": // 中国电信
if flowCode == recharge_phone_bill.FlowCodeD10Y50 || flowCode == recharge_phone_bill.FlowCodeD10Y100 || flowCode == recharge_phone_bill.FlowCodeD10Y200 {
return true, nil
}
}
switch mobile[0:3] {
case "139", "138", "137", "136", "135", "134", "150", "151", "152", "157", "158", "159 182", "183", "184", "187", "188", "147", "198", "178 ", "165": // 中国移动
if flowCode == recharge_phone_bill.FlowCodeY10Y100 || flowCode == recharge_phone_bill.FlowCodeY10Y200 {
return true, nil
}
case "130", "131", "132", "155", "156", "185", "186", "175", "176", "166", "171", "167": // 中国联通
if flowCode == recharge_phone_bill.FlowCodeL10Y50 || flowCode == recharge_phone_bill.FlowCodeL10Y100 || flowCode == recharge_phone_bill.FlowCodeL10Y200 {
return true, nil
}
case "133", "153", "173", "177", "180", "181", "189", "191", "199": // 中国电信
if flowCode == recharge_phone_bill.FlowCodeD10Y50 || flowCode == recharge_phone_bill.FlowCodeD10Y100 || flowCode == recharge_phone_bill.FlowCodeD10Y200 {
return true, nil
}
}
return false, errors.New("运营商查询错误/充值编码错误")
}
func Pay(ctx *jxcontext.Context, orderID string, payType int, vendorPayType, appId string, isChoose int) (result *financial.WxPayParam, err error) {
var (
tempPayprice int
tempPaymethod int
db = dao.GetDB()
tdb, _ = dao.Begin(db)
)
orderInfo, err := dao.GetOrderByID(db, orderID)
if err != nil {
return nil, err
}
var (
payHandler = &financial.PayHandler{
PayType: payType,
Ctx: ctx,
VendorPayType: vendorPayType,
}
)
if orderInfo.OrderType == 6 {
return nil, errors.New("不能余额充值余额")
}
// 用户是否使用余额抵消
if isChoose == 1 { // 余额抵消
// 查询用户余额
userBill, err := dao.GetUserBill(db, ctx.GetUserID(), "")
if err != nil || userBill == nil { // 出现错误或异常直接使用金钱支付
tempPayprice = orderInfo.PayPrice
tempPaymethod = model.OrderPayMethodWX
} else {
if userBill.AccountBalance-orderInfo.PayPrice >= 0 { // 余额大于支付金额,使用余额支付
switch orderInfo.OrderType { // 1-发任务2-会员月卡3-发快递4-提现5-会员年卡,6-使用充值到余额方式的订单,7-话费
case model.OrderTypeMember, model.OrderTypeMemberYear:
if err := financial.OnWXPayFinished(orderInfo); err != nil {
return nil, err
}
case model.OrderTypeDelivery:
call := &tonglianpayapi.CallBackResult{}
call.TrxID = "ziDingYi_" + utils.Int64ToStr(time.Now().Unix())
call.TrxStatus = tonglianpayapi.TrxStatusSuccess
if err := financial.OnWxPaySendPage(dao.GetDB(), orderInfo, call, 4); err != nil {
return nil, err
}
case model.OrderTypeMobile:
if err := financial.OnWxPayTelephone(orderInfo); err != nil {
return nil, err
}
default:
return nil, errors.New("其他待处理信息,联系管理员")
}
//账户支出
if err = financial.AddExpendUpdateAccount(tdb, userBill, model.BillTypePayByAccountBalance, orderInfo.PayPrice, 1); err != nil {
dao.Rollback(db, tdb)
return nil, err
}
return nil, nil
} else {
// 混合支付
tempPayprice = orderInfo.PayPrice - userBill.AccountBalance
tempPaymethod = model.OrderPayMethodMix
//账户支出
if err = financial.AddExpendUpdateAccount(tdb, userBill, model.BillTypePayByAccountBalance, userBill.AccountBalance, 1); err != nil {
dao.Rollback(db, tdb)
return nil, err
}
}
}
} else { // 原价给
tempPayprice = orderInfo.PayPrice
tempPaymethod = model.OrderPayMethodWX
}
orderInfo.PayPrice = tempPayprice
orderInfo.PayMethod = tempPaymethod
dao.UpdateEntity(dao.GetDB(), orderInfo, "PayPrice", "PayMethod")
payHandler.Order = orderInfo
//如果用户没有对应账单信息就给他生成一条
// 给用户创建一个银行卡账户
userBill, err := dao.GetUserBill(db, orderInfo.UserID, "")
if userBill == nil {
err = financial.AddUserBill(tdb, jxutils.GenBillID(), orderInfo.UserID)
}
err = payHandler.CreatePay(tdb, appId)
return payHandler.WxPayParam, err
}
//余额支付 微信补差值
func PayByBalance(ctx *jxcontext.Context, orderID string, isChoose, payType int, vendorPayType, appID string) (*financial.WxPayParam, string, error) {
var (
db = dao.GetDB()
)
//获取订单信息
orderInfo, err := dao.GetOrderByID(db, orderID)
if err != nil {
return nil, "获取订单信息失败", err
}
//获取用户 会员账户信息
userBill, err := dao.GetUserBill(db, orderInfo.UserID, "")
if err != nil {
return nil, "获取用户会员账户余额失败", err
}
if orderInfo.Status == model.OrderNotPay {
//需要充值余额支付的方式//todo 后续添加
//if orderInfo.OrderType == 6 {
// WxPayParam, err := Pay(ctx, orderInfo.OrderID, payType, vendorPayType, appID, orderInfo.PayPrice)
// if err != nil {
// return nil, "微信支付失败:", err
// }
// return WxPayParam, "", err
//}
//快递混合支付
if orderInfo.OrderType == model.OrderTypeDelivery {
if isChoose == model.PayChooseBalance {
// (1)使用余额且 余额大于支付金额
if userBill.AccountBalance > orderInfo.PayPrice {
globals.SugarLogger.Debug("进入余额支付部分")
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
panic(r)
}
}()
//增加账单 余额减去相应金额
money := userBill.AccountBalance - orderInfo.PayPrice
if err = dao.UpdateUserBill(userBill.UserID, money); err != nil {
return nil, "余额支付失败", err
}
//更新订单状态
orderInfo.PayMethod = 1
orderInfo.Status = 110
if _, err := dao.UpdateEntityTx(txDB, orderInfo, "PayMethod"); err != nil {
dao.Rollback(db, txDB)
return nil, "更新order.PayMethod状态失败", err
}
if _, err := dao.UpdateEntityTx(txDB, orderInfo, "Status"); err != nil {
dao.Rollback(db, txDB)
return nil, "更新order.Status状态失败", err
}
//todo 后续需增加其他订单类型
//更新快递 订单状态
temp_vendor_status := 4
if _, err := dao.SetUserVendorOrderStatus(txDB, orderInfo.OrderID, temp_vendor_status); err != nil {
dao.Rollback(db, txDB)
return nil, "更新user_vendor_order状态失败", err
}
dao.Commit(db, txDB)
//再次从数据库获取order、userOrder
orderNew, err := dao.GetOrderByID(db, orderID)
if err != nil {
return nil, "获取orderNew失败", err
}
userOrder, err := dao.GetUserVendorOrder(db, orderNew.UserID, orderNew.OrderID)
if err != nil {
return nil, "获取userOrder失败", err
}
//快递单 同步到qbd
if orderNew.Status == 110 && userOrder.OrderStatus == 4 {
if err := q_bida.CreateOrder2QBiDa(userOrder, orderInfo.OrderID); err != nil {
return nil, "", err
}
} else {
return nil, "order/user_vendor_order更新状态出错", nil
}
} else {
//2用户选中余额 但余额<订单总价 需混合微信支付
if userBill.AccountBalance == 0 {
WxPayParam, err := Pay(ctx, orderInfo.OrderID, payType, vendorPayType, appID, orderInfo.PayPrice)
if err != nil {
return nil, "微信支付失败:", err
}
return WxPayParam, "", err
} else if userBill.AccountBalance > 0 {
//2用户使用余额剩余微信支付
totalPrice := orderInfo.PayPrice //订单原价
needPay := totalPrice - userBill.AccountBalance //需支付金额
WxPayParam, err := Pay(ctx, orderInfo.OrderID, payType, vendorPayType, appID, needPay)
if err != nil {
return nil, "微信支付失败:", err
}
return WxPayParam, "", err
}
}
}
if isChoose == model.PayNotChooseBalance {
//3不选中余额支付 即直接微信支付
WxPayParam, err := Pay(ctx, orderInfo.OrderID, payType, vendorPayType, appID, orderInfo.PayPrice)
if err != nil {
return nil, "微信支付失败:", err
}
return WxPayParam, "", err
}
}
}
return nil, "", err
}
func Cash(ctx *jxcontext.Context, orderID string, payType int, vendorPayType string) (errCode string, err error) {
var (
db = dao.GetDB()
order = &model.Order{
OrderID: orderID,
}
payHandler = &financial.PayHandler{
PayType: payType,
Ctx: ctx,
VendorPayType: vendorPayType,
}
)
err = dao.GetEntity(db, order, "OrderID")
if err != nil {
return errCode, err
}
if order.ID == 0 {
return errCode, fmt.Errorf("未找到此订单!")
}
payHandler.Order = order
err = payHandler.CreateRefund()
return errCode, err
}
func GetOrders(ctx *jxcontext.Context, orderID, userID string, orderType int, cityCodes []int, fromTime, toTime, keyword string, offset, pageSize int) (pageInfo *model.PagedInfo, err error) {
return dao.GetOrders(dao.GetDB(), orderID, userID, orderType, cityCodes, utils.Str2Time(fromTime), utils.Str2Time(toTime), keyword, offset, pageSize)
}
//id获取订单详情(单条查询)
//func GetOrderByID(ctx *jxcontext.Context, orderID int) (errMsg string, err error) {
// //var db = dao.GetDB()
// if _, err := dao.GetOrderByID(dao.GetDB(), orderID); err != nil {
// return "id获取订单详情失败", err
// }
// return "", err
//}
func FinishedCashOrders(ctx *jxcontext.Context, orderIDs []string) (err error) {
var (
db = dao.GetDB()
)
for _, orderID := range orderIDs {
order := &model.Order{
OrderID: orderID,
}
dao.GetEntity(db, order, "OrderID")
if order.ID != 0 && order.Status == model.OrderStatusWait4Pay {
order.PayFinishedAt = time.Now()
order.Comment = "手动转账"
order.Status = model.OrderStatusFinished
dao.UpdateEntity(db, order, "PayFinishedAt", "Comment", "Status")
}
}
return err
}
func GetPayStatistics(ctx *jxcontext.Context, userID string, pop int, cityCodes []int, mobile, fromTime, toTime string, consumeTypes []int) (getPayStatisticsResult *dao.GetPayStatisticsResult, err error) {
var (
db = dao.GetDB()
)
return dao.GetPayStatistics(db, userID, pop, cityCodes, mobile, utils.Str2Time(fromTime), utils.Str2Time(toTime), consumeTypes)
}
func GetManageStatisticsImg(ctx *jxcontext.Context, cityCodes []int, fromTime, toTime string, jobIDs []int) (getManageStatistics []*dao.GetManageStatisticsResult, err error) {
var (
db = dao.GetDB()
fromTimeT = utils.Str2Time(fromTime)
toTimeT = utils.Str2Time(toTime)
)
for i := 1; i < utils.Float64TwoInt(toTimeT.Sub(fromTimeT).Hours()/24)+1; i++ {
getManageStatisticsResult, _ := dao.GetManageStatistics(db, cityCodes, fromTimeT.AddDate(0, 0, i-1), jobIDs)
getManageStatistics = append(getManageStatistics, getManageStatisticsResult)
}
return getManageStatistics, err
}
func GetManageStatisticsJob(ctx *jxcontext.Context, cityCodes []int, fromTime, toTime string, jobIDs []int, offset, pageSize int) (paged *model.PagedInfo, err error) {
var (
db = dao.GetDB()
)
return dao.GetManageStatisticsJob(db, cityCodes, utils.Str2Time(fromTime), utils.Str2Time(toTime), jobIDs, offset, pageSize)
}
func NewUnionOrder(unionOrder *model.UnionOrder, orderStatus *model.UnionOrderStatus) (err error) {
var (
db = dao.GetDB()
userID string
)
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, txDB)
panic(r)
}
}()
userBinds, err := dao.GetUserUnionBind(db, "", unionOrder.VendorID, unionOrder.PID)
if err != nil {
dao.Rollback(db, txDB)
return err
}
if len(userBinds) == 0 {
userID = unionOrder.PID
} else {
userID = userBinds[0].UserID
}
unionOrder.UserID = userID
dao.WrapAddIDCULEntity(unionOrder, jxcontext.AdminCtx.GetUserName())
if err = dao.CreateEntityTx(txDB, unionOrder); err != nil {
dao.Rollback(db, txDB)
return err
}
dao.WrapAddIDCULEntity(orderStatus, jxcontext.AdminCtx.GetUserName())
if err = dao.CreateEntityTx(txDB, orderStatus); err != nil {
dao.Rollback(db, txDB)
return err
}
dao.Commit(db, txDB)
//发消息
if err == nil {
orderMessage(unionOrder)
}
return err
}
func ChangeUnionOrder(unionOrder *model.UnionOrder, orderStatus *model.UnionOrderStatus) (err error) {
var (
db = dao.GetDB()
)
globals.SugarLogger.Debugf("ChangeUnionOrder1, unionorder: %v", utils.Format4Output(unionOrder, true))
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, txDB)
panic(r)
}
}()
unionOrder.Status = orderStatus.Status
globals.SugarLogger.Debugf("ChangeUnionOrder2, unionorder: %v", utils.Format4Output(unionOrder, true))
if _, err = dao.UpdateEntityTx(txDB, unionOrder, "Status"); err != nil {
dao.Rollback(db, txDB)
fmt.Println("err1", err)
return err
}
dao.WrapAddIDCULEntity(orderStatus, jxcontext.AdminCtx.GetUserName())
if err = dao.CreateEntityTx(txDB, orderStatus); err != nil {
dao.Rollback(db, txDB)
fmt.Println("err2", err)
return err
}
dao.Commit(db, txDB)
//发消息
if err == nil {
orderMessage(unionOrder)
}
return err
}
func orderMessage(unionOrder *model.UnionOrder) {
content := new(strings.Builder)
content.WriteString("您有[")
content.WriteString(model.VendorChineseNames[unionOrder.VendorID])
content.WriteString("]平台的推广订单:")
content.WriteString(unionOrder.VendorOrderID)
content.WriteString("。")
content.WriteString(model.UnionOrderStatusName[unionOrder.Status])
content.WriteString("。预计返佣:")
content.WriteString(jxutils.IntPrice2StandardString(int64(unionOrder.PromotionAmount)))
content.WriteString("元。")
event.SendSysMessageSimple(content.String(), unionOrder.UserID)
}
func GetMyUnionOrders(ctx *jxcontext.Context, statuss []int, vendorID, offset, pageSize int) (page *model.PagedInfo, err error) {
return dao.GetMyUnionOrders(dao.GetDB(), ctx.GetUserID(), statuss, vendorID, offset, pageSize)
}
func GetUnionOrders(ctx *jxcontext.Context, vendorIDs, statuss []int, beginTime, endTime, keyword string, offset, pageSize int) (page *model.PagedInfo, err error) {
return dao.GetUnionOrdersPage(dao.GetDB(), vendorIDs, statuss, utils.Str2Time(beginTime), utils.Str2Time(endTime), keyword, offset, pageSize)
}

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

@@ -1,16 +1,9 @@
package permission
package cms
import (
"fmt"
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
"git.rosy.net.cn/jx-callback/globals/api2"
"strings"
"time"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
@@ -18,17 +11,10 @@ import (
func GetMenu(ctx *jxcontext.Context, userID string) (menus []*model.Menu, err error) {
if userID == "" {
return dao.GetMenu(dao.GetDB(), "", 0, 0, userID)
return dao.GetMenu(dao.GetDB(), "", 0, userID)
} else {
if user, err := dao.GetUserByID(dao.GetDB(), "user_id", userID); err == nil {
if user.Type&model.UserTypeRole != 0 {
return dao.GetMenuWithUser(dao.GetDB(), "", 0, 0, userID)
} else {
return dao.GetMenu(dao.GetDB(), "", 0, 0, "")
}
}
return dao.GetMenuWithUser(dao.GetDB(), "", 0, userID)
}
return dao.GetMenu(dao.GetDB(), "", 0, 0, userID)
}
func AddMenu(ctx *jxcontext.Context, menu *model.Menu) (err error) {
@@ -41,7 +27,7 @@ func AddMenu(ctx *jxcontext.Context, menu *model.Menu) (err error) {
if menu.Name == "" || menu.Level == 0 {
return fmt.Errorf("添加失败menu 名称和等级必须有值!")
}
menus, err := dao.GetMenu(db, menu.Name, menu.Level, 0, "")
menus, err := dao.GetMenu(db, menu.Name, menu.Level, "")
if len(menus) > 0 {
return fmt.Errorf("添加失败!已存在相同名称的 menu name : %v", menu.Name)
}
@@ -91,36 +77,15 @@ func UpdateMenu(ctx *jxcontext.Context, menuID int, payload map[string]interface
return num, err
}
func GetRole(ctx *jxcontext.Context, name string) (roles []*model.Role, err error) {
var (
db = dao.GetDB()
)
roles, err = dao.GetRole(db, name, "")
task := tasksch.NewParallelTask("GetRole", tasksch.NewParallelConfig().SetIsContinueWhenError(true), ctx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
v := batchItemList[0].(*model.Role)
if v.CityCodes != "" {
if cityInfos, err := dao.GetPlaces(db, jxutils.StrListToIntList(strings.Split(v.CityCodes, ","))); err == nil {
v.CityInfo = cityInfos
}
}
if v.StoreIDs != "" {
if stores, err := dao.GetStoreList(db, jxutils.StrListToIntList(strings.Split(v.StoreIDs, ",")), nil, nil, nil, nil, ""); err == nil {
v.Stores = stores
}
}
return retVal, err
}, roles)
tasksch.HandleTask(task, nil, false).Run()
task.GetResult(0)
return roles, err
func GetRole(ctx *jxcontext.Context) (roles []*model.Role, err error) {
return dao.GetRole(dao.GetDB(), "")
}
func AddRole(ctx *jxcontext.Context, name string) (err error) {
var (
db = dao.GetDB()
)
roles, err := dao.GetRole(db, "", name)
roles, err := dao.GetRole(db, name)
if len(roles) > 0 {
return fmt.Errorf("添加失败!已存在相同名称的 role name : %v", name)
}
@@ -140,18 +105,10 @@ func AddRole(ctx *jxcontext.Context, name string) (err error) {
return err
}
func UpdateRole(ctx *jxcontext.Context, roleID int, name string, isDelete bool, brandID int, cityCodes, storeIDs []int) (num int64, err error) {
func UpdateRole(ctx *jxcontext.Context, roleID int, name string, isDelete bool) (num int64, err error) {
var (
db = dao.GetDB()
cityCodesStr []string
storeIDsStr []string
db = dao.GetDB()
)
for _, v := range cityCodes {
cityCodesStr = append(cityCodesStr, utils.Int2Str(v))
}
for _, v := range storeIDs {
storeIDsStr = append(storeIDsStr, utils.Int2Str(v))
}
if roleID == 1 {
return 0, fmt.Errorf("管理员不允许修改!")
}
@@ -172,10 +129,7 @@ func UpdateRole(ctx *jxcontext.Context, roleID int, name string, isDelete bool,
role.Name = name
role.UpdatedAt = time.Now()
role.LastOperator = ctx.GetUserName()
role.BrandID = brandID
role.CityCodes = strings.Join(cityCodesStr, ",")
role.StoreIDs = strings.Join(storeIDsStr, ",")
num, err = dao.UpdateEntity(db, role, "Name", "UpdatedAt", "LastOperator", "BrandID", "CityCodes", "StoreIDs")
num, err = dao.UpdateEntity(db, role, "Name", "UpdatedAt", "LastOperator")
} else {
role.DeletedAt = time.Now()
num, err = dao.UpdateEntity(db, role, "DeletedAt")
@@ -217,7 +171,7 @@ func UpdateUserRole(ctx *jxcontext.Context, userIDs []string, roleIDs []int) (er
}
nowRoleIDMap[nowRoleID] = 1
}
for roleID, _ := range roleIDMap {
for _, roleID := range roleIDMap {
if nowRoleIDMap[roleID] == 0 {
addUserRoleMap[userID] = append(addUserRoleMap[userID], roleID)
}
@@ -254,12 +208,6 @@ func UpdateUserRole(ctx *jxcontext.Context, userIDs []string, roleIDs []int) (er
}
}
}
for _, v := range userIDs {
if user, err := dao.GetUserByID(db, "user_id", v); err == nil {
user.Type = user.Type | model.UserTypeRole
dao.UpdateEntity(db, user, "Type")
}
}
dao.Commit(db, txDB)
return err
}
@@ -297,9 +245,9 @@ func UpdateRoleMenu(ctx *jxcontext.Context, roleIDs, menuIDs []int) (err error)
}
nowMenuIDMap[nowMenuID] = 1
}
for menuID, _ := range menuIDMap {
for _, menuID := range menuIDMap {
if nowMenuIDMap[menuID] == 0 {
addRoleMenuMap[roleID] = append(addRoleMenuMap[roleID], menuID)
addRoleMenuMap[menuID] = append(addRoleMenuMap[menuID], menuID)
}
}
}
@@ -337,74 +285,3 @@ func UpdateRoleMenu(ctx *jxcontext.Context, roleIDs, menuIDs []int) (err error)
dao.Commit(db, txDB)
return err
}
func GetUserStoresResultMap(userID string) (resultMap map[int]int, err error) {
var (
db = dao.GetDB()
)
resultMap = make(map[int]int)
user, _ := dao.GetUserByID(db, "user_id", userID)
if user != nil && user.BindStoreID != "" {
for _, v := range strings.Split(user.BindStoreID, ",") {
resultMap[utils.Str2Int(v)] = utils.Str2Int(v)
}
return resultMap, err
}
userRoles, err2 := dao.GetUserRole2(db, []string{userID}, nil)
err = err2
for _, v := range userRoles {
var (
brandIDs, cityCodes, storeIDs []int
)
if v.CityCodes == "" && v.StoreIDs == "" {
continue
}
if v.BrandID != 0 {
brandIDs = append(brandIDs, v.BrandID)
}
if v.CityCodes != "0" && v.CityCodes != "" {
cityCodes = append(cityCodes, jxutils.StrListToIntList(strings.Split(v.CityCodes, ","))...)
}
if v.StoreIDs != "" {
storeIDs = append(storeIDs, jxutils.StrListToIntList(strings.Split(v.StoreIDs, ","))...)
}
if stores, err := dao.GetStoreList(db, storeIDs, cityCodes, nil, brandIDs, nil, ""); len(stores) > 0 && err == nil {
for _, v := range stores {
resultMap[v.ID] = v.ID
}
}
}
roleList, _ := api2.RoleMan.GetUserRoleList(userID)
for _, v := range roleList {
resultMap[v.StoreID] = v.StoreID
}
return resultMap, err
}
func IsRoled(ctx *jxcontext.Context) bool {
if ctx.GetUserName() != "jxadmin" {
userRole, _ := dao.GetUserRole(dao.GetDB(), []string{ctx.GetUserID()}, nil)
for _, v := range userRole {
if v.RoleID == model.YES {
return false
}
}
return true
/*if user, err := dao.GetUserByID(dao.GetDB(), "user_id", ctx.GetUserID()); err == nil {
if user.Type&model.UserTypeRole != 0 {
return true
}
}*/
}
return false
}
func IsRoledByUserID(userID string) bool {
if user, err := dao.GetUserByID(dao.GetDB(), "user_id", userID); err == nil {
if user.Type&model.UserTypeRole != 0 {
return true
}
}
return false
}

View File

@@ -0,0 +1,50 @@
package cms
import (
"errors"
"git.rosy.net.cn/baseapi/platformapi/recharge_phone_bill"
"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/api"
"time"
)
// QueryUserRecharge 用户查询充值列表
func QueryUserRecharge(userId []string, mobile, orderId string, page, pageSize int, startTime, endTime string, rechargeStatus int) ([]*model.RechargeUserModelData, int, error) {
if page == 0 {
page = 1
}
if pageSize == 0 {
pageSize = 10
}
var start time.Time
var end time.Time
if startTime != "" {
start = utils.Str2Time(startTime)
}
if endTime != "" {
end = utils.Str2Time(endTime)
}
return dao.QueryRechargeRecommend(userId, mobile, orderId, page, pageSize, start, end, rechargeStatus)
}
// QueryUserOrderDetail 用户查询订单详情
func QueryUserOrderDetail(orderId, mobile string) ([]recharge_phone_bill.QueryOrderDetailResList, error) {
data, err := api.TelephoneAPI.QueryOrderDetail("", orderId)
if err != nil {
return nil, err
}
have := false
for _, v := range data {
if v.Mobile == mobile {
have = true
}
}
if have {
return data, err
}
return nil, errors.New("参数电话号码异常")
}

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

@@ -0,0 +1,77 @@
package cms
import (
"encoding/json"
"fmt"
"git.rosy.net.cn/baseapi/utils"
"net"
"os"
)
var (
textChan chan string
)
func TestTemp2() {
server := "127.0.0.1:8000"
tcpAddr, err := net.ResolveTCPAddr("tcp4", server)
if err != nil {
fmt.Fprintf(os.Stderr, "Fatal error: %s", err.Error())
os.Exit(1)
}
conn, err := net.DialTCP("tcp", nil, tcpAddr)
if err != nil {
fmt.Println("Dial err:", err)
return
}
textChan = make(chan string, 10)
connHandler2(conn)
}
func connHandler2(c net.Conn) {
//接收终端输入
//reader := bufio.NewReader(os.Stdin)
//缓冲
//buf := make([]byte, 1024)
fmt.Println("Please input data...")
go func() {
for {
//读取终端输入直到读取到\n
//input, err := reader.ReadString('\n')
//if err != nil {
// fmt.Println("ReadString err:", err)
// return
//}
s := <-textChan
//写入数据
n, err := c.Write([]byte(s))
if err != nil {
fmt.Println("Write err:", err, n)
return
}
//服务器端返回的数据写入buf
//cnt, err := c.Read(buf)
//if err != nil {
// fmt.Println("Read err:", err)
// return
//}
//服务器端回传的信息
//fmt.Println("server response:", string(buf[0:cnt]))
}
}()
}
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
}

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

@@ -1,16 +1,7 @@
package common
import (
"fmt"
"git.rosy.net.cn/baseapi/platformapi/tencent_map"
"sort"
"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/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/globals/api"
)
type Store4User struct {
@@ -40,7 +31,6 @@ type Store4User struct {
Distance int `json:"distance"`
WalkDistance int `json:"walkDistance"`
DeliverySelf int `json:"deliverySelf"`
}
type Store4UserList []*Store4User
@@ -63,236 +53,166 @@ func (x Store4UserList) Swap(i, j int) {
x[i], x[j] = x[j], x[i]
}
func GetNearSupplyGoodsStoreByStoreID(ctx *jxcontext.Context, storeID int) (store *model.Store, err error) {
var (
stores []*model.Store
db = dao.GetDB()
)
store2, _ := dao.GetStoreDetail(db, storeID, model.VendorIDJX, "")
if store2 == nil {
return nil, fmt.Errorf("该门店未绑定京西平台storeID: %v", storeID)
}
if store2.IsSupplyGoods == model.YES {
return nil, fmt.Errorf("该门店已经是货源门店无法从其他货源门店进货storeID: %v", storeID)
}
sql := `
SELECT a.*
FROM store a
JOIN store_map b ON b.store_id = a.id
JOIN store c ON c.city_code = a.city_code AND c.id = ?
WHERE a.deleted_at = ?
AND b.deleted_at = ?
AND b.vendor_id = ?
AND b.is_supply_goods = ?
AND a.status = ?
`
sqlParams := []interface{}{
storeID,
utils.DefaultTimeValue, utils.DefaultTimeValue,
model.VendorIDJX, model.YES, model.StoreStatusOpened,
}
err = dao.GetRows(db, &stores, sql, sqlParams...)
if len(stores) > 0 {
realDistance := float64(0)
for _, v := range stores {
distance := jxutils.EarthDistance(jxutils.IntCoordinate2Standard(v.Lng), jxutils.IntCoordinate2Standard(v.Lat), jxutils.IntCoordinate2Standard(store2.Lng), jxutils.IntCoordinate2Standard(store2.Lat))
if realDistance == 0 {
realDistance = distance
store = v
} else {
if realDistance > distance {
realDistance = distance
store = v
}
}
}
}
return store, err
}
func GetStoreListByLocation(ctx *jxcontext.Context, lng, lat float64, maxRadius int, needWalkDistance, isJds bool, brandID []int) (storeList []*Store4User, err error) {
const (
maxStoreCount4User = 5
)
var (
sql string
sqlParams []interface{}
)
lng2, _ := jxutils.ConvertDistanceToLogLat(lng, lat, float64(maxRadius), 90)
_, lat2 := jxutils.ConvertDistanceToLogLat(lng, lat, float64(maxRadius), 0)
lng1 := lng - (lng2 - lng)
lat1 := lat - (lat2 - lat)
if !isJds {
sql = `
SELECT t1.*,
city.name city_name,sm.delivery_self
FROM store t1
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 <> ?
WHERE t1.deleted_at = ? AND t1.status <> ? AND t1.lng > ? AND t1.lng < ? AND t1.lat > ? AND t1.lat < ?
AND sm.is_order <> ?
AND t1.id <> ?
`
sqlParams = append(sqlParams,
model.VendorIDJX, utils.DefaultTimeValue, model.StoreStatusDisabled,
utils.DefaultTimeValue, model.StoreStatusDisabled, jxutils.StandardCoordinate2Int(lng1), jxutils.StandardCoordinate2Int(lng2), jxutils.StandardCoordinate2Int(lat1), jxutils.StandardCoordinate2Int(lat2),
model.YES,
model.MatterStoreID,
)
if len(brandID) != 0 {
sql += " AND t1.brand_id IN (" + dao.GenQuestionMarks(len(brandID)) + ")"
sqlParams = append(sqlParams, brandID)
}
sql += `
ORDER BY t1.id
`
} else {
sql = `
SELECT t1.*,
city.name city_name,sm.delivery_self
FROM store t1
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 = ?
WHERE t1.deleted_at = ? AND t1.status = ? AND t1.lng > ? AND t1.lng < ? AND t1.lat > ? AND t1.lat < ?
AND sm.is_order <> ?
AND t1.id <> ?
ORDER BY t1.id
`
sqlParams = []interface{}{
model.VendorIDJDShop, utils.DefaultTimeValue, model.StoreStatusOpened,
utils.DefaultTimeValue, model.StoreStatusOpened, jxutils.StandardCoordinate2Int(lng1), jxutils.StandardCoordinate2Int(lng2), jxutils.StandardCoordinate2Int(lat1), jxutils.StandardCoordinate2Int(lat2),
model.YES,
model.MatterStoreID,
}
}
var storeList1 []*Store4User
if err = dao.GetRows(dao.GetDB(), &storeList1, sql, sqlParams...); err == nil {
var storeList2 []*Store4User
for _, v := range storeList1 {
distance := jxutils.Point2StoreDistance(lng, lat, v.Lng, v.Lat, v.DeliveryRangeType, v.DeliveryRange)
if distance > 0 || (lng == jxutils.IntCoordinate2Standard(v.Lng) && lat == jxutils.IntCoordinate2Standard(v.Lat)) {
v.Distance = distance
storeList2 = append(storeList2, v)
}
}
// 为了审核用
if len(storeList2) == 0 {
sql2 := `
SELECT t1.*,
city.name city_name
FROM store t1
JOIN place city ON city.code = t1.city_code
WHERE t1.deleted_at = ? AND t1.id = ?
`
sqlParams2 := []interface{}{
// model.VendorIDJX, utils.DefaultTimeValue, model.StoreStatusDisabled,
utils.DefaultTimeValue,
// model.StoreStatusDisabled,
// jxutils.StandardCoordinate2Int(0),
// jxutils.StandardCoordinate2Int(10000),
// jxutils.StandardCoordinate2Int(0),
// jxutils.StandardCoordinate2Int(10000),
// model.YES,
102919, //商城模板店
}
dao.GetRows(dao.GetDB(), &storeList2, sql2, sqlParams2...)
// if len(storeList2) > 1 {
// storeList2 = storeList2[:1]
// }
}
// 如果要求以步行距离来算
if needWalkDistance {
var coordList []*tencent_map.Coordinate
for _, v := range storeList2 {
coordList = append(coordList, &tencent_map.Coordinate{
Lng: v.FloatLng,
Lat: v.FloatLat,
})
}
if distanceList, err2 := api.TencentMapAPI.BatchWalkingDistance(lng, lat, coordList); err2 == nil {
for k, v := range storeList2 {
v.WalkDistance = int(distanceList[k])
}
} else {
return nil, err2
}
}
sort.Sort(Store4UserList(storeList2))
storeList = storeList2
if len(storeList) > maxStoreCount4User {
storeList = storeList[:maxStoreCount4User]
}
}
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
}
//
//func GetNearSupplyGoodsStoreByStoreID(ctx *jxcontext.Context, storeID int) (store *model.Store, err error) {
// var (
// stores []*model.Store
// db = dao.GetDB()
// )
// store2, _ := dao.GetStoreDetail(db, storeID, model.VendorIDJX)
// if store2 == nil {
// return nil, fmt.Errorf("该门店未绑定京西平台storeID: %v", storeID)
// }
// if store2.IsSupplyGoods == model.YES {
// return nil, fmt.Errorf("该门店已经是货源门店无法从其他货源门店进货storeID: %v", storeID)
// }
// sql := `
// SELECT a.*
// FROM store a
// JOIN store_map b ON b.store_id = a.id
// JOIN store c ON c.city_code = a.city_code AND c.id = ?
// WHERE a.deleted_at = ?
// AND b.deleted_at = ?
// AND b.vendor_id = ?
// AND b.is_supply_goods = ?
// AND a.status = ?
// `
// sqlParams := []interface{}{
// storeID,
// utils.DefaultTimeValue, utils.DefaultTimeValue,
// model.VendorIDJX, model.YES, model.StoreStatusOpened,
// }
// err = dao.GetRows(db, &stores, sql, sqlParams)
// if len(stores) > 0 {
// realDistance := float64(0)
// for _, v := range stores {
// distance := jxutils.EarthDistance(jxutils.IntCoordinate2Standard(v.Lng), jxutils.IntCoordinate2Standard(v.Lat), jxutils.IntCoordinate2Standard(store2.Lng), jxutils.IntCoordinate2Standard(store2.Lat))
// if realDistance == 0 {
// realDistance = distance
// store = v
// } else {
// if realDistance > distance {
// realDistance = distance
// store = v
// }
// }
// }
// }
// return store, err
//}
//
//func GetStoreListByLocation(ctx *jxcontext.Context, lng, lat float64, maxRadius int, needWalkDistance, isJds bool) (storeList []*Store4User, err error) {
// const (
// maxStoreCount4User = 5
// )
//
// var (
// sql string
// sqlParams []interface{}
// )
//
// lng2, _ := jxutils.ConvertDistanceToLogLat(lng, lat, float64(maxRadius), 90)
// _, lat2 := jxutils.ConvertDistanceToLogLat(lng, lat, float64(maxRadius), 0)
// lng1 := lng - (lng2 - lng)
// lat1 := lat - (lat2 - lat)
// // globals.SugarLogger.Debugf("%f,%f,%f,%f\n", lng1, lng2, lat1, lat2)
// if !isJds {
// sql = `
// SELECT t1.*,
// city.name city_name
// FROM store t1
// 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 <> ?
// WHERE t1.deleted_at = ? AND t1.status <> ? AND t1.lng > ? AND t1.lng < ? AND t1.lat > ? AND t1.lat < ?
// AND sm.is_order <> ?
// AND t1.id <> ?
// ORDER BY t1.id
// `
// sqlParams = []interface{}{
// model.VendorIDJX, utils.DefaultTimeValue, model.StoreStatusDisabled,
// utils.DefaultTimeValue, model.StoreStatusDisabled, jxutils.StandardCoordinate2Int(lng1), jxutils.StandardCoordinate2Int(lng2), jxutils.StandardCoordinate2Int(lat1), jxutils.StandardCoordinate2Int(lat2),
// model.YES,
// model.MatterStoreID,
// }
// } else {
// sql = `
// SELECT t1.*,
// city.name city_name
// FROM store t1
// 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 = ?
// WHERE t1.deleted_at = ? AND t1.status = ? AND t1.lng > ? AND t1.lng < ? AND t1.lat > ? AND t1.lat < ?
// AND sm.is_order <> ?
// AND t1.id <> ?
// ORDER BY t1.id
// `
// sqlParams = []interface{}{
// model.VendorIDJDShop, utils.DefaultTimeValue, model.StoreStatusOpened,
// utils.DefaultTimeValue, model.StoreStatusOpened, jxutils.StandardCoordinate2Int(lng1), jxutils.StandardCoordinate2Int(lng2), jxutils.StandardCoordinate2Int(lat1), jxutils.StandardCoordinate2Int(lat2),
// model.YES,
// model.MatterStoreID,
// }
// }
// var storeList1 []*Store4User
// if err = dao.GetRows(dao.GetDB(), &storeList1, sql, sqlParams...); err == nil {
// var storeList2 []*Store4User
// for _, v := range storeList1 {
// distance := jxutils.Point2StoreDistance(lng, lat, v.Lng, v.Lat, v.DeliveryRangeType, v.DeliveryRange)
// if distance > 0 || (lng == jxutils.IntCoordinate2Standard(v.Lng) && lat == jxutils.IntCoordinate2Standard(v.Lat)) {
// v.Distance = distance
// storeList2 = append(storeList2, v)
// }
// }
//
// // 为了审核用
// if len(storeList2) == 0 {
// sql2 := `
// SELECT t1.*,
// city.name city_name
// FROM store t1
// JOIN place city ON city.code = t1.city_code
// WHERE t1.deleted_at = ? AND t1.status <> ? AND t1.id = ?
// `
// sqlParams2 := []interface{}{
// // model.VendorIDJX, utils.DefaultTimeValue, model.StoreStatusDisabled,
// utils.DefaultTimeValue,
// model.StoreStatusDisabled,
// // jxutils.StandardCoordinate2Int(0),
// // jxutils.StandardCoordinate2Int(10000),
// // jxutils.StandardCoordinate2Int(0),
// // jxutils.StandardCoordinate2Int(10000),
// // model.YES,
// 102919, //商城模板店
// }
// dao.GetRows(dao.GetDB(), &storeList2, sql2, sqlParams2...)
// // if len(storeList2) > 1 {
// // storeList2 = storeList2[:1]
// // }
// }
//
// // 如果要求以步行距离来算
// if needWalkDistance {
// var coordList []*autonavi.Coordinate
// for _, v := range storeList2 {
// coordList = append(coordList, &autonavi.Coordinate{
// Lng: v.FloatLng,
// Lat: v.FloatLat,
// })
// }
// if distanceList, err2 := api.AutonaviAPI.BatchWalkingDistance(lng, lat, coordList); err2 == nil {
// for k, v := range storeList2 {
// v.WalkDistance = int(distanceList[k])
// }
// } else {
// return nil, err2
// }
// }
//
// sort.Sort(Store4UserList(storeList2))
// storeList = storeList2
// if len(storeList) > maxStoreCount4User {
// storeList = storeList[:maxStoreCount4User]
// }
// }
// return storeList, err
//}

View File

@@ -1,33 +1,182 @@
package event
import (
"errors"
"fmt"
"regexp"
"strings"
"sync"
"time"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxstore/financial"
"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"
"github.com/gorilla/websocket"
)
var (
NoUseEventMap = map[string]string{
"CreateQrOrBarCode": "CreateQrOrBarCode",
"StatisticsReportForOrders": "StatisticsReportForOrders",
"UpdateUser": "UpdateUser",
}
regexpToken = regexp.MustCompile(`,"token":".*"`)
wsClient = &WSClient{}
//广播频道(通道)
broadcast = make(chan *model.ImMessageRecord)
)
type CheckCookie struct {
VendorID int `json:"vendorID"`
VendorOrgCode string `json:"vendorOrgCode"`
Status string `json:"status"`
const (
sysMessageTitle = ""
)
//连接的客户端,吧每个客户端都放进来
type WSClient struct {
Clients map[int]map[string]*websocket.Conn
ClientsHeart map[string]*websocket.Conn
s *sync.RWMutex
}
func init() {
clients := make(map[int]map[string]*websocket.Conn)
clientsHeart := make(map[string]*websocket.Conn)
wsClient.Clients = clients
wsClient.ClientsHeart = clientsHeart
wsClient.s = new(sync.RWMutex)
go handleMessages()
}
//广播推送消息
func handleMessages() {
for {
//读取通道中的消息
msg := <-broadcast
if msg.GroupID == 0 {
// globals.SugarLogger.Debugf("heart %v", utils.Format4Output(msg, false))
if wsClient.ClientsHeart[msg.UserID] != nil {
if err := wsClient.ClientsHeart[msg.UserID].WriteJSON(&model.ImMessageRecord{
Key: "pang",
}); err != nil {
globals.SugarLogger.Debugf("heart client.WriteJSON error: %v", err)
wsClient.ClientsHeart[msg.UserID].Close() //关闭
delete(wsClient.ClientsHeart, msg.UserID)
}
}
} else {
globals.SugarLogger.Debugf("clients len %v", len(wsClient.Clients))
//循环map客户端
for userID, client := range wsClient.Clients[msg.GroupID] {
//把通道中的消息发送给客户端
user, err := dao.GetUser(dao.GetDB(), msg.UserID)
if err == nil {
msg.UserInfo = user
}
globals.SugarLogger.Debugf("msg %v", utils.Format4Output(msg, false))
if msg.CreatedAt == utils.ZeroTimeValue {
msg.CreatedAt = time.Now()
}
err = client.WriteJSON(msg)
if err != nil {
globals.SugarLogger.Debugf("client.WriteJSON error: %v", err)
client.Close() //关闭
delete(wsClient.Clients[msg.GroupID], userID)
// delete(clients, client) //删除map中的客户端
}
}
}
}
}
func ImMessage(userID string, ws *websocket.Conn) (err error) {
var (
clientUser = make(map[string]*websocket.Conn)
db = dao.GetDB()
)
//将当前客户端放入map中
messageGroups, _ := dao.GetUserMessageGroups(dao.GetDB(), userID)
if len(messageGroups) == 0 {
return
}
wsClient.s.Lock()
clientUser[userID] = ws
wsClient.ClientsHeart[userID] = ws
for _, v := range messageGroups {
if len(wsClient.Clients[v.GroupID]) > 0 {
wsClient.Clients[v.GroupID][userID] = ws
} else {
wsClient.Clients[v.GroupID] = clientUser
}
}
wsClient.s.Unlock()
globals.SugarLogger.Debugf("userID :%v ,clients :%v", userID, utils.Format4Output(wsClient.Clients, false))
var s *model.ImMessageRecord
for {
//接收客户端的消息
err := ws.ReadJSON(&s)
if err != nil {
globals.SugarLogger.Debugf("页面可能断开啦 ws.ReadJSON error: %v", err.Error())
for k, _ := range wsClient.Clients {
delete(wsClient.Clients[k], userID)
}
delete(wsClient.ClientsHeart, userID)
// delete(clients, ws) //删除map中的客户端
break //结束循环
} else {
//接受消息 业务逻辑
broadcast <- s
if s.GroupID != 0 {
if s.GroupID != model.SysGroupID {
//发聊天消息时这个组所有的成员包括创建者都在userIDs里
userIDs := []string{}
if results, err := dao.GetMessageGroups(db, "", s.GroupID, 0, true, ""); err == nil {
for _, v := range results {
userIDs = append(userIDs, v.UserID)
for _, vv := range v.MessageGroupMembers {
userIDs = append(userIDs, vv.UserID)
}
}
}
//如果这些人不在这个组的ws池子里就打上未读标记
for _, v := range userIDs {
if wsClient.ClientsHeart[v] == nil {
messageGroupReads, _ := dao.GetMessageGroupRead(db, v, s.GroupID)
for _, vv := range messageGroupReads {
vv.UnReadCount++
dao.UpdateEntity(db, vv, "UnReadCount")
}
}
}
} else {
if wsClient.ClientsHeart[s.ToUserID] == nil {
messageGroupReads, _ := dao.GetMessageGroupRead(db, s.ToUserID, s.GroupID)
for _, vv := range messageGroupReads {
vv.UnReadCount++
dao.UpdateEntity(db, vv, "UnReadCount")
}
}
}
}
utils.CallFuncAsync(func() {
if s.GroupID != 0 {
dao.WrapAddIDCULDEntity(s, "")
dao.CreateEntity(db, s)
}
})
}
}
ws.Close()
return err
}
func GetOnlineUserCount() (count int) {
wsClient.s.RLock()
count = len(wsClient.ClientsHeart)
wsClient.s.RUnlock()
return count
}
func AddOperateEvent(ctx *jxcontext.Context, accessUUID, jsonData string, errCode, errMsg string, useTime int, apiFunctionSpec string) (err error) {
@@ -48,7 +197,7 @@ func AddOperateEvent(ctx *jxcontext.Context, accessUUID, jsonData string, errCod
}
if apiFunction != "" {
if apiFunction[0:3] == "Get" || NoUseEventMap[apiFunction] != "" {
return errors.New("未知错误")
return err
}
}
if accessUUID != "" {
@@ -68,7 +217,7 @@ func AddOperateEvent(ctx *jxcontext.Context, accessUUID, jsonData string, errCod
ErrMsg: errMsg,
UseTime: useTime,
}
txDB, err := dao.Begin(db)
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, txDB)
@@ -135,66 +284,505 @@ func GetOperateEvents(ctx *jxcontext.Context, name string, apiFunctions []string
return pageInfo, err
}
func GetCheckVendorCookie(ctx *jxcontext.Context, vendorIDs []int, isAuto bool) (ccList []*CheckCookie, err error) {
func CreateMessageGroup(ctx *jxcontext.Context, userID, userID2, groupName string, dividePercentage, quitPrice int) (messageGroupResult *dao.GetMessageGroupsResult, err error) {
var (
ebaiOrderID = "1577329467196263592"
ebaiErr = "return not json"
ebaiErr2 = "系统错误"
mtStoreID = "7388603"
mtErr = "返回结果格式不正常"
jdUpcCode = "6952395700895"
jdErr = "请输入用户名"
// mtpsErr = "用户未登录"
errMsg = ""
db = dao.GetDB()
groupID int
)
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
}
for {
groupID = jxutils.GenRand6()
temp := &model.MessageGroup{
GroupID: groupID,
}
dao.GetEntity(db, temp, "GroupID")
if temp.UserID == "" {
break
}
}
if userID2 != "" {
messageGroups, err := dao.GetMessageGroups(db, userID, 0, model.GroupTypeSingle, true, userID2)
if len(messageGroups) > 0 && len(messageGroups[0].MessageGroupMembers) > 0 {
return messageGroups[0], err
}
user, err := dao.GetUserByID(db, "user_id", userID2)
if err != nil {
return nil, err
}
if user == nil {
return nil, fmt.Errorf("无法找到要联系的用户!")
}
messageGroup := &model.MessageGroup{
GroupID: groupID,
UserID: userID,
// Name: user.Name,
Type: model.GroupTypeSingle,
MaxCount: 2,
}
messageGroupMember := &model.MessageGroupMember{
GroupID: groupID,
MemberUserID: userID2,
Type: model.GroupMemberTypeNormal,
}
dao.WrapAddIDCULDEntity(messageGroup, ctx.GetUserName())
dao.WrapAddIDCULDEntity(messageGroupMember, ctx.GetUserName())
err = dao.CreateEntity(db, messageGroup)
err = dao.CreateEntity(db, messageGroupMember)
if err == nil {
messageGroupRead := &model.MessageGroupRead{
GroupID: groupID,
UserID: userID,
}
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
dao.WrapAddIDCULEntity(messageGroupRead, ctx.GetUserName())
messageGroupRead2 := messageGroupRead
messageGroupRead2.UserID = userID2
dao.CreateEntity(db, messageGroupRead)
if err = dao.CreateEntity(db, messageGroupRead2); err == nil {
if messageGroupReads, err := dao.GetMessageGroupRead(db, userID2, model.SysGroupID); len(messageGroupReads) == 0 && err == nil {
messageGroupRead := &model.MessageGroupRead{
GroupID: model.SysGroupID,
UserID: userID2,
}
dao.WrapAddIDCULEntity(messageGroupRead, ctx.GetUserName())
dao.CreateEntity(db, messageGroupRead)
}
}
}
cc.VendorID = v
cc.VendorOrgCode = ""
if flag {
cc.Status = "无效"
} else {
cc.Status = "有效"
} else {
userMembers, err := dao.GetUserMember(db, userID, model.MemberTypeNormal)
messageGroupsResult, err := dao.GetMessageGroups(db, userID, 0, model.GroupTypeMulit, false, "")
messageGroupMembers, err := dao.GetMessageGroupMembers(db, 0, model.GroupTypeMulit, userID)
if err != nil {
return nil, err
}
if len(userMembers) == 0 {
return nil, fmt.Errorf("抱歉,只有会员才能创建群聊!")
}
if len(messageGroupsResult) > 0 {
return nil, fmt.Errorf("您已经有群组了,请勿重复创建!群号为:%d", messageGroupsResult[0].GroupID)
}
if len(messageGroupMembers) > 0 {
return nil, fmt.Errorf("您已加入了[%v]群,请先退出后再创建!", messageGroupMembers[0].GroupID)
}
messageGroup := &model.MessageGroup{
GroupID: groupID,
UserID: userID,
Name: groupName,
Type: model.GroupTypeMulit,
MaxCount: 2000,
DividePercentage: dividePercentage,
QuitPrice: quitPrice,
}
user, err := dao.GetUserByID(db, "user_id", userID)
if groupName == "" {
messageGroup.Name = user.Name + "的集团"
}
dao.WrapAddIDCULDEntity(messageGroup, ctx.GetUserName())
if err = dao.CreateEntity(db, messageGroup); err == nil {
messageGroupRead := &model.MessageGroupRead{
GroupID: groupID,
UserID: userID,
}
dao.WrapAddIDCULEntity(messageGroupRead, ctx.GetUserName())
dao.CreateEntity(db, messageGroupRead)
}
ccList = append(ccList, cc)
}
if isAuto && errMsg != "" {
globals.SugarLogger.Warnf("GetCheckVendorCookie[%v]", errMsg)
if err == nil {
if messageGroupReads, err := dao.GetMessageGroupRead(db, userID, model.SysGroupID); len(messageGroupReads) == 0 && err == nil {
messageGroupRead := &model.MessageGroupRead{
GroupID: model.SysGroupID,
UserID: userID,
}
dao.WrapAddIDCULEntity(messageGroupRead, ctx.GetUserName())
dao.CreateEntity(db, messageGroupRead)
}
}
return ccList, err
return messageGroupResult, err
}
func GetMessageGroupByUser(ctx *jxcontext.Context, userID string) (messageGroupResult []*dao.GetMessageGroupsResult, err error) {
var (
db = dao.GetDB()
)
messageGroups, err := dao.GetMessageGroups(db, "", model.SysGroupID, 0, false, "")
messageGroups2, err := dao.GetMessageGroups(db, userID, 0, 0, true, "")
messageGroups = append(messageGroups, messageGroups2...)
messageGroupMembers, err := dao.GetMessageGroupMembers(db, 0, 0, userID)
for _, v := range messageGroupMembers {
if messageGroupList, err := dao.GetMessageGroups(db, "", v.GroupID, 0, false, ""); err == nil {
messageGroups = append(messageGroups, messageGroupList...)
}
}
for _, v := range messageGroups {
//是这个人创建的群聊,如果是单聊就返回对方的头像
if v.Type == model.GroupTypeSingle {
var userID2 string
if v.UserID == userID {
userID2 = v.MessageGroupMembers[0].MemberUserID
} else {
userID2 = userID
}
if user, err := dao.GetUserByID(db, "user_id", userID2); err == nil {
v.Avatar = user.Avatar
v.Name = user.Name
}
}
var (
imMessageRecord *model.ImMessageRecord
sql string
sqlParams = []interface{}{}
)
if v.GroupID != model.SysGroupID {
//最后一条记录和时间和人
sql = `
SELECT * FROM im_message_record WHERE group_id = ? ORDER BY created_at DESC LIMIT 1
`
sqlParams = append(sqlParams, v.GroupID)
} else {
//最后一条记录和时间和人
sql = `
SELECT * FROM im_message_record WHERE group_id = ? AND to_user_id = ? ORDER BY created_at DESC LIMIT 1
`
sqlParams = append(sqlParams, v.GroupID, userID)
}
if err = dao.GetRow(db, &imMessageRecord, sql, sqlParams); err == nil {
v.LastTime = imMessageRecord.CreatedAt
v.LastContent = imMessageRecord.Content
v.LastMessageType = imMessageRecord.MessageType
if user3, err := dao.GetUserByID(db, "user_id", imMessageRecord.UserID); err == nil {
v.LastUserName = user3.Name
}
} else {
err = nil
}
//该用户各组的未读消息数
var unReadCount int
if messageGroupReads, err := dao.GetMessageGroupRead(db, userID, v.GroupID); err == nil && len(messageGroupReads) > 0 {
for _, vv := range messageGroupReads {
unReadCount += vv.UnReadCount
}
}
v.UnReadMessageCount = unReadCount
}
return messageGroups, err
}
func AddMessageGroup(ctx *jxcontext.Context, groupID int, userID string) (err error) {
var (
db = dao.GetDB()
)
messageGroupMembers, err := dao.GetMessageGroupMembers(db, groupID, 0, userID)
messageGroupMembers3, err := dao.GetMessageGroupMembers(db, 0, 0, userID)
messageGroupsResult, err := dao.GetMessageGroups(db, userID, groupID, model.GroupTypeMulit, false, "")
messageGroupsResult2, err := dao.GetMessageGroups(db, "", groupID, model.GroupTypeMulit, false, "")
messageGroupsResult3, err := dao.GetMessageGroups(db, userID, 0, model.GroupTypeMulit, false, "")
messageGroupMembers2, err := dao.GetMessageGroupMembers(db, groupID, 0, "")
if err != nil {
return err
}
if len(messageGroupMembers) > 0 {
return fmt.Errorf("此用户已经在该群组中了!")
}
if len(messageGroupMembers3) > 0 {
return fmt.Errorf("您已经有群组[%v]了,不能申请加入其它群!", messageGroupMembers3[0].GroupID)
}
if len(messageGroupsResult) > 0 {
return fmt.Errorf("请不要加入自己创建的群!")
}
if len(messageGroupsResult2) > 0 && len(messageGroupMembers2) > 0 {
if len(messageGroupMembers2)+1 > messageGroupsResult2[0].MaxCount {
return fmt.Errorf("抱歉该群组已经满员了!")
}
}
if len(messageGroupsResult3) > 0 {
return fmt.Errorf("您已经拥有[%v]群了,不能再加入其它群!", messageGroupsResult3[0].GroupID)
}
messageGroupMember := &model.MessageGroupMember{
GroupID: groupID,
MemberUserID: userID,
Type: model.GroupMemberTypeNormal,
}
dao.WrapAddIDCULDEntity(messageGroupMember, ctx.GetUserName())
if err = dao.CreateEntity(db, messageGroupMember); err == nil {
messageGroupRead := &model.MessageGroupRead{
GroupID: groupID,
UserID: userID,
}
dao.WrapAddIDCULEntity(messageGroupRead, ctx.GetUserName())
if err = dao.CreateEntity(db, messageGroupRead); err == nil {
if messageGroupReads, err := dao.GetMessageGroupRead(db, userID, model.SysGroupID); len(messageGroupReads) == 0 && err == nil {
messageGroupRead := &model.MessageGroupRead{
GroupID: model.SysGroupID,
UserID: userID,
}
dao.WrapAddIDCULEntity(messageGroupRead, ctx.GetUserName())
dao.CreateEntity(db, messageGroupRead)
}
}
}
return err
}
func UpdateMessageGroup(ctx *jxcontext.Context, groupID int, payload map[string]interface{}) (num int64, err error) {
var (
db = dao.GetDB()
messageGroup = &model.MessageGroup{
GroupID: groupID,
}
)
if err = dao.GetEntity(db, messageGroup, "GroupID"); err != nil {
return 0, err
}
if messageGroup.UserID != ctx.GetUserID() {
return 0, fmt.Errorf("只有群主才能修改群信息!")
}
valid := dao.StrictMakeMapByStructObject(payload, messageGroup, ctx.GetUserName())
if len(valid) > 0 {
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, txDB)
panic(r)
}
}()
if num, err = dao.UpdateEntityLogically(db, messageGroup, valid, ctx.GetUserName(), nil); err != nil {
dao.Rollback(db, txDB)
return 0, err
}
dao.Commit(db, txDB)
}
return num, err
}
func DeleteMessageGroup(ctx *jxcontext.Context, groupID int, userID string, flag bool) (errCode string, err error) {
var (
db = dao.GetDB()
messageGroup = &model.MessageGroup{
GroupID: groupID,
}
)
if err = dao.GetEntity(db, messageGroup, "GroupID"); err != nil {
return errCode, err
}
//解散群
if flag {
if messageGroup.UserID != ctx.GetUserID() {
return errCode, fmt.Errorf("只有群主才能解散群!")
}
messageGroup.DeletedAt = time.Now()
messageGroup.LastOperator = ctx.GetUserName()
dao.UpdateEntity(db, messageGroup, "DeletedAt", "LastOperator")
messageGroupMembers, _ := dao.GetMessageGroupMembers(db, groupID, 0, "")
for _, v := range messageGroupMembers {
v.DeletedAt = time.Now()
v.LastOperator = ctx.GetUserName()
dao.UpdateEntity(db, v, "DeletedAt", "LastOperator")
}
} else {
//token中用户与传入user不一致就判定为踢人
if ctx.GetUserID() != userID {
if messageGroup.UserID != ctx.GetUserID() {
messageGroupMembers, err := dao.GetMessageGroupMembers(db, groupID, 0, ctx.GetUserID())
if err != nil {
return errCode, err
}
if messageGroupMembers[0].Type == model.GroupMemberTypeNormal {
return errCode, fmt.Errorf("只有创建者和管理员才能踢人!")
}
}
} else {
quitPrice := messageGroup.QuitPrice
userBill, err := dao.GetUserBill(db, userID, "")
userBillGroupMaster, err := dao.GetUserBill(db, messageGroup.UserID, "")
if err != nil {
return errCode, err
}
if userBill.AccountBalance < quitPrice {
return model.ErrCodeAccountBalanceNotEnough, fmt.Errorf("用户余额不足,请充值!")
}
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, txDB)
panic(r)
}
}()
//账户支出
if err = financial.AddExpendUpdateAccount(txDB, userBill, model.BillTypeQuitGroup, quitPrice, 0); err != nil {
dao.Rollback(db, txDB)
return errCode, err
}
//群主收到退团金额
if err = financial.AddIncomeUpdateAccount(txDB, userBillGroupMaster, model.BillTypeQuitGroup, quitPrice, 0); err != nil {
dao.Rollback(db, txDB)
return errCode, err
}
dao.Commit(db, txDB)
}
messageGroupMembers, err := dao.GetMessageGroupMembers(db, groupID, 0, userID)
if err != nil {
return errCode, err
}
messageGroupMembers[0].DeletedAt = time.Now()
messageGroupMembers[0].LastOperator = ctx.GetUserName()
dao.UpdateEntity(db, messageGroupMembers[0], "DeletedAt", "LastOperator")
}
return errCode, err
}
func TransferMessageGroupMaster(ctx *jxcontext.Context, groupID int, userID string) (err error) {
var (
db = dao.GetDB()
messageGroup = &model.MessageGroup{
GroupID: groupID,
}
)
if err = dao.GetEntity(db, messageGroup, "GroupID"); err != nil {
return err
}
if messageGroup.UserID != ctx.GetUserID() {
return fmt.Errorf("只有群主才能转让群主!")
}
//群主换成选的那个人
messageGroup.UserID = userID
messageGroup.LastOperator = ctx.GetUserName()
//之前那个群成员换成之前的群主
messageGroupMembers, err := dao.GetMessageGroupMembers(db, groupID, 0, userID)
if err != nil && len(messageGroupMembers) == 0 {
return err
}
messageGroupMember := messageGroupMembers[0]
messageGroupMember.MemberUserID = ctx.GetUserID()
messageGroupMember.LastOperator = ctx.GetUserName()
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, txDB)
panic(r)
}
}()
if _, err = dao.UpdateEntity(db, messageGroup, "UserID", "LastOperator"); err != nil {
dao.Rollback(db, txDB)
return err
}
if _, err = dao.UpdateEntity(db, messageGroupMember, "MemberUserID", "LastOperator"); err != nil {
dao.Rollback(db, txDB)
return err
}
dao.Commit(db, txDB)
return err
}
func SendSysMessageSimple(content, toUserID string) (err error) {
return SendSysMessage(jxcontext.AdminCtx, &model.ImMessageRecord{
Content: sysMessageTitle + " " + content,
ToUserID: toUserID,
GroupID: model.SysGroupID,
MessageType: 1, // 普通文字消息
})
}
func SendSysMessage(ctx *jxcontext.Context, imMessageRecord *model.ImMessageRecord) (err error) {
var (
db = dao.GetDB()
userID = imMessageRecord.ToUserID
groupID = imMessageRecord.GroupID
)
if groupID != model.SysGroupID {
return fmt.Errorf("只能给系统组发消息!")
}
imMessageRecord.CreatedAt = time.Now()
imMessageRecord.LastOperator = ctx.GetUserName()
imMessageRecord.DeletedAt = utils.DefaultTimeValue
imMessageRecord.UpdatedAt = utils.DefaultTimeValue
imMessageRecord.Seq = time.Now().Unix()
err = dao.CreateEntity(db, imMessageRecord)
if userID == "" {
//循环map客户端
for _, client := range wsClient.Clients[groupID] {
globals.SugarLogger.Debugf("msg %v", utils.Format4Output(imMessageRecord, false))
err = client.WriteJSON(imMessageRecord)
if err != nil {
globals.SugarLogger.Debugf("client.WriteJSON error: %v", err)
client.Close() //关闭
// delete(wsClient.Clients[msg.GroupID], userID)
}
}
} else {
client := wsClient.Clients[groupID][userID]
globals.SugarLogger.Debugf("msg %v", utils.Format4Output(imMessageRecord, false))
if client == nil {
return
}
err = client.WriteJSON(imMessageRecord)
if err != nil {
globals.SugarLogger.Debugf("client.WriteJSON error: %v", err)
client.Close() //关闭
// delete(wsClient.Clients[msg.GroupID], userID)
}
}
return err
}
func DeleteMessageRecord(ctx *jxcontext.Context) (err error) {
var (
db = dao.GetDB()
)
sql := `
DELETE FROM im_message_record WHERE created_at < ? AND group_id <> ?
`
sqlParams := []interface{}{
time.Now().AddDate(0, 0, -3), model.SysGroupID,
}
_, err = dao.ExecuteSQL(db, sql, sqlParams)
return err
}
func UpdateUserMessageGroupRead(ctx *jxcontext.Context, reads []*model.MessageGroupRead) (err error) {
var (
db = dao.GetDB()
userID = ctx.GetUserID()
)
for _, v := range reads {
if messageReads, err := dao.GetMessageGroupRead(db, userID, v.GroupID); err == nil {
if len(messageReads) > 0 {
messageReads[0].UnReadCount += v.UnReadCount
dao.UpdateEntity(db, messageReads[0], "UnReadCount")
} else {
}
}
}
return err
}
type GetUserStatisticsResult struct {
RegisterUserCount int `json:"registerUserCount"` //注册数
OnlineUserCount int `json:"onlineUserCount"` //在线用户数
ConsumeUserCount int `json:"consumeUserCount"` //消费用户数
MemberUserCount int `json:"memberUserCount"` //会员用户数
}
func GetUserStatistics(ctx *jxcontext.Context) (getUserStatisticsResult *GetUserStatisticsResult, err error) {
var (
db = dao.GetDB()
)
getUserStatisticsResult = &GetUserStatisticsResult{}
sql := `
SELECT a.member_user_count, b.consume_user_count FROM
( SELECT DISTINCT COUNT(a.user_id) member_user_count
FROM user a
JOIN user_member b ON a.user_id = b.user_id AND b.deleted_at = ? )a,
( SELECT DISTINCT COUNT(a.user_id) consume_user_count
FROM user a
JOIN ` + "`order`" + `b ON a.user_id = b.user_id AND b.status = ?)b
`
sqlParams := []interface{}{
utils.DefaultTimeValue, model.OrderStatusFinished,
}
err = dao.GetRow(db, &getUserStatisticsResult, sql, sqlParams)
paged, _ := dao.GetUsers2(db, "", "", 0, "", utils.ZeroTimeValue, utils.ZeroTimeValue, 0, nil, nil, 0, -1)
getUserStatisticsResult.RegisterUserCount = paged.TotalCount
getUserStatisticsResult.OnlineUserCount = GetOnlineUserCount()
return getUserStatisticsResult, err
}

View File

@@ -0,0 +1,97 @@
package event
import (
"fmt"
"sync"
)
var (
PrintObject *PrintObjectStruct // 缓存的打印机对象
PrintAddrAndIp *PrintAddrAndIpStruct // 缓存打印机地址:[ip:printNo] event 文件包,connect只能获取到addr
PrintIpAndAddr *PrintIpAndAddrStruct // 缓存打印机地址:[printNo:ip] api_controller 只能获取到printNo
)
func init() {
fmt.Println("初始化打印机对象")
PrintObject = &PrintObjectStruct{
PrintObject: make(map[string]*TcpClient),
RWMutex: new(sync.RWMutex),
}
PrintAddrAndIp = &PrintAddrAndIpStruct{
PrintObject: make(map[string]string),
RWMutex: new(sync.RWMutex),
}
PrintIpAndAddr = &PrintIpAndAddrStruct{
PrintObject: make(map[string]string),
RWMutex: new(sync.RWMutex),
}
}
type PrintObjectStruct struct {
PrintObject map[string]*TcpClient
*sync.RWMutex
}
func (p *PrintObjectStruct) GetPrintObj(printNo string) (*TcpClient, bool) {
p.RLock()
defer p.RUnlock()
tcpObj, ok := PrintObject.PrintObject[printNo]
return tcpObj, ok
}
func (p *PrintObjectStruct) SetPrintObj(printNo string, tcpObj *TcpClient) {
p.RLock()
defer p.RUnlock()
PrintObject.PrintObject[printNo] = tcpObj
}
func (p *PrintObjectStruct) DelPrintObj(printNo string) {
p.RLock()
defer p.RUnlock()
delete(PrintObject.PrintObject, printNo)
}
type PrintAddrAndIpStruct struct {
PrintObject map[string]string
*sync.RWMutex
}
func (p *PrintAddrAndIpStruct) GetPrintAddrAndIp(ip string) (string, bool) {
p.RLock()
defer p.RUnlock()
printNo, ok := PrintAddrAndIp.PrintObject[ip]
return printNo, ok
}
func (p *PrintAddrAndIpStruct) SetPrintAddrAndIp(ip string, printNo string) {
p.RLock()
defer p.RUnlock()
PrintAddrAndIp.PrintObject[ip] = printNo
}
func (p *PrintAddrAndIpStruct) DelPrintAddrAndIp(ip string) {
p.RLock()
defer p.RUnlock()
delete(PrintAddrAndIp.PrintObject, ip)
}
type PrintIpAndAddrStruct struct {
PrintObject map[string]string
*sync.RWMutex
}
func (p *PrintIpAndAddrStruct) GetPrintIpAndAddr(printNo string) (string, bool) {
p.RLock()
defer p.RUnlock()
tcpObj, ok := PrintIpAndAddr.PrintObject[printNo]
return tcpObj, ok
}
func (p *PrintIpAndAddrStruct) SetPrintIpAndAddr(printNo string, ip string) {
p.RLock()
defer p.RUnlock()
PrintIpAndAddr.PrintObject[printNo] = ip
}
func (p *PrintIpAndAddrStruct) DelPrintIpAndAddr(printNo string) {
p.RLock()
defer p.RUnlock()
delete(PrintIpAndAddr.PrintObject, printNo)
}

View File

@@ -0,0 +1,373 @@
package event
import (
"encoding/hex"
"errors"
"fmt"
"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"
"io"
"net"
"strings"
"time"
"unicode/utf8"
)
// ConnRead 获取链接数据
func ConnRead(c net.Conn) ([]byte, int, error) {
buffer := make([]byte, 1024*2)
n, err := c.Read(buffer)
return buffer, n, err
}
// ListenTcp 入口
func ListenTcp() {
l, err := net.Listen("tcp", ":8000")
if err != nil {
fmt.Println("listen error:", err)
return
}
for {
c, err := l.Accept()
if err != nil || c == nil {
fmt.Println("accept error:", err)
break
}
fn := func() {
// 捕获异常 防止waitGroup阻塞
defer func() {
if err := recover(); err != nil {
fmt.Println("recover err = ", err)
return
}
}()
if err := handleConn(c); err != nil {
c.Close()
Pool.Wait()
Pool.Stop()
return
}
}
Pool.AddJob(fn)
}
}
func handleConn(c net.Conn) error {
if c == nil {
return errors.New("conn is nil")
}
for {
buffer, n, err := ConnRead(c)
printRemoteAddr := c.RemoteAddr().String()
printRemoteAddr = strings.Split(printRemoteAddr, ":")[0]
printNoByIP, _ := PrintAddrAndIp.GetPrintAddrAndIp(printRemoteAddr)
if err != nil {
if err == io.EOF {
fmt.Println("connection close")
} else {
fmt.Println("ReadString err:", err)
}
globals.SugarLogger.Debugf("--------printRemoteAddr := %s,printNo := %s", printRemoteAddr, printNoByIP)
if printNo, ok := PrintAddrAndIp.GetPrintAddrAndIp(printRemoteAddr); ok {
PrintAddrAndIp.DelPrintAddrAndIp(printRemoteAddr)
PrintObject.DelPrintObj(printNo)
PrintIpAndAddr.DelPrintIpAndAddr(printRemoteAddr)
dao.ExecuteSQL(dao.GetDB(), `UPDATE printer SET status = -1,is_online = -1 WHERE print_no = ? `, []interface{}{printNo}...)
} else {
printStatusOff := make(map[string]int, 0)
for ip, pn := range PrintAddrAndIp.PrintObject {
if ip == printRemoteAddr {
PrintAddrAndIp.DelPrintAddrAndIp(printRemoteAddr)
PrintIpAndAddr.DelPrintIpAndAddr(pn)
PrintObject.DelPrintObj(printNo)
} else if pn != "" {
printStatusOff[pn] = 1
}
}
}
return err
}
//看是心跳还是打印回调
data := hex.EncodeToString(buffer[:n])
var (
printNo string = "" //打印机编号
heartbeat bool = false
callback bool = false
)
if strings.Contains(data, heartText) || strings.Contains(data, heartTextNew) {
printNoData, _ := hex.DecodeString(data[len(heartText) : len(data)-8])
printNo = string(printNoData)
heartbeat = true
} else if strings.Contains(data, printText) || strings.Contains(data, printTextNew) { //打印回调
_, printNo = getCallbackMsgInfo(data)
callback = true
}
t, ok := PrintObject.GetPrintObj(printNo)
if !ok || t.Clients[printNo] == nil || time.Now().Sub(t.Clients[printNo].StatusTime).Seconds() >= 120 {
t = NewTcpClient()
}
if heartbeat {
// 证明是心跳
Heartbeat(c, t, data, printNo, printRemoteAddr)
} else if callback {
// 打印回调
Callback(c, t, data, printNo)
}
}
}
func (t *TcpClient) printFail() (err error) {
//新开机的打印失败和错误的
var (
db = dao.GetDB()
)
prints, _ := dao.GetPrintMsgs(db, "", []int{printMsgFail, printMsgErr, PrintMsgAlreadyLoad, printMsgAlreadySend}, time.Now().Add(-time.Hour*3), time.Now(), 0, 999)
for _, printMsg := range prints {
t.addMsgChan(printMsg)
}
return err
}
func (t *TcpClient) changePrintMsg(data string, orderNo int64, printNo string) (err error) {
var (
db = dao.GetDB()
comment string
status int
)
//1、先找出打印机编号和订单序列号这两个确定唯一一条消息?
//通过参数传进来
//2、打印成功改变打印表的状态
if strings.Contains(data, printSuccessText) || strings.Contains(data, printSuccessTextNew) {
status = printMsgSuccess
comment = "回调成功,修改打印状态"
} else {
//打印失败也改变状态并更新失败原因
status = printMsgFail
comment = printErrMap[data[12:14]]
}
//这里序号重复会有问题
if printMsgs, err := dao.GetPrintMsgNoPage(db, printNo, orderNo); err != nil {
globals.SugarLogger.Debugf("changePrintMsg err :[%v]", err)
return err
} else if len(printMsgs) == 0 {
globals.SugarLogger.Debugf("changePrintMsg err ,not found printMsg printNo:[%v], orderNo :[%v]", printNo, orderNo)
} else if len(printMsgs) > 0 {
for _, v := range printMsgs {
v.Comment = comment
v.Status = status
dao.UpdateEntity(db, v, "Comment", "Status")
}
}
return err
}
func HandleTcpMessages(t *TcpClient, printNo string) {
var (
db = dao.GetDB()
offset, pageSize = 0, 10
)
if !t.isExistMsg(printNo) {
return
}
fn := func() {
//for {
// time.Sleep(2 * time.Second)
if t.TimeoutMap[printNo] == true {
timeNow := time.Now()
timeStart := time.Date(timeNow.Year(), timeNow.Month(), timeNow.Day(), 0, 0, 0, 0, timeNow.Location())
timeEnd := time.Date(timeNow.Year(), timeNow.Month(), timeNow.Day(), 23, 59, 59, 0, timeNow.Location())
prints, _ := dao.GetPrintMsgs(db, printNo, []int{PrintMsgWait}, timeStart.AddDate(0, 0, -1), timeEnd, offset, pageSize)
for _, printMsg := range prints {
printMsg.Status = PrintMsgAlreadyLoad
//先避免重复读再插到channel
if _, err := dao.UpdateEntity(db, printMsg, "Status"); err == nil {
if err = t.addMsgChan(printMsg); err != nil {
globals.SugarLogger.Debugf("HandleTcpMessages addMsgChan Err: %v", err)
}
}
}
} else {
globals.SugarLogger.Debugf("HandleTcpMessages timeout")
return
}
}
Pool.AddJob(fn)
}
func (t *TcpClient) readTimeoutMap(key string) bool {
t.Lock()
defer t.Unlock()
return t.TimeoutMap[key]
}
func doPrint(t *TcpClient, key string) (err error) {
var (
db = dao.GetDB()
)
if !t.isExistMsg(key) {
return err
}
fn := func() {
for {
if t.TimeoutMap[key] == true {
select {
case printMsg, ok := <-t.MsgMap[key]:
if !ok {
globals.SugarLogger.Debugf("doPrint err !ok ...")
return
}
var (
data []byte
c net.Conn
)
if printMsg == nil {
globals.SugarLogger.Debugf("print msg is nil")
continue
}
if err = checkPrintMsg(db, printMsg); err == nil {
status := t.getPrintStatus(printMsg.PrintNo)
switch status {
//只有在线才打印内容
case printerStatusOnline:
if c = t.getPrintConn(printMsg.PrintNo); c != nil {
data, err = buildMsg(printMsg)
}
case printerStatusOffline:
err = fmt.Errorf("打印机离线!")
case printerStatusOnlineWithoutPaper:
err = fmt.Errorf("打印机缺纸!")
default:
err = fmt.Errorf("打印机状态未知!")
}
}
if c == nil {
if printRemoteAddrIP, have := PrintIpAndAddr.GetPrintIpAndAddr(key); have {
PrintIpAndAddr.DelPrintIpAndAddr(key)
PrintAddrAndIp.DelPrintAddrAndIp(printRemoteAddrIP)
PrintObject.DelPrintObj(key)
}
return
}
if err != nil {
printMsg.Status = printMsgErr
printMsg.Comment = err.Error()
dao.UpdateEntity(db, printMsg, "Status", "Comment")
if printRemoteAddrIP, have := PrintIpAndAddr.GetPrintIpAndAddr(key); have {
PrintIpAndAddr.DelPrintIpAndAddr(key)
PrintAddrAndIp.DelPrintAddrAndIp(printRemoteAddrIP)
PrintObject.DelPrintObj(key)
}
return
}
if _, err = c.Write(data); err != nil {
globals.SugarLogger.Debugf("handleTcpMessages err [%v]", err)
if printRemoteAddrIP, have := PrintIpAndAddr.GetPrintIpAndAddr(key); have {
PrintIpAndAddr.DelPrintIpAndAddr(key)
PrintAddrAndIp.DelPrintAddrAndIp(printRemoteAddrIP)
PrintObject.DelPrintObj(key)
}
} else {
//等待回调
dataStr := <-t.CallBackMap[key]
if dataStr != "" {
a, b := getCallbackMsgInfo(dataStr)
t.changePrintMsg(dataStr, a, b)
// 查询打印机是否扣费,未扣费就扣费,已经扣费不做处理
have, err2 := dao.QueryOrderDeductionRecord(db, b, utils.Int64ToStr(a))
if err2 == nil && !have {
// 扣除打印机账号金额
if err = dao.DeductionPrintBalance(db, b); err != nil {
globals.SugarLogger.Debugf("扣除用户打印机金额错误 %s", err)
} else {
// 添加打印记录(支出记录)
if err = dao.AddPrintRecord(db, &model.PrintBillRecord{
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
PrintNo: b,
PayType: 2,
PayMoney: 1, // 固定支出一分钱
OrderId: utils.Int64ToStr(a),
UserId: "",
}); err != nil {
globals.SugarLogger.Debugf("添加打印机订单支付记录错误 %s", err)
}
}
} else {
globals.SugarLogger.Debugf("今天已经扣除过了! %v %d %s", err2, a, b)
}
// 回调重置打印机状态时间
t.Clients[b].StatusTime = time.Now()
//判断音频暂停?
//收到打印成功回调后,如果消息中有音频,需要等待一下,等上一个音频播完
//暂停时间就暂时取的sound标签内内容长度/2
if sounds := regexpSoundSpan.FindStringSubmatch(printMsg.Content); len(sounds) > 0 {
sound := sounds[1]
lenTime := time.Duration(utf8.RuneCountInString(sound)) * time.Second
time.Sleep(lenTime / 2)
}
}
}
}
} else {
globals.SugarLogger.Debugf("doPrint timeout")
return
}
}
}
Pool.AddJob(fn)
return err
}
// HandleCheckTcpHeart 检测心跳
func HandleCheckTcpHeart(t *TcpClient, key string) {
if t.TimeoutMap[key] == true {
statusTime := t.getPrintStatusTime(key)
if !utils.IsTimeZero(statusTime) {
//1分钟内没心跳判断打印机掉线了
if time.Now().Sub(statusTime) > time.Second*75 {
globals.SugarLogger.Debugf("超过一分十秒没有心跳的打印机[%s],当前心跳时间: %s ,上一次心跳时间 : %s", key, utils.Time2TimeStr(time.Now()), utils.Time2TimeStr(statusTime))
changePrinterStatus(key, printerStatusOffline)
// 链接出错,彻底删除换成
if printRemoteAddrIP, have := PrintIpAndAddr.GetPrintIpAndAddr(key); have {
PrintIpAndAddr.DelPrintIpAndAddr(key)
PrintAddrAndIp.DelPrintAddrAndIp(printRemoteAddrIP)
PrintObject.DelPrintObj(key)
}
}
}
} else {
t.getClients(key).C.Close()
close(t.MsgMap[key])
close(t.CallBackMap[key])
//t.delConn(key)
t.clear(key)
// 链接出错,彻底删除换成
if printRemoteAddrIP, have := PrintIpAndAddr.GetPrintIpAndAddr(key); have {
PrintIpAndAddr.DelPrintIpAndAddr(key)
PrintAddrAndIp.DelPrintAddrAndIp(printRemoteAddrIP)
PrintObject.DelPrintObj(key)
}
return
}
}

View File

@@ -0,0 +1,687 @@
package event
import (
"encoding/hex"
"fmt"
"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/business/model/dao"
"git.rosy.net.cn/jx-callback/globals"
"net"
"regexp"
"strconv"
"strings"
"sync"
"time"
)
const (
heartText = "1e000f02000151" // 老版心跳
heartTextNew = "1e001a02000151" // 新版心跳
printText = "1e00180200" // 老版打印回调
printTextNew = "1e00190200" // 新版打印回调
printSuccessText = "1e001802000150" // 老版消息打印
printSuccessTextNew = "1e001902000150" // 新版消息打印
printErrWithoutPaper = "05"
printMsgAlreadySend = 2 //已经发出打印消息
printMsgSuccess = 1 //打印成功
PrintMsgWait = 0 //待打印
printMsgFail = -1 //打印失败(打印机报出)
printMsgErr = -2 //京西报出
PrintMsgAlreadyLoad = 3 //已放入队列
heartErrNormal = "00" //正常
heartErrWithoutPaper = "04" //心跳错,缺纸
heartErrHot = "08" //过热
printerStatusOnlineWithoutPaper = 2 //在线缺纸
printerStatusOnline = 1 //在线
printerStatusOffline = -1 //离线
printerStatusOfflineAll = -9 //其他异常状态
PrintSoundMaxNumber = 16 // 十六进制最大补位
PlaceFillingParam = "0" // 补位参数
)
//标签
const (
signBR = "<br>" //换行
signCenter = "<center>" //居中
signLeft = "<left>" //居左
signRight = "<right>" //居右
signBig = "<b>" //字体放大
signHighBig = "<hb>" //字体纵向放大
signWideBig = "<wb>" //字体横向放大
signQrCenter = "<qrc>" //二维码居中
signQrLeft = "<qrl>" //二维码居左
signQrRight = "<qrr>" //二维码居右
signSound, signSoundEnd = "<sound>", "</sound>" // 声音结束标签
// GPRS通讯说明打印机识别二进制码
hexSignBROrEXE = "0a" // 换行
hexSignCenter = "1b6101" // 居中打印
hexSignLeft = "1b6100" // 恢复居左打印
hexSignRight = "1b6102" // 居右打印
hexSignNormal = "1b2100"
hexSignBig = "1b2130" // 横向及纵向都放大
hexSignHighBig = "1b2110" // 倍高
hexSignWideBig = "1b2120" // 倍宽
hexSignQrCenter = "1d5802" // 二维码居中
hexSignQrLeft = "1d5800" // 二维码居左
hexSignQrRight = "1d5804" // 二维码居右
hexSignQr = "1b5a000106" // "1b5a000106" 0600 : 后面二维码的字节数
hexSignQrEnd = "000a1b40" // 000a0a0a1b40
hexSignSound = "1d6b40" // 音频指令(自定义语音指令)
hexSignSoundSolidification = "1B594155" // 音频指令(固化指令)
//起始标签 -- 自定义标签utf8转码为gbk字符集
byteSignBR = "3c62723e" // 换行
byteSignCenter = "3c63656e7465723e" // 居中
byteSignLeft = "3c6c6566743e" // 居左
byteSignRight = "3c72696768743e" // 居右
byteSignBig = "3c623e" // 字体放大
byteSignHighBig = "3c68623e" // 字体纵向放大
byteSignWideBig = "3c77623e" // 字体横向放大
byteSignQrCenter = "3c7172633e" // 二维码居中
byteSignQrLeft = "3c71726c3e" // 二维码居左
byteSignQrRight = "3c7172723e" // 二维码居右
byteSignSound = "3c736f756e643e" // 声音
//结束标签
byteSignCenterE = "3c2f63656e7465723e" // 居中
byteSignLeftE = "3c2f6c6566743e" // 居左
byteSignRightE = "3c2f72696768743e" // 居右
byteSignBigE = "3c2f623e" // 字体放大
byteSignHighBigE = "3c2f68623e" // 字体纵向放大
byteSignWideBigE = "3c2f77623e" // 字体横向放大
byteSignQrCenterE = "3c2f7172633e" // 二维码居中
byteSignQrLeftE = "3c2f71726c3e" // 二维码居左
byteSignQrRightE = "3c2f7172723e" // 二维码居右
byteSignSoundE = "3c2f736f756e643e" // 声音
)
var (
printErrMap = map[string]string{
printErrWithoutPaper: "打印机缺纸!",
}
signMap = map[string]string{
byteSignBR: hexSignBROrEXE,
}
regexpQrc = regexp.MustCompile(byteSignQrCenter + "(.*?)" + byteSignQrCenterE)
regexpQrl = regexp.MustCompile(byteSignQrLeft + "(.*?)" + byteSignQrLeftE)
regexpQrr = regexp.MustCompile(byteSignQrRight + "(.*?)" + byteSignQrRightE)
regexpSound = regexp.MustCompile(byteSignSound + "(.*?)" + byteSignSoundE)
regexpSoundSpan = regexp.MustCompile(signSound + "(.*?)" + signSoundEnd)
)
type PrintInfo struct {
C net.Conn
Status int // 2 //在线缺纸 1 //在线 -1 //离线
StatusTime time.Time
}
//type PrintPoolMap struct {
// *sync.RWMutex
// PrintObj *TcpClient
//}
//连接的客户端,吧每个客户端都放进来
type TcpClient struct {
Clients map[string]*PrintInfo //放tcp连接的printNo 为key
MsgMap map[string]chan *model.PrintMsg //放打印信息的printNo为key
CallBackMap map[string]chan string //放打印信息回调信息的printNo为key
TimeoutMap map[string]bool //退出channel
*sync.RWMutex
}
type GetPrintStatus struct {
PrintNo string //打印机编号
AppID int
}
//从连接池删除,并关闭连接
func (t *TcpClient) delConn(key string) {
t.Lock()
defer t.Unlock()
if t.Clients[key].C != nil {
globals.SugarLogger.Debugf("-------close2 := %s", key)
t.Clients[key].C.Close()
}
delete(t.Clients, key)
}
func (t *TcpClient) clear(key string) {
t.Lock()
defer t.Unlock()
t.Clients[key].C.Close()
delete(t.Clients, key)
close(t.MsgMap[key])
delete(t.MsgMap, key)
close(t.CallBackMap[key])
delete(t.CallBackMap, key)
delete(t.TimeoutMap, key)
}
//添加到连接池中
func addConn(c net.Conn, t *TcpClient, key string, status int) {
t.Lock()
defer t.Unlock()
t.Clients[key] = &PrintInfo{
C: c,
Status: status,
StatusTime: time.Now(),
}
}
func (t *TcpClient) buildMsgMap(key string) {
t.Lock()
defer t.Unlock()
dataChan := make(chan *model.PrintMsg, 1024)
t.MsgMap[key] = dataChan
}
func (t *TcpClient) buildCallBackMap(key string) {
t.Lock()
defer t.Unlock()
dataChan := make(chan string, 1024)
t.CallBackMap[key] = dataChan
}
func (t *TcpClient) buildTimeoutMap(key string) {
t.Lock()
defer t.Unlock()
//dataChan := make(chan bool)
//t.TimeoutMap[key] = dataChan
t.TimeoutMap[key] = true
}
func (t *TcpClient) getTimeOut(key string) bool {
t.RLock()
defer t.RUnlock()
//return <-t.TimeoutMap[key]
return t.TimeoutMap[key]
}
func buildAllMap(t *TcpClient, key string) {
t.Lock()
defer t.Unlock()
t.MsgMap[key] = make(chan *model.PrintMsg, 1024)
t.CallBackMap[key] = make(chan string, 1024)
t.TimeoutMap[key] = true
}
func BuildAllMap(t *TcpClient, key string) {
buildAllMap(t, key)
}
func (t *TcpClient) getPrintStatus(key string) int {
t.RLock()
defer t.RUnlock()
if t.Clients[key] != nil {
return t.Clients[key].Status
} else {
return printerStatusOfflineAll
}
}
func (t *TcpClient) getPrintConn(key string) net.Conn {
t.RLock()
defer t.RUnlock()
if t.Clients[key] != nil {
return t.Clients[key].C
} else {
return nil
}
}
func (t *TcpClient) getPrintStatusTime(key string) time.Time {
t.RLock()
defer t.RUnlock()
if t.Clients[key] != nil {
return t.Clients[key].StatusTime
} else {
return utils.ZeroTimeValue
}
}
// 获取连接对象
func (t *TcpClient) getClients(key string) *PrintInfo {
t.RLock()
defer t.RUnlock()
return t.Clients[key]
}
func (t *TcpClient) isExistMsg(key string) bool {
t.RLock()
defer t.RUnlock()
if t.MsgMap[key] == nil {
return false
} else {
return true
}
}
func (t *TcpClient) isExistCallback(key string) bool {
t.RLock()
defer t.RUnlock()
if t.CallBackMap[key] == nil {
return false
} else {
return true
}
}
func (t *TcpClient) isExist(key string) bool {
t.RLock()
defer t.RUnlock()
if t.Clients[key] == nil {
return false
} else {
return true
}
}
func (t *TcpClient) setPrintStatus(key string, status int) {
t.Lock()
defer t.Unlock()
if t.Clients[key] != nil {
t.Clients[key].Status = status
//t.Clients[key].StatusTime = time.Now()
}
}
func (t *TcpClient) setPrintStatusTime(key string) {
t.Lock()
defer t.Unlock()
if t.Clients[key] != nil {
//t.Clients[key].Status = status
t.Clients[key].StatusTime = time.Now()
}
}
func (t *TcpClient) addMsgChan(printMsg *model.PrintMsg) (err error) {
t.Lock()
defer func() {
t.Unlock()
if r := recover(); r != nil && r.(error).Error() == "send on closed channel" {
err = fmt.Errorf("send on closed channel")
}
}()
if t.MsgMap[printMsg.PrintNo] == nil {
dataChan := make(chan *model.PrintMsg, 1024)
t.MsgMap[printMsg.PrintNo] = dataChan
}
t.MsgMap[printMsg.PrintNo] <- printMsg
return err
}
func (t *TcpClient) addCallbackChan(key, data string) {
t.Lock()
defer t.Unlock()
if t.CallBackMap[key] == nil {
dataChan := make(chan string, 1024)
t.CallBackMap[key] = dataChan
}
t.CallBackMap[key] <- data
}
func (t *TcpClient) GetCallbackChan(key string) string {
t.RLock()
defer t.RUnlock()
if t.CallBackMap[key] == nil {
return ""
}
return <-t.CallBackMap[key]
}
func NewTcpClient() *TcpClient {
t := &TcpClient{
Clients: make(map[string]*PrintInfo),
CallBackMap: make(map[string]chan string),
MsgMap: make(map[string]chan *model.PrintMsg),
TimeoutMap: make(map[string]bool, 0),
}
t.RWMutex = new(sync.RWMutex)
return t
}
func printStatus2JxStatus(printStatus string) (status int) {
if printStatus == heartErrWithoutPaper {
return printerStatusOnlineWithoutPaper
} else if printStatus == heartErrNormal {
return printerStatusOnline
}
return status
}
func getCallbackMsgInfo(data string) (orderNo int64, printNo string) {
orderNo = h8l82int(data[len(data)-6:len(data)-4], data[len(data)-4:len(data)-2])
printNoData, _ := hex.DecodeString(data[len(printSuccessText) : len(data)-6])
printNo = string(printNoData)
return orderNo, printNo
}
func changePrinterStatus(printNo string, status int) {
var (
db = dao.GetDB()
)
if printer, err := dao.GetPrinter(db, printNo); err == nil && printer != nil {
var feilds []string
if printer.Status != status {
printer.Status = status
feilds = append(feilds, "Status")
}
isOnline := 0
if status == printerStatusOnline || status == printerStatusOnlineWithoutPaper {
isOnline = model.YES
} else {
isOnline = model.NO
printer.OfflineCount++
feilds = append(feilds, "OfflineCount")
}
if isOnline != printer.IsOnline {
printer.IsOnline = isOnline
feilds = append(feilds, "IsOnline")
}
if len(feilds) > 0 {
dao.UpdateEntity(db, printer, feilds...)
}
}
}
//按打印机方提供的文档来的
func buildMsg(printMsg *model.PrintMsg) (data []byte, err error) {
var (
content = printMsg.Content
orderNo = printMsg.OrderNo
str = "1e"
const1 = "0200ff50"
printInit = "1b40" //打印机初始化
//voice = "1d6b401dfd001a01015b7631365d736f756e64622cc4fad3d0d0c2b6a9b5a5c0b1" //语音,中国
//qr = "1d58021b5a0001061600747470733a2f2f7777772e62616964752e636f6d2f1b000A0A0A1B40"
orderNoHexH, orderNoHexL, printData string
)
//写入数据
no, err := strconv.ParseInt(orderNo, 10, 64)
if err != nil {
globals.SugarLogger.Debug("order_msg Order_no 转换异常")
}
orderNoHexH, orderNoHexL = int2h8l8(no)
// 将数据与模板组装
if strings.Contains(content, "•") {
content = strings.ReplaceAll(content, "•", "-")
}
printDataGBK, _ := jxutils.Utf8ToGbk([]byte(utils.FilterEmoji(content)))
printData = hex.EncodeToString(printDataGBK)
printData = replaceContent(printData, printMsg)
lenData := int64(len(str) + len(const1) + len(orderNoHexH) + len(orderNoHexL) + len(printInit) + 2 + 4 + len(printData))
x1, x2 := int2h8l8(lenData / 2)
dataStr := str + x1 + x2 + const1 + orderNoHexH + orderNoHexL + printInit + printData
check := getCheckSum(dataStr)
return jxutils.Hextob(dataStr + check), err
}
func getCheckSum(str string) (check string) {
var sum int64
for i := 0; i < len(str); i = i + 2 {
b := string(str[i]) + string(str[i+1])
bt, _ := strconv.ParseInt(b, 16, 32)
sum += bt
}
_, check = int2h8l8(sum)
return check
}
//内容中的标签替换成指令
func replaceContent(content string, printMsg *model.PrintMsg) (result string) {
var (
lenqr int
hexLenqr string
)
result = content
for k, v := range signMap {
if strings.Contains(result, k) {
result = strings.ReplaceAll(result, k, v)
}
}
// 居中标签
if strings.Contains(result, byteSignCenter) && strings.Contains(result, byteSignCenterE) {
result = strings.ReplaceAll(result, byteSignCenter, hexSignCenter)
result = strings.ReplaceAll(result, byteSignCenterE, hexSignBROrEXE+hexSignLeft)
}
// 居左标签
if strings.Contains(result, byteSignLeft) && strings.Contains(result, byteSignLeftE) {
result = strings.ReplaceAll(result, byteSignLeft, hexSignLeft)
result = strings.ReplaceAll(result, byteSignLeftE, hexSignBROrEXE+hexSignLeft)
}
// 居右标签
if strings.Contains(result, byteSignRight) && strings.Contains(result, byteSignRightE) {
result = strings.ReplaceAll(result, byteSignRight, hexSignRight)
result = strings.ReplaceAll(result, byteSignRightE, hexSignBROrEXE+hexSignLeft)
}
// 字体放大
if strings.Contains(result, byteSignBig) && strings.Contains(result, byteSignBigE) {
result = strings.ReplaceAll(result, byteSignBig, hexSignBig)
result = strings.ReplaceAll(result, byteSignBigE, hexSignBROrEXE+hexSignNormal)
}
// 字体高大
if strings.Contains(result, byteSignHighBig) && strings.Contains(result, byteSignHighBigE) {
result = strings.ReplaceAll(result, byteSignHighBig, hexSignHighBig)
result = strings.ReplaceAll(result, byteSignHighBigE, hexSignBROrEXE+hexSignNormal)
}
// 字体宽大
if strings.Contains(result, byteSignWideBig) && strings.Contains(result, byteSignWideBigE) {
result = strings.ReplaceAll(result, byteSignWideBig, hexSignWideBig)
result = strings.ReplaceAll(result, byteSignWideBigE, hexSignBROrEXE+hexSignNormal)
}
// 二维码居中
if strings.Contains(result, byteSignQrCenter) && strings.Contains(result, byteSignQrCenterE) {
if qrs := regexpQrc.FindStringSubmatch(result); len(qrs) > 0 {
lenqr = len(qrs[1]) / 2
hexLenqr = fmt.Sprintf("%x", lenqr)
if len(hexLenqr) < 2 {
hexLenqr = "0" + hexLenqr
}
}
result = strings.ReplaceAll(result, byteSignQrCenter, hexSignQrCenter+hexSignQr+hexLenqr+"00")
result = strings.ReplaceAll(result, byteSignQrCenterE, hexSignQrEnd)
}
// 二维码局左
if strings.Contains(result, byteSignQrLeft) && strings.Contains(result, byteSignQrLeftE) {
if qrs := regexpQrl.FindStringSubmatch(result); len(qrs) > 0 {
lenqr = len(qrs[1]) / 2
hexLenqr = fmt.Sprintf("%x", lenqr)
if len(hexLenqr) < 2 {
hexLenqr = "0" + hexLenqr
}
}
result = strings.ReplaceAll(result, byteSignQrLeft, hexSignQrLeft+hexSignQr+hexLenqr+"00")
result = strings.ReplaceAll(result, byteSignQrLeftE, hexSignQrEnd)
}
// 二维码居右
if strings.Contains(result, byteSignQrRight) && strings.Contains(result, byteSignQrRightE) {
if qrs := regexpQrr.FindStringSubmatch(result); len(qrs) > 0 {
lenqr = len(qrs[1])
hexLenqr = fmt.Sprintf("%x", lenqr)
if len(hexLenqr) < 2 {
hexLenqr = "0" + hexLenqr
}
}
result = strings.ReplaceAll(result, byteSignQrRight, hexSignQrRight+hexSignQr+hexLenqr+"00")
result = strings.ReplaceAll(result, byteSignQrRightE, hexSignQrEnd)
}
// 固定模板输出语音
if strings.Contains(result, byteSignSound) && strings.Contains(result, byteSignSoundE) {
var soundStr []string
for _, v1 := range strings.Split(result, byteSignSoundE) {
v1 += byteSignSoundE
if sounds := regexpSound.FindStringSubmatch(v1); len(sounds) > 0 {
sound := sounds[1]
// 将语音包转换为十六进制
voice := ""
for _, v := range strings.Split(sound, "2c") {
voice += hexSignSoundSolidification
soundNum, _ := hex.DecodeString(v) // 十六进制转字符串
intSound, _ := strconv.ParseInt(string(soundNum), 10, 64)
int16Sound := strconv.FormatInt(intSound, 16)
if intSound < PrintSoundMaxNumber { // 小于十六补位
voice += PlaceFillingParam + int16Sound
} else {
voice += int16Sound
}
}
soundStr = append(soundStr, voice)
}
}
result = strings.ReplaceAll(result, byteSignSound, "*")
result = strings.ReplaceAll(result, byteSignSoundE, "&")
for i := 0; i < len(soundStr); i++ {
start := strings.Index(result, "*")
end := strings.Index(result, "&")
result = strings.Replace(result, result[start:end+1], soundStr[i], 1)
}
}
// 自动合成语音功能
//if strings.Contains(result, byteSignSound) && strings.Contains(result, byteSignSoundE) {
// if sounds := regexpSound.FindStringSubmatch(result); len(sounds) > 0 {
// sound := sounds[1]
// if printer, _ := dao.GetPrinter(dao.GetDB(), printMsg.PrintNo); printer != nil {
// //先把结束标签消了
// result = strings.ReplaceAll(result, byteSignSoundE, "")
// soundPrefix := ""
// if printer.Sound != "" {
// soundPrefix = "[v" + utils.Int2Str(printer.Volume*2) + "]" + printer.Sound
// } else {
// soundPrefix = "[v" + utils.Int2Str(printer.Volume*2) + "]"
// }
// hexPrefix, _ := jxutils.Utf8ToGbk([]byte(soundPrefix))
// hexPrefixStr := hex.EncodeToString(hexPrefix)
// realSound := hexPrefixStr + sound
// allLen := fmt.Sprintf("%x", (len("fd001a0101")+len(realSound))/2)
// if len(allLen) < 2 {
// allLen = "0" + allLen
// }
// soundLenH, soundLenX := int2h8l8(int64((len(realSound) + len("0101")) / 2))
// result = strings.ReplaceAll(result, byteSignSound, hexSignSound+allLen+"fd"+soundLenH+soundLenX+"0100"+hexPrefixStr)
// }
// }
//}
return result
}
func checkPrintMsg(db *dao.DaoDB, printMsg *model.PrintMsg) (err error) {
if printMsg.Content == "" {
return fmt.Errorf("此打印信息内容为空printMsg printNo:[%v], orderNo :[%v] 1", printMsg.PrintNo, printMsg.OrderNo)
}
if printMsg.PrintNo == "" {
return fmt.Errorf("此打印信息打印机编号为空printMsg printNo:[%v], orderNo :[%v] 2", printMsg.PrintNo, printMsg.OrderNo)
}
if printMsg.OrderNo == "" {
return fmt.Errorf("此打印信息订单序号为空printMsg printNo:[%v], orderNo :[%v] 3", printMsg.PrintNo, printMsg.OrderNo)
}
//if printer, err := dao.GetPrinter(db, printMsg.PrintNo); err == nil {
// if printer != nil {
// if printer.FlowFlag == 1 {
// return fmt.Errorf("此打印机当月流量已用完请及时充值printNo:[%v]", printMsg.PrintNo)
// }
// }
//}
return err
}
func int2h8l8(i int64) (h, l string) {
origin2 := fmt.Sprintf("%b", i)
flag := 16 - len(origin2)
for i := 0; i < flag; i++ {
origin2 = "0" + origin2
}
begin8 := origin2[:8]
end8 := origin2[8:]
r1, _ := strconv.ParseInt(begin8, 2, 32)
r2, _ := strconv.ParseInt(end8, 2, 32)
h = fmt.Sprintf("%x", r1)
l = fmt.Sprintf("%x", r2)
if len(h)%2 != 0 {
h = "0" + h
}
if len(l)%2 != 0 {
l = "0" + l
}
return h, l
}
func h8l82int(h, l string) (i int64) {
s1, s2 := xtob(h), xtob(l)
flag1 := 8 - len(s1)
flag2 := 8 - len(s2)
for m := 0; m < flag1; m++ {
s1 = "0" + s1
}
for j := 0; j < flag2; j++ {
s2 = "0" + s2
}
i, _ = strconv.ParseInt(s1+s2, 2, 32)
return i
}
func xtob(x string) string {
base, _ := strconv.ParseInt(x, 16, 10)
return strconv.FormatInt(base, 2)
}
// Heartbeat 心跳回调
func Heartbeat(c net.Conn, t *TcpClient, data string, printNo string, printRemoteAddr string) {
//printNoData, _ := hex.DecodeString(data[len(heartText) : len(data)-8])
//printNo = string(printNoData)
status := printStatus2JxStatus(data[len(data)-8 : len(data)-6])
//如果没在连接池里
//1、加到连接池中不同的打印机no开不同的goroutine
//2、初始化channel每个打印机一个放打印消息和打印回调消息
//3、读数据库里的待打印信息放到打印channel中
//4、读打印channel并打印并切等待回调channel中的消息
//5、修改数据库中打印机状态没在连接池中说明是重新连接的
//6、监听心跳时间超过1分多钟就clear掉
if t.getClients(printNo) == nil || t == nil || t.getPrintStatusTime(printNo).IsZero() || time.Now().Sub(t.Clients[printNo].StatusTime).Seconds() >= 120 {
addConn(c, t, printNo, status)
buildAllMap(t, printNo)
//t.TimeoutMap[printNo] <- true
HandleTcpMessages(t, printNo)
doPrint(t, printNo)
if status == printerStatusOnline {
//t.printFail()
}
//changePrinterStatus(printNo, status)
// todo 暂时关闭心跳检测
HandleCheckTcpHeart(t, printNo)
// todo 证明打印机已经被激活,将激活打印机存入数据库,保证用户不能无限制绑定打印机
if err := dao.NotExistsCreate(printNo); err != nil {
globals.SugarLogger.Debugf("监听打印机心跳,不存在则创建 :[%v],printNo[%s]", err, printNo)
}
PrintObject.SetPrintObj(printNo, t)
PrintAddrAndIp.SetPrintAddrAndIp(printRemoteAddr, printNo)
PrintIpAndAddr.SetPrintIpAndAddr(printNo, printRemoteAddr)
} else {
//在加到连接池中已经更新了时间所以放在else里
t.setPrintStatusTime(printNo)
}
//状态不一致再更新状态(可能缺纸了,过热了等)
t.setPrintStatus(printNo, status)
changePrinterStatus(printNo, status)
}
// Callback 打印成功回调
func Callback(c net.Conn, t *TcpClient, data string, printNo string) {
//打印消息发送后打印机会回调该条打印消息的状态打印成功or失败失败原因..
//将回调的信息放到回调channel中打印成功后再打印下一条消息
//_, printNo = getCallbackMsgInfo(data)
//更新打印机心跳时间(打印机本身不会在打印的同时,或回调的同时发心跳消息,会导致心跳判断超时,这里更新一下)
t.setPrintStatusTime(printNo)
t.addCallbackChan(printNo, data)
}

View File

@@ -0,0 +1,117 @@
package event
import (
"encoding/hex"
"fmt"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/model"
"strconv"
"strings"
"testing"
"time"
"unicode/utf8"
)
func TestPrintMsg(t *testing.T) {
msg := &model.PrintMsg{
ModelIDCULD: model.ModelIDCULD{},
PrintNo: "120220915001069",
Content: "<left><hb>客户地址:瑞小满颐园 (瑞小满•颐园正门 门卫大叔 就可以 拍照反馈 辛苦谢谢)@#四川省成都市金牛区天回镇街道瑞小满•熊猫颐园</hb></left>",
OrderNo: "12", // 2147483648111
Status: 0,
Comment: "",
MsgID: "20221216175529_09440117",
}
data, err := buildMsg(msg)
fmt.Println("data=", string(data))
fmt.Println("err=", err)
}
// 十六进制转字符串
func TestDC(t *testing.T) {
str := "093c736f756e643e323009091b61011b2130bea9cef7b9fbd4b00a1b21000a1b61000a0a09091b6101cad6bbfac2f2b2cbc9cfbea9cef70a1b61000a1b6101bcabcbd9b5bdbcd2cbcdbeaacfb20a1b61000a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0acfc2b5a5cab1bce43a20323032312d30382d32372032313a35373a32360ad4a4bcc6cbcdb4ef3a20323032312d30382d32372032323a35373a32360ab6a9b5a5b1e0bac53a2039333135343434313733303231313130300a0a1b2130c3c0cdc5cde2c2f42331390a1b21000a1d58021b5a00010611003933313534343431373330323131313030000a1b400abfcdbba73a20c0eeb4f3c3ce28cfc8c9fa290ab5e7bbb03a2031353938373230303334300ab5d8d6b73a20b1b1c6d6ceb0d2b5b9e3b3a12d32bac5c2a52028ceb0d2b5b9e3b3a142c7f8294023d4c6c4cfcaa1b3fed0dbd2cdd7e5d7d4d6ced6ddb3fed0dbcad0c2b9b3c7d5f2ceb0d2b5b9e3b3a10a0abfcdbba7b1b8d7a23a200a1b2130a1bec8e7d3f6c8b1bbf5a1bfa3ba20c8b1bbf5cab1b5e7bbb0d3ebced2b9b5cda80a1b21000a0a0ac9ccc6b7c3f7cfb83a200ac6b7c3fb20202020cafdc1bf20202020b5a5bcdb20202020202020d0a1bcc60a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0aa1bed7d4d3c9c6b4a1bfcfb4bebbbaeccce1313630672fbad00a20202020202078312020202020a3a4392e32302020202020a3a4392e32300aa1beb9fbc7d0a1bf20c5a3c4ccc4beb9cfd4bc333030672fb7dd0a20202020202078312020202020a3a4392e37302020202020a3a4392e37300aa1bed7d4d3c9c6b4a1bfd1cfd1a1cfe3bdb6b9fbc7d0313830672fbad00a20202020202078312020202020a3a4382e38302020202020a3a4382e38300a5bcdf8baecb9fbc7d05dcedac3b7d0a1b7acc7d13235672fb8f60a20202020207831302020202020a3a4302e38302020202020a3a4382e30300a5bcfd6b0fe5dccf0caafc1f1d7d1d4bc323530672fb7dd2831b8f6290a20202020202078312020202020a3a4332e35302020202020a3a4332e35300aa1beb1acc6b7ccd8bbdda1bfd0c2cfcab4e0ccf0b0ebbdefb9fec3dcb9cf20b9fec3dbb9cfb9fbc7d0d2bbbad0323530672fbad0283233307e32363067290a20202020202078312020202020a3a4302e30312020202020a3a4302e30310aa1beb1acc6b7ccd8bbdda1bfd0c2cfcab4e0ccf0b0ebbdefb9fec3dcb9cf20b9fec3dbb9cfb9fbc7d0d2bbbad0323530672fbad0283233307e32363067290a20202020202078312020202020a3a4382e36302020202020a3a4382\ne36300a0ab9b237d6d63136bcfec9ccc6b70a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0a1b61011b2110c9ccc6b7d6cac1bfcecacce2c7ebc1aacfb53a0a1b21000a1b61000a1b61011b2110bea9cef7b9fbd4b0a1a4b9fbc7d0a1a4cbaeb9fbc0cca3a8b9fbb9fbceddb5eaa3a93a31353834313031313339370a1b21000a1b61000a0ab8fcb6e0d0c5cfa2c7ebb9d8d7a2b9d9b7bdcea2d0c53a20bea9cef7b2cbcad00a0a0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d0a0a0a"
str2, _ := hex.DecodeString(str)
fmt.Println(string(str2))
}
// 十进制字符串转十六进制
func Test10Two16(t *testing.T) {
//fmt.Println(strconv.FormatInt(11, 16)) // 2 to 10
//for _, v := range strings.Split("324c", "d") {
// fmt.Println(v)
//}
hexPrefix, _ := jxutils.Utf8ToGbk([]byte("[8]sounda14"))
hexPrefixStr := hex.EncodeToString(hexPrefix)
fmt.Println(hexPrefixStr)
}
func TestCheckSum(t *testing.T) {
soundNum, _ := hex.DecodeString("3130") // 十六进制转字符串
intSound, _ := strconv.ParseInt(string(soundNum), 10, 64)
int16Sound := strconv.FormatInt(intSound, 16)
b := strconv.FormatInt(16, 16)
if int16Sound < b {
fmt.Println("111111")
} else {
fmt.Println("22222")
}
fmt.Println("==========", int16Sound)
fmt.Println("======2====", utf8.RuneCountInString("64,65,66"))
}
func TestTen216(t *testing.T) {
aa := `
3c736f756e643e
312c322c33
3c2f736f756e643e
1b6101bed3d6d0cec4d7d60a1b6100
3c736f756e643e
342c352c36
3c2f736f756e643e
1b6101bed3d6d00a1b6100
`
bb := `1B59415501 1B59415502 1B59415503`
kk := `1B59415501 1B59415502 1B59415503 1b6101bed3d6d0cec4d7d60a1b6100 1b6101bed3d6d0cec4d7d60a1b6100 1B59415504 1B59415505 1B59415506 1b6101bed3d6d00a1b6100`
// 第一个语音字段
index1 := strings.Index(aa, "3c736f756e643e")
index2 := strings.Index(aa, "3c2f736f756e643e")
str := aa[index1:index2]
gg := strings.Replace(aa, str, bb, 1)
fmt.Println(gg)
fmt.Println(kk)
}
func TestNewPool(t *testing.T) {
var pool = NewPool(100)
pool.Start()
for i := 0; i < 10; i++ {
num := i
pool.AddJob(func() {
fmt.Printf("Worker %d: %d is odd? %v\n", num%5, num, num%2 == 1)
})
}
time.Sleep(5 * time.Second)
for i := 0; i < 10; i++ {
pool.AddJob(func() {
fmt.Println("刘磊")
})
}
pool.Wait()
pool.Stop()
}
func TestCC(t *testing.T) {
var aa map[string]string
aa = make(map[string]string, 10)
fmt.Println(aa)
aa["1"] = "2"
c, d := aa["1"]
fmt.Println(c)
fmt.Println(d)
}

View File

@@ -0,0 +1,157 @@
package event
import (
"sync"
"time"
)
// 全局单例线程池初始化500个worker
var Pool *WorkerPool
func init() {
Pool = NewWorkerPool(500, 1024) // 500个worker任务队列长度1024
Pool.Start()
}
// Job 任务定义
type Job func()
// Worker 工作协程
type Worker struct {
id int
jobChan chan Job
quitChan chan struct{}
closeOnce sync.Once
}
// WorkerPool 线程池
type WorkerPool struct {
workers []*Worker
jobChan chan Job
wg sync.WaitGroup
closeOnce sync.Once
closed bool
mu sync.Mutex
}
// ----------------------------------------------------
// 创建 Worker
// ----------------------------------------------------
func NewWorker(id int, jobChan chan Job) *Worker {
return &Worker{
id: id,
jobChan: jobChan,
quitChan: make(chan struct{}),
}
}
// Start 启动Worker自带panic恢复
func (w *Worker) Start() {
go func() {
defer func() {
if r := recover(); r != nil {
// 打印panic日志防止整个worker崩溃
// log.Printf("worker %d panic recovered: %v", w.id, r)
}
}()
for {
select {
case job, ok := <-w.jobChan:
if !ok {
return
}
job()
case <-w.quitChan:
return
}
}
}()
}
// Stop 安全停止Worker
func (w *Worker) Stop() {
w.closeOnce.Do(func() {
close(w.quitChan)
})
}
// ----------------------------------------------------
// 创建线程池
// ----------------------------------------------------
func NewWorkerPool(workerCount int, queueSize int) *WorkerPool {
jobChan := make(chan Job, queueSize) // 带缓冲队列,高并发不阻塞
pool := &WorkerPool{
workers: make([]*Worker, workerCount),
jobChan: jobChan,
}
for i := 0; i < workerCount; i++ {
pool.workers[i] = NewWorker(i, jobChan)
}
return pool
}
// Start 启动所有worker
func (p *WorkerPool) Start() {
for _, w := range p.workers {
w.Start()
}
}
// AddJob 提交任务非阻塞、安全、不panic
func (p *WorkerPool) AddJob(job Job) bool {
p.mu.Lock()
closed := p.closed
p.mu.Unlock()
if closed {
return false
}
p.wg.Add(1)
select {
case p.jobChan <- func() {
defer p.wg.Done()
job()
}:
return true
case <-time.After(10 * time.Millisecond):
// 队列满了,不阻塞,快速失败
p.wg.Done()
return false
}
}
// Wait 等待所有任务执行完成
func (p *WorkerPool) Wait() {
p.wg.Wait()
}
// Stop 优雅关闭线程池安全不panic
func (p *WorkerPool) Stop() {
p.closeOnce.Do(func() {
p.mu.Lock()
p.closed = true
p.mu.Unlock()
// 1. 关闭任务通道
close(p.jobChan)
// 2. 停止所有worker
for _, w := range p.workers {
w.Stop()
}
// 3. 等待所有任务执行完
p.Wait()
})
}
// IsClosed 判断线程池是否关闭
func (p *WorkerPool) IsClosed() bool {
p.mu.Lock()
defer p.mu.Unlock()
return p.closed
}

View File

@@ -0,0 +1,243 @@
package financial
import (
_ "fmt"
"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/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
"github.com/astaxie/beego/client/orm"
"time"
)
func AddMixPay(txDB orm.TxOrmer, orderID string, balancePrice, totalPrice, status int) error {
mixPayInfo := &model.MixPay{
OrderID: orderID,
BalancePrice: balancePrice,
TotalPrice: totalPrice,
Status: status,
WxPrice: totalPrice - balancePrice,
}
dao.WrapAddIDCULEntity(mixPayInfo, jxcontext.AdminCtx.GetUserName())
return dao.CreateEntityTx(txDB, mixPayInfo)
}
func AddBillIncome(txDB orm.TxOrmer, billID int64, billType, incomePrice, jobID int) (err error) {
billIncome := &model.BillIncome{
BillID: billID,
Type: billType,
IncomePrice: incomePrice,
JobID: jobID,
}
dao.WrapAddIDCULEntity(billIncome, jxcontext.AdminCtx.GetUserName())
return dao.CreateEntityTx(txDB, billIncome)
}
func AddBillExpend(txDB orm.TxOrmer, billID int64, billType, expendPrice, jobID int) (err error) {
billExpend := &model.BillExpend{
BillID: billID,
Type: billType,
ExpendPrice: expendPrice,
JobID: jobID,
}
dao.WrapAddIDCULEntity(billExpend, jxcontext.AdminCtx.GetUserName())
return dao.CreateEntityTx(txDB, billExpend)
}
func AddUserBill(txDB orm.TxOrmer, billID int64, userID string) (err error) {
userBillInsert := &model.UserBill{
BillID: billID,
UserID: userID,
}
dao.WrapAddIDCULDEntity(userBillInsert, jxcontext.AdminCtx.GetUserName())
return dao.CreateEntityTx(txDB, userBillInsert)
}
func AddUserBillDb(db *dao.DaoDB, billID int64, userID string) (err error) {
userBillInsert := &model.UserBill{
BillID: billID,
UserID: userID,
}
dao.WrapAddIDCULDEntity(userBillInsert, jxcontext.AdminCtx.GetUserName())
return dao.CreateEntity(db, userBillInsert)
}
func GetUserBillDetail(ctx *jxcontext.Context, userID, fromTime, toTime string, pageSize, offset int) (pagedInfo *model.PagedInfo, err error) {
return dao.GetUserBillDetail(dao.GetDB(), userID, utils.Str2Time(fromTime), utils.Str2Time(toTime), pageSize, offset)
}
func AddExpendUpdateAccount(txDB orm.TxOrmer, userBill *model.UserBill, billType, price, jobID int) (err error) {
//1、账户支出增加一条记录
err = AddBillExpend(txDB, userBill.BillID, billType, price, jobID)
if err != nil {
return err
}
//2、账户表余额减少相应值
userBill.AccountBalance -= price
_, err = dao.UpdateEntityTx(txDB, userBill, "AccountBalance")
return err
}
func AddIncomeUpdateAccount(txDB orm.TxOrmer, userBill *model.UserBill, billType, price, jobID int) (err error) {
//2、账户收入增加一条记录
err = AddBillIncome(txDB, userBill.BillID, billType, price, jobID)
if err != nil {
return err
}
//1、根据任务剩余数量退钱到账户余额中
userBill.AccountBalance += price
_, err = dao.UpdateEntityTx(txDB, userBill, "AccountBalance")
return err
}
func SettleUnionOrders(ctx *jxcontext.Context, vendorIDs []int) (err error) {
var (
db = dao.GetDB()
unionOrderVendorMap map[int][]*model.UnionOrder //key 为平台ID
unionOrderMap map[string]map[int][]*model.UnionOrder //key为userID整个map把每个User的不同平台的订单放一起
settleOrders []*model.UnionOrderSettle
)
unionOrderVendorMap = make(map[int][]*model.UnionOrder)
unionOrderMap = make(map[string]map[int][]*model.UnionOrder)
unionOrders, err := dao.GetUnionOrders(db, vendorIDs, []int{model.UnionOrderStatusFinish}, utils.ZeroTimeValue, utils.ZeroTimeValue, model.NO)
if err != nil {
return err
}
for _, v := range unionOrders {
if _, ok := unionOrderMap[v.UserID]; ok {
if _, ol := unionOrderVendorMap[v.VendorID]; ol {
unionOrderMap[v.UserID][v.VendorID] = append(unionOrderMap[v.UserID][v.VendorID], v)
} else {
unionOrderMap[v.UserID][v.VendorID] = []*model.UnionOrder{v}
}
} else {
unionOrderVendorMap[v.VendorID] = []*model.UnionOrder{v}
unionOrderMap[v.UserID] = unionOrderVendorMap
}
}
for userID, v := range unionOrderMap {
var (
billID int64
)
userBill, _ := dao.GetUserBill(db, userID, "")
if userBill == nil {
billID = jxutils.GenBillID()
AddUserBillDb(db, billID, userID)
} else {
billID = userBill.BillID
}
for vendorID, vv := range v {
var (
sumPrice, count int
)
for _, unionOrder := range vv {
count++
sumPrice += unionOrder.PromotionAmount
}
unionOrderSettle := &model.UnionOrderSettle{
BillID: billID,
VendorID: vendorID,
Issue: jxutils.GetIssue(),
EarningPrice: sumPrice,
OrderCount: count,
}
dao.WrapAddIDCULEntity(unionOrderSettle, ctx.GetUserName())
settleOrders = append(settleOrders, unionOrderSettle)
//err = dao.CreateEntity(db, unionOrderSettle)
}
}
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, txDB)
panic(r)
}
}()
for _, v := range settleOrders {
//插入结算表
if err = dao.CreateEntityTx(txDB, v); err != nil {
dao.Rollback(db, txDB)
return err
}
//更新用户账户
userBill, _ := dao.GetUserBill(db, "", utils.Int64ToStr(v.BillID))
if err = AddIncomeUpdateAccount(txDB, userBill, model.BillTypeUnionShare, v.EarningPrice, 0); err != nil {
dao.Rollback(db, txDB)
return err
}
}
//修改订单结算标志
for _, v := range unionOrders {
v.IsEarning = model.YES
v.UpdatedAt = time.Now()
if _, err = dao.UpdateEntityTx(txDB, v, "IsEarning", "UpdatedAt"); err != nil {
dao.Rollback(db, txDB)
return err
}
}
dao.Commit(db, txDB)
return err
}
//微信 老会员续费
func WXInvestMember(ctx *jxcontext.Context, memberID int, userID string) (errCode string, err error) {
var db = dao.GetDB()
//获取用户 当前会员信息
userMembers, err := dao.GetUserMember(db, userID, model.MemberTypeNormal)
if err != nil {
return "获取用户会员信息失败", err
}
//当前状态是否是会员 续费/开通
if len(userMembers) > 0 {
userMember := userMembers[0]
if memberID == model.OrderTypeMember {
userMember.EndAt = userMember.EndAt.AddDate(0, 1, 0)
} else {
userMember.EndAt = userMember.EndAt.AddDate(1, 0, 0)
}
if _, err = dao.UpdateEntity(db, userMember, "EndAt"); err != nil {
return "更新会员到期时间失败", err
}
} else {
userMember2 := &model.UserMember{
UserID: userID,
MemberType: model.MemberTypeNormal,
MemberTypeID: memberID,
}
if memberID == model.OrderTypeMember {
userMember2.EndAt = time.Now().AddDate(0, 1, 0)
} else {
userMember2.EndAt = time.Now().AddDate(1, 0, 0)
}
dao.WrapAddIDCULDEntity(userMember2, ctx.GetUserName())
if err = dao.CreateEntity(db, userMember2); err != nil {
return "开通会员失败", err
}
}
return errCode, err
}
//微信 新充值会员
func WXInvestMemberNew(ctx *jxcontext.Context, memberID int, userID string) (errCode string, err error) {
var db = dao.GetDB()
userMember2 := &model.UserMember{
UserID: userID,
MemberType: 1, //model.MemberTypeNormal,
MemberTypeID: 1,
}
if memberID == model.OrderTypeMember {
userMember2.EndAt = time.Now().AddDate(0, 1, 0)
} else {
userMember2.EndAt = time.Now().AddDate(1, 0, 0)
}
userinfo, err := dao.GetUser(db, userMember2.UserID)
if err != nil {
return "", err
}
userMember2.LastOperator = userinfo.UserID2
userMember2.DeletedAt = utils.DefaultTimeValue
if err = dao.CreateEntity(db, userMember2); err != nil {
return "开通会员失败", err
}
return errCode, err
}

View File

@@ -0,0 +1,14 @@
package financial
import (
"testing"
)
func TestOnWXPayFinished(t *testing.T) {
//var (
// ctx *jxcontext.Context
//)
//if _, err := WXInvestMember(ctx, 1, "1303D7B2096011ED9A4C525400C36BDA", true); err != nil {
// t.Logf("微信购买会员失败")
//}
}

View File

@@ -1,122 +1,410 @@
package financial
import (
"context"
"errors"
"crypto/hmac"
"crypto/md5"
"crypto/sha256"
"encoding/json"
"fmt"
"mime/multipart"
"path"
"github.com/astaxie/beego/client/orm"
"sort"
"strings"
"time"
"git.rosy.net.cn/baseapi/platformapi/tonglianpayapi"
"git.rosy.net.cn/baseapi/platformapi/wxpayapi"
"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/auth2/authprovider/weixin"
"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/api"
"github.com/qiniu/api.v7/storage"
)
type tUploadFileInfo struct {
FileHeader *multipart.FileHeader
StoreID int
const (
sigKey = "sign"
sigTypeMd5 = "MD5"
sigTypeSha256 = "HMAC-SHA256"
)
var (
payMap = map[string]*wxpayapi.API{
"weixinapp": api.WxpayAPI,
"weixinmini": api.WxpayAPI2,
}
)
func (p *PayHandler) CreatePay(txDB orm.TxOrmer, subAppID string) (err error) {
switch p.PayType {
case model.PayTypeTL:
param := &tonglianpayapi.CreateUnitorderOrderParam{
Trxamt: p.Order.PayPrice,
NotifyUrl: globals.TLPayNotifyURL,
Reqsn: p.Order.OrderID,
PayType: p.VendorPayType,
}
//暂时做兼容处理
if p.VendorPayType == "JSAPI" {
param.PayType = tonglianpayapi.PayTypeWxXcx
}
if p.VendorPayType == tonglianpayapi.PayTypeWxXcx {
param.SubAppID = subAppID
authInfo, err := p.Ctx.GetV2AuthInfo()
// 微信小程序支付
if err == nil && authInfo.GetAuthType() == weixin.AuthTypeMini && authInfo.GetAuthTypeID() == subAppID {
param.Acct = authInfo.GetAuthID()
}
}
if p.VendorPayType == tonglianpayapi.PayTypeZfbJS || p.VendorPayType == tonglianpayapi.PayTypeZfbApp {
if authInfo, err := p.Ctx.GetV2AuthInfo(); err == nil {
param.Acct = authInfo.GetAuthID()
}
if param.Acct == "" {
return fmt.Errorf("未找到用户的认证ID")
}
}
if p.VendorPayType == tonglianpayapi.PayTypeH5 {
param2 := &tonglianpayapi.CreateH5UnitorderOrderParam{
Trxamt: p.Order.PayPrice,
NotifyUrl: globals.TLPayNotifyURL,
Body: "冲天猴",
Charset: "UTF-8",
}
err = api.TLpayAPI.CreateH5UnitorderOrder(param2)
} else {
result, err := api.TLpayAPI.CreateUnitorderOrder(param)
if err != nil {
return err
}
var result2 tonglianpayapi.PayInfo
json.Unmarshal([]byte(result.PayInfo), &result2)
p.Order.PrepayID = result2.Package[strings.LastIndex(result2.Package, "=")+1 : len(result2.Package)]
p.Order.TransactionID = result.TrxID
if _, err = dao.UpdateEntityTx(txDB, p.Order, "PrepayID", "TransactionID"); err != nil {
return err
}
wxPay := &WxPayParam{
Prepayid: p.Order.PrepayID,
Noncestr: result2.NonceStr,
Timestamp: utils.Int64ToStr(utils.MustInterface2Int64(result2.TimeStamp)),
Package: result2.Package,
Partnerid: "", // 商户Id
Appid: result2.AppID,
Sign: result2.PaySign,
}
p.WxPayParam = wxPay
}
// 暂时不支持微信直接支付
case model.PayTypeWX:
param := &wxpayapi.CreateOrderParam{
OutTradeNo: p.Order.OrderID,
Body: "冲天猴儿App账户充值",
NotifyURL: globals.WxpayNotifyURL,
SpbillCreateIP: p.Ctx.GetRealRemoteIP(),
TradeType: p.VendorPayType,
TotalFee: p.Order.PayPrice,
TimeStart: wxpayapi.Time2PayTime(time.Now()),
// ProfitSharing: wxpayapi.OptYes,
}
authBinds, err := dao.GetUserBindAuthInfo(dao.GetDB(), p.Ctx.GetUserID(), model.AuthBindTypeAuth, []string{p.Order.Way}, "", "", "")
if err != nil {
return err
}
if len(authBinds) == 0 {
return fmt.Errorf("未绑定微信认证方式!")
}
param.OpenID = authBinds[0].AuthID
result, err2 := payMap[p.Order.Way].CreateUnifiedOrder(param)
if err2 == nil {
param2 := make(map[string]interface{})
param2["prepayid"] = result.PrepayID
param2["noncestr"] = utils.GetUUID()
param2["timestamp"] = time.Now().Unix()
param2["package"] = "Sign=WXPay"
param2["partnerid"] = result.MchID
param2["appid"] = result.AppID
sign := signParam(sigTypeMd5, param2)
wxPay := &WxPayParam{
Prepayid: param2["prepayid"].(string),
Noncestr: param2["noncestr"].(string),
Timestamp: utils.Int64ToStr(utils.MustInterface2Int64(param2["timestamp"])),
Package: param2["package"].(string),
Partnerid: param2["partnerid"].(string),
Appid: param2["appid"].(string),
Sign: sign,
}
p.WxPayParam = wxPay
p.Order.PrepayID = result.PrepayID
p.Order.Comment = result.CodeURL
_, err = dao.UpdateEntityTx(txDB, p.Order, "PrepayID", "Comment")
} else {
return err2
}
default:
err = fmt.Errorf("支付方式:%d当前不支持", p.PayType)
}
return err
}
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
func signParam(signType string, params map[string]interface{}) (sig string) {
var valueList []string
for k, v := range params {
if k != sigKey {
if str := fmt.Sprint(v); str != "" {
valueList = append(valueList, fmt.Sprintf("%s=%s", k, str))
}
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)
}
}
}
sort.Sort(sort.StringSlice(valueList))
valueList = append(valueList, fmt.Sprintf("key=%s", globals.WxpayAppKey))
sig = strings.Join(valueList, "&")
var binSig []byte
if signType == sigTypeSha256 {
mac := hmac.New(sha256.New, []byte(globals.WxpayAppKey))
mac.Write([]byte(sig))
binSig = mac.Sum(nil)
} else {
binSig2 := md5.Sum([]byte(sig))
binSig = binSig2[:]
}
sig = fmt.Sprintf("%X", binSig)
// baseapi.SugarLogger.Debug(sig)
return sig
}
func (p *PayHandler) CreateRefund() (err error) {
switch p.PayType {
case model.PayTypeTL: // 收费贵,不适用
case model.PayTypeAliPay: // 支付宝支付
case model.PayTypeWX: // 需要保持账号每天有交易流水,不适用
//企业付款(提现)
if p.VendorPayType == model.VendorPayTypeCompanyPay {
param := &wxpayapi.TransfersParam{
PartnerTradeNo: p.Order.OrderID,
CheckName: wxpayapi.CheckName,
Desc: "冲天猴儿app提现到账",
SpbillCreateIP: p.Ctx.GetRealRemoteIP(),
}
//1元以下免费以上收取对应城市手续费
place, err := dao.GetPlaceByCode(dao.GetDB(), p.Order.CityCode)
if err != nil || place == nil {
return fmt.Errorf("未找到该城市code%v", p.Order.CityCode)
}
if p.Order.PayPrice < 100 {
param.Amount = p.Order.PayPrice
} else {
param.Amount = p.Order.PayPrice * place.DividePercentage / 100 //手续费
}
if authInfo, err := p.Ctx.GetV2AuthInfo(); err == nil {
param.OpenID = authInfo.GetAuthID()
}
globals.SugarLogger.Debugf("CreateRefund wx param: %v", utils.Format4Output(param, false))
result, err2 := payMap[p.Order.Way].Transfers(param)
if err2 == nil {
p.Order.PayFinishedAt = utils.Str2Time(result.PaymentTime)
p.Order.Comment = result.DeviceInfo
p.Order.OriginalData = utils.Format4Output(result, true)
if result.ReturnMsg == "" {
p.Order.Status = model.OrderStatusFinished
} else {
globals.SugarLogger.Warnf("SendFilesToStores file:%s failed with error:%v", fileHeader.Filename, err)
p.Order.Status = model.OrderStatusCanceled
}
dao.UpdateEntity(dao.GetDB(), p.Order)
if result.ReturnMsg == "" {
err = OnCashFinished(p.Order)
}
} else {
globals.SugarLogger.Warnf("SendFilesToStores open file:%s failed with error:%v", fileHeader.Filename, err)
return err2
}
return retVal, err
}, fileList)
tasksch.HandleTask(task, nil, true).Run()
hint = task.ID
if !isAsync {
_, err = task.GetResult(0)
err = OnCashFinished(p.Order)
} else if p.VendorPayType == model.VendorPayTypeTransferAccount {
p.Order.PayFinishedAt = time.Now()
p.Order.Comment = "手动转账"
p.Order.Status = model.OrderStatusFinished
if _, err := dao.UpdateEntity(dao.GetDB(), p.Order); err == nil {
err = OnCashFinished(p.Order)
}
}
}
return task.ID, err
return 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
func OnTLPayCallback(call *tonglianpayapi.CallBackResult) (err error) {
globals.SugarLogger.Debugf("OnTLPayCallback msg:%s", utils.Format4Output(call, true))
switch call.TrxCode {
case tonglianpayapi.MsgTypePay:
err = onTLpayFinished(call)
case tonglianpayapi.MsgTypeRefund:
err = onTLpayRefund(call)
}
return bills, err
return err
}
func onTLpayFinished(call *tonglianpayapi.CallBackResult) (err error) {
order := &model.Order{
OrderID: call.CusorderID,
TransactionID: call.TrxID,
}
db := dao.GetDB()
if err = dao.GetEntity(db, order, "OrderID"); err == nil {
if order.Status != model.OrderStatusWait4Pay {
globals.SugarLogger.Debugf("already pay msg:%s, err:%v", utils.Format4Output(call, true), err)
return err
}
loc, _ := time.LoadLocation("Local")
t1, _ := time.ParseInLocation("20060102150405", call.PayTime, loc)
order.PayFinishedAt = t1
order.OriginalData = utils.Format4Output(call, true)
payStatus := model.PayStatusNo
//order.PayMethod = 2 // 通联微信支付
if call.TrxStatus == tonglianpayapi.TrxStatusSuccess {
order.Status = model.OrderStatusFinished
payStatus = model.OrderStatusSuccessPay
} else {
order.Status = model.OrderStatusCanceled
payStatus = model.OrderStatusFailPay
}
//充值会员 增加微信支付处理业务
if (order.OrderType == model.OrderTypeMember || order.OrderType == model.OrderTypeMemberYear) && call.TrxStatus == tonglianpayapi.TrxStatusSuccess {
return OnWXPayFinished(order)
}
// 充值话费
if order.OrderType == model.OrderTypeMobile && call.TrxStatus == tonglianpayapi.TrxStatusSuccess {
return OnWxPayTelephone(order)
}
// 发快递
if order.OrderType == model.OrderTypeDelivery && call.TrxStatus == tonglianpayapi.TrxStatusSuccess {
return OnWxPaySendPage(db, order, call, payStatus)
}
//需要充值到余额方式 购买的
if order.OrderType == model.OrderTypeBalance && call.TrxStatus == tonglianpayapi.TrxStatusSuccess {
if err := dao.UpdateUserBill(order.UserID, order.PayPrice); err != nil {
return err
}
order.Status = 110
if _, err := dao.UpdateEntity(db, order, "Status"); err != nil {
return err
}
}
} else {
globals.SugarLogger.Debugf("onTLpayFinished msg:%s, err:%v", utils.Format4Output(call, true), err)
}
return err
}
func onTLpayRefund(call *tonglianpayapi.CallBackResult) (err error) {
orderPayRefund := &model.OrderPayRefund{
RefundID: call.CusorderID,
}
db := dao.GetDB()
if err = dao.GetEntity(db, orderPayRefund, "RefundID"); err == nil {
if call.TrxStatus == tonglianpayapi.TrxStatusSuccess {
orderPayRefund.Status = model.RefundStatusYes
} else {
orderPayRefund.Status = model.RefundStatusFailed
}
orderPayRefund.OriginalData = utils.Format4Output(call, true)
dao.UpdateEntity(db, orderPayRefund)
} else if dao.IsNoRowsError(err) {
globals.SugarLogger.Warnf("收到异常的退款事件, call:%s", utils.Format4Output(call, true))
}
orderPay := &model.Order{
OrderID: orderPayRefund.VendorOrderID,
}
if err = dao.GetEntity(db, orderPay, "VendorOrderID"); err == nil {
orderPay.Status = model.OrderStatusCancel
}
if orderPay.OrderType == model.PayType4Express {
tx, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, tx)
panic(r)
}
}()
if _, err = dao.UpdateEntityTx(tx, orderPay); err != nil {
tx.Rollback()
return err
}
if _, err = dao.UpdateEntityTx(tx, &model.UserVendorOrder{LocalWayBill: call.CusorderID, OrderStatus: model.OrderStatusCancel}, "OrderStatus"); err != nil {
tx.Rollback()
return err
}
tx.Commit()
return err
}
return err
}
func OnWxPayCallback(msg *wxpayapi.CallbackMsg) (err error) {
globals.SugarLogger.Debugf("OnWxPayCallback msg:%s", utils.Format4Output(msg, true))
switch msg.MsgType {
case wxpayapi.MsgTypePay:
err = onWxpayFinished(msg.Data.(*wxpayapi.PayResultMsg))
case wxpayapi.MsgTypeRefund:
// err = onWxpayRefund(msg.Data.(*wxpayapi.RefundResultMsg))
}
return err
}
func onWxpayFinished(msg *wxpayapi.PayResultMsg) (err error) {
order := &model.Order{
OrderID: msg.OutTradeNo,
}
db := dao.GetDB()
if err = dao.GetEntity(db, order, "OrderID"); err == nil {
order.PayFinishedAt = wxpayapi.PayTime2Time(msg.TimeEnd)
order.TransactionID = msg.TransactionID
order.OriginalData = utils.Format4Output(msg, true)
if msg.ResultCode == wxpayapi.ResponseCodeSuccess {
order.Status = model.OrderStatusFinished
} else {
order.Status = model.OrderStatusCanceled
}
dao.UpdateEntity(db, order)
if msg.ResultCode == wxpayapi.ResponseCodeSuccess {
err = OnPayFinished(order)
}
} else {
globals.SugarLogger.Debugf("onWxpayFinished msg:%s, err:%v", utils.Format4Output(msg, true), err)
}
return err
}
// func onWxpayRefund(msg *wxpayapi.RefundResultMsg) (err error) {
// orderPayRefund := &model.OrderPayRefund{
// RefundID: msg.ReqInfoObj.OutRefundNo,
// }
// db := dao.GetDB()
// if err = dao.GetEntity(db, orderPayRefund, "RefundID"); err == nil {
// if msg.ResultCode == wxpayapi.ResponseCodeSuccess {
// orderPayRefund.Status = model.RefundStatusYes
// } else {
// orderPayRefund.Status = model.RefundStatusFailed
// }
// orderPayRefund.OriginalData = utils.Format4Output(msg, true)
// dao.UpdateEntity(db, orderPayRefund)
// } else if dao.IsNoRowsError(err) {
// globals.SugarLogger.Warnf("收到异常的退款事件, msg:%s", utils.Format4Output(msg, true))
// }
// orderPay := &model.OrderPay{
// VendorOrderID: orderPayRefund.VendorOrderID,
// VendorID: jxutils.GetPossibleVendorIDFromVendorOrderID(orderPayRefund.VendorOrderID),
// PayType: model.PayTypeWX,
// Status: model.PayStatusYes,
// }
// orderPay.DeletedAt = utils.DefaultTimeValue
// if err = dao.GetEntity(db, orderPay, "VendorOrderID", "VendorID", "PayType", "Status", "DeletedAt"); err == nil {
// orderPay.Status = model.PayStatusRefund
// dao.UpdateEntity(db, orderPay)
// }
// return err
// }

View File

@@ -0,0 +1,224 @@
package financial
import (
"fmt"
"git.rosy.net.cn/baseapi/platformapi/recharge_phone_bill"
"git.rosy.net.cn/baseapi/platformapi/tonglianpayapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/business/q_bida"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/globals/api"
)
type PayHandler struct {
PayType int `json:"-"` //支付方式
Ctx *jxcontext.Context
Order *model.Order
VendorPayType string
WxPayParam *WxPayParam `json:"wxPayParam"`
}
type WxPayParam struct {
Prepayid string `json:"prepayid"`
Noncestr string `json:"noncestr"`
Timestamp string `json:"timestamp"`
Package string `json:"package"`
Partnerid string `json:"partnerid"`
Appid string `json:"appid"`
Sign string `json:"sign"`
}
type PayHandlerInterface interface {
CreatePay() (err error)
CreateRefund() (err error)
}
func OnPayFinished(order *model.Order) (err error) {
var db = dao.GetDB()
globals.SugarLogger.Debugf("OnPayFinished begin modify account order: %v", utils.Format4Output(order, false))
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, txDB)
panic(r)
}
}()
//如果用户没有对应账单信息就给他生成一条
userBill, err := dao.GetUserBill(db, order.UserID, "")
if userBill == nil {
globals.SugarLogger.Debugf("OnPayFinished 未找到该用户的账单 order: %v", utils.Format4Output(order, false))
return fmt.Errorf("未找到该用户的账单!%v", order.UserID)
}
//根据订单类型来操作账户
switch order.Type {
case model.OrderTypePay:
//如果是账户充值(发布任务等)
//账户收入
if err = AddIncomeUpdateAccount(txDB, userBill, model.BillTypeInvest, order.PayPrice, 0); err != nil {
dao.Rollback(db, txDB)
}
default:
globals.SugarLogger.Debugf("OnPayFinished 暂不支持此订单类型 order: %v", utils.Format4Output(order, false))
return fmt.Errorf("暂不支持此订单类型!")
}
dao.Commit(db, txDB)
globals.SugarLogger.Debugf("OnPayFinished end modify account ...")
return err
}
func OnCashFinished(order *model.Order) (err error) {
var (
db = dao.GetDB()
)
globals.SugarLogger.Debugf("OnCashFinished begin modify account order: %v", utils.Format4Output(order, false))
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, txDB)
panic(r)
}
}()
//如果用户没有对应账单信息就给他生成一条
userBill, err := dao.GetUserBill(db, order.UserID, "")
if userBill == nil {
globals.SugarLogger.Debugf("OnCashFinished 未找到该用户的账单 order: %v", utils.Format4Output(order, false))
return fmt.Errorf("未找到该用户的账单!%v", order.UserID)
}
//根据订单类型来操作账户
switch order.Type {
case model.OrderTypeCash:
//如果是账户提现
//账户支出
if err = AddExpendUpdateAccount(txDB, userBill, model.BillTypeCash, order.PayPrice, 0); err != nil {
dao.Rollback(db, txDB)
}
default:
globals.SugarLogger.Debugf("OnPayFinished 暂不支持此订单类型 order: %v", utils.Format4Output(order, false))
return fmt.Errorf("暂不支持此订单类型!")
}
dao.Commit(db, txDB)
globals.SugarLogger.Debugf("OnCashFinished end modify account ...")
return err
}
//微信支付充值会员
func OnWXPayFinished(order *model.Order) (err error) {
var (
db = dao.GetDB()
ctx *jxcontext.Context
txDB, _ = dao.Begin(db)
)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, txDB)
panic(r)
}
}()
//判断是新会员充值还是老会员续费
userMembers, err := dao.GetUserMember(db, order.UserID, model.MemberTypeNormal)
if err != nil {
return err
}
//根据订单类型来操作账户
if order.Type == model.OrderTypePay {
//为新会员生成会员信息并充值
if len(userMembers) > 0 {
if _, err := WXInvestMember(ctx, order.OrderType, order.UserID); err != nil {
return err
}
} else {
if _, err := WXInvestMemberNew(ctx, order.OrderType, order.UserID); err != nil {
return err
}
}
order.Status = model.OrderStatusFinished
//更新order状态
if _, err := dao.UpdateEntityTx(txDB, &order, "Status"); err != nil {
dao.Rollback(db, txDB)
return err
}
} else {
return fmt.Errorf("暂不支持此订单类型!")
}
return err
}
// OnWxPayTelephone 微信充值话费
func OnWxPayTelephone(order *model.Order) error {
orderNumber, err := api.TelephoneAPI.RechargePhoneBill(&recharge_phone_bill.RechargePhoneBillBase{
FlowCode: order.FlowCode,
Mobile: order.Mobile,
OrderNumber: order.OrderID,
CallbackURL: "http://callback.rsm.jxc4.com/recharge/msg",
ChargeType: "1",
})
if err != nil {
order.Comment = err.Error()
order.RechargeStatus = -1 // 充值失败
}
order.RechargeStatus = 1 // 充值中
order.Comment = orderNumber
//更新order状态
order.Status = model.OrderStatusFinished
if _, err := dao.UpdateEntity(dao.GetDB(), &order, "Status", "RechargeStatus", "Comment"); err != nil {
return err
}
return nil
}
// OnWxPaySendPage 发快递支付方
func OnWxPaySendPage(db *dao.DaoDB, order *model.Order, call *tonglianpayapi.CallBackResult, payStatus int) (err error) {
txdb, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
panic(r)
}
}()
order.TransactionID = call.TrxID
order.Status = 110 //支付成功状态
if _, err := dao.UpdateEntityTx(txdb, order, "TransactionID", "Status"); err != nil {
dao.Rollback(db, txdb)
return err
}
userOrder := model.UserVendorOrder{LocalWayBill: order.OrderID}
if err := dao.GetEntity(db, &userOrder, "LocalWayBill"); err != nil {
dao.Rollback(db, txdb)
return err
}
userOrder.OrderStatus = payStatus
if _, err := dao.UpdateEntityTx(txdb, &userOrder, "OrderStatus"); err != nil {
dao.Rollback(db, txdb)
return err
}
//1-余额,2-微信,5-混合
if order.PayMethod == model.OrderPayMethodMix {
userBill, err := dao.GetUserBill(db, order.UserID, "")
if err != nil {
return err
}
//创建混合支付账单
totalPrice := order.PayPrice + userBill.AccountBalance
if err := AddMixPay(txdb, order.OrderID, userBill.AccountBalance, totalPrice, 1); err != nil {
dao.Rollback(db, txdb)
return err
}
//余额清空
if err := dao.UpdateUserBill(order.UserID, 0); err != nil {
dao.Rollback(db, txdb)
return err
}
}
dao.Commit(db, txdb)
if call.TrxStatus == tonglianpayapi.TrxStatusSuccess {
switch order.OrderType {
case model.PayType4Express:
err = q_bida.CreateOrder2QBiDa(&userOrder, order.OrderID)
}
}
return err
}

View File

@@ -2,13 +2,12 @@ package initdata
import (
"fmt"
"git.rosy.net.cn/baseapi/platformapi/tencent_map"
"git.rosy.net.cn/baseapi/platformapi/autonavi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/globals/api"
)
@@ -17,9 +16,9 @@ func TruncateTable(db *dao.DaoDB, tableName string) (err error) {
return err
}
func insertPlace(ctx *jxcontext.Context, db *dao.DaoDB, parent *tencent_map.District, placeList []*tencent_map.District) (err error) {
func insertPlace(ctx *jxcontext.Context, db *dao.DaoDB, parent *autonavi.District, placeList []*autonavi.District) (err error) {
for _, v := range placeList {
if v.Level <= tencent_map.DistrictLevelDistrict {
if v.Level <= autonavi.DistrictLevelDistrict {
place := &model.Place{
Code: int(utils.Str2Int64(v.Adcode)),
Name: v.Name,
@@ -43,8 +42,7 @@ func insertPlace(ctx *jxcontext.Context, db *dao.DaoDB, parent *tencent_map.Dist
}
func InitPlace(ctx *jxcontext.Context) (err error) {
// 这个地方是更新全国的place表,因为两个不兼容且上传时间不会发送改变,暂时不做返回
placeList, err2 := api.TencentMapAPI.GetDistricts(tencent_map.DistrictLevelDistrict, "", 0)
placeList, err2 := api.AutonaviAPI.GetDistricts(autonavi.DistrictLevelDistrict, "")
if err = err2; err != nil {
return err
}
@@ -69,124 +67,10 @@ func InitPlace(ctx *jxcontext.Context) (err error) {
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,

View File

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

View File

@@ -1,825 +1,76 @@
package misc
import (
"fmt"
"sync"
"git.rosy.net.cn/jx-callback/business/jxstore/partner/pdd"
"git.rosy.net.cn/jx-callback/business/model/dao"
bidaServer "git.rosy.net.cn/jx-callback/business/q_bida"
"time"
"git.rosy.net.cn/jx-callback/business/bidding"
"git.rosy.net.cn/jx-callback/business/partner/delivery"
"git.rosy.net.cn/jx-callback/business/jxstore/event"
"git.rosy.net.cn/jx-callback/business/partner/purchase/jdshop"
"git.rosy.net.cn/baseapi/platformapi/jdapi"
"git.rosy.net.cn/jx-callback/business/partner/purchase/jx/localjx"
"git.rosy.net.cn/jx-callback/globals/api"
"git.rosy.net.cn/jx-callback/business/jxstore/report"
"git.rosy.net.cn/jx-callback/business/jxstore/cms"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/baseapi/utils/errlist"
"git.rosy.net.cn/jx-callback/business/jxcallback/orderman"
"git.rosy.net.cn/jx-callback/business/jxcallback/scheduler/defsch"
"git.rosy.net.cn/jx-callback/business/jxstore/act"
"git.rosy.net.cn/jx-callback/business/jxstore/cms"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/jxutils/netprinter"
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/business/netspider"
"git.rosy.net.cn/jx-callback/business/partner"
"git.rosy.net.cn/jx-callback/globals"
beego "github.com/astaxie/beego/server/web"
)
const (
SpecialTaskID = "Running"
TaskNameSyncStoreSku = "SyncStoreSku"
)
var (
dailyHeartbeat = []string{
"09:00:00",
}
dailyWorkTimeList = []string{
"21:30:00",
"00:18:35",
}
dailyWorkTimeList2 = []string{
"02:30:00",
stationTimeList = []string{
"11:35:00",
}
priceReferTimeList = []string{
"03:00:00",
}
checkCookieList = []string{
"08:00:00",
"12:00:00",
"18:00:00",
}
createStorePriceTimeList = []string{
startDeleteTime = []string{
"04:00:00",
}
refreshPageActTimeList = []string{
"7:00:00",
//"8:00:00",
"9:00:00",
//"10:00:00",
"11:00:00",
//"12:00:00",
"13:00:00",
//"14:00:00",
"15:00:00",
//"16:00:00",
"17:00:00",
//"18:00:00",
"19:00:00",
"22:00:00",
}
// 七牛云流量检查
ChangeStoreSkuSaleStatusList = []string{
//"7:00:00",
//"8:00:00",
//"9:00:00",
/* //"10:00:00",
//"11:00:00",
//"12:00:00",
//"13:00:00",
//"14:00:00",
//"15:00:00",
//"16:00:00",
//"17:00:00",
//"18:00:00",
//"19:00:00",
//"20:00:00",*/
}
openRemoteStoreTimeList = []string{
"04:30:00",
"23:30:00",
}
updateActStatusTimeList = []string{
"00:01:00",
}
sendSecKillWarnList = []string{
"9:00:00",
}
autoPayForPopluarManList = []string{
"10:30:00",
}
autoSaleStoreSkuTimeList = []string{
cms.AutoSaleAtStr,
}
backUpStoreSkuBindList = []string{
"23:30:00",
}
exSyncList = []string{
"11:30:00",
}
importantTaskMap = &sync.Map{}
cancelPayTimeOutOrderList = localjx.GetHalfHoursList()
discountActJxList = localjx.GetDiscountActHoursList()
//ebaiStorePageCookieExdTOKEN string
//ebaiStorePageCookieWMUSS2 string
//ebaiStorePageCookieWMSTOKEN2 string
ebaiStorePageCookie string
//ebaiStorePageCookieWMSTOKEN string
mtwmCookieStr string
mtpsStoreToken string
jd2StorePageCookie string
JdStorePageCookie string
yinbaoCookie string
feiePageCookie string
jdStorePageEarning string
//jdsCookie string
// jdsCookie2 string
)
func GetImportantTaskID(taskName string) string {
if value, ok := importantTaskMap.Load(taskName); ok {
return value.(string)
}
return ""
}
func SaveImportantTaskID(taskName, taskID string) {
importantTaskMap.Store(taskName, taskID)
}
func IsImportantTaskRunning(taskName string) bool {
taskID := GetImportantTaskID(taskName)
if taskID == "" {
return false
} else if taskID == SpecialTaskID {
return true
}
return tasksch.IsTaskRunning(taskID)
}
func Init() {
if globals.IsProductEnv() {
//ScheduleTimerFunc("doDailyWork2", doDailyWork2, dailyWorkTimeList2)
if globals.IsMainProductEnv() {
//京东的订单信息解密密钥获取
//拼多多订单轮询
ScheduleTimerFuncByInterval(func() {
jdshop.InitKey()
}, 5*time.Second, 8*time.Hour)
ScheduleTimerFuncByInterval(func() {
RefreshRealMobile(jxcontext.AdminCtx, model.VendorIDEBAI, time.Now().Add(-24*time.Hour), utils.DefaultTimeValue, false, true)
report.RefreshStoreManageState(jxcontext.AdminCtx, nil, []int{model.VendorIDJD})
}, 5*time.Second, 1*time.Hour)
// 定时任务通知:签约门店过期通知
ScheduleTimerFunc("GetExpireShopNoticeUser", func() {
bidding.GetExpireShopNoticeUser()
}, []string{
"10:00:00",
})
//每天晚上23:00更新抖店 审核状态
ScheduleTimerFunc("UpdateStorePoiStatus", func() {
cms.UpdateStorePoiStatus(jxcontext.AdminCtx)
}, []string{
"22:00:00",
})
//每天晚上23:00获取门店 电子围栏、仓库、限售模板、运费模板ID同步进数据库
ScheduleTimerFunc("UpdateStoreRelInformation", func() {
cms.UpdateStoreRelInformation(jxcontext.AdminCtx)
}, []string{
"22:00:00",
})
// 更新抖店订单的结算信息
ScheduleTimerFunc("UpdateTiktokShopTotalMoney", func() {
orderman.UpdateTiktokShopTotalMoney(0, utils.DefaultTimeValue, utils.DefaultTimeValue)
}, []string{
"07:00:00",
"09:00:00",
"15:00:00",
"19:00:00",
"22:00:00",
"02:00:00",
"05:00:00",
})
ScheduleTimerFunc("UpdateMtActivityInfo", func() {
bidding.GetMTInfo()
}, []string{
"13:00:00",
})
/// 更新淘鲜达结算信息
//ScheduleTimerFunc("UpdateTaoTotalMoney", func() {
// orderman.UpdateTaoSettleInfo()
//}, []string{
// "06:30:00",
// "01:45:00",
//})
// 每分钟轮询一次,推送骑手信息(假的订单)
ScheduleTimerFuncByInterval(func() {
delivery.UpdateFakeWayBillToTiktok()
}, 10*time.Second, 20*time.Second)
// 每五分钟轮询一次推送骑手信息坐标给美团/抖音(真订单,真自送)
ScheduleTimerFuncByInterval(func() {
delivery.GetOrderRiderInfoToPlatform("", 0)
}, 10*time.Second, 20*time.Second)
// (自动发单拣货,设置骑手) 刷单用
//ScheduleTimerFuncByInterval(func() {
// auto_delivery.Init() // 初始化骑手列表
// auto_delivery.AutoSettingFakeDelivery()
//}, 10*time.Second, 5*time.Minute)
// 定时任务更新负责人信息
ScheduleTimerFunc("RefreshStoreOperator", func() {
cms.UpdateStoreOperatorConfig()
}, []string{
"04:00:00",
})
// 每天更新美团-门店结算方式[结算给企业/结算给个人](取消了平台运单的骑手计费)
ScheduleTimerFunc("LoadingStoreOrderSettleAmount", func() {
delivery.LoadingStoreOrderSettleAmount(0, 0, nil)
}, []string{
"12:50:00",
})
ScheduleTimerFunc("UpdateStoreName ", func() {
cms.UpdateStoreName()
}, []string{
"13:35:00",
})
// 定时任务更新昨天的都要商品和本地商品id的映射关系
//ScheduleTimerFunc("RefreshStoreOperator", func() {
// t := time.Now()
// cms.SyncTiktokMainIdToLocal(jxcontext.AdminCtx, &tiktok_store.MainSku{
// AppOrgCode: "",
// CheckStatus: 3,
// StartTime: time.Date(t.Year(), t.Month(), t.Day()-1, 0, 0, 1, 0, time.Local).Unix(),
// EndTime: time.Date(t.Year(), t.Month(), t.Day()-1, 23, 59, 59, 0, time.Local).Unix(),
// Page: 1,
// PageSize: 100,
// })
//}, []string{
// "04:30:00",
//})
ScheduleTimerFuncByInterval(func() {
defsch.FixedScheduler.ConfirmSelfTakeOrders(jxcontext.AdminCtx, []int{model.VendorIDJD}, time.Now().Add(-48*time.Hour), time.Now().Add(-30*time.Minute), true, true)
}, 5*time.Second, 10*time.Minute)
ScheduleTimerFuncByInterval(func() {
report.RefreshStoreManageState(jxcontext.AdminCtx, nil, []int{model.VendorIDMTWM, model.VendorIDEBAI})
}, 5*time.Second, 40*time.Minute)
ScheduleTimerFuncByInterval(func() {
orderman.SaveJdsOrders(jxcontext.AdminCtx, time.Now().Add(-30*time.Minute), time.Now())
orderman.UpdateJdsOrdersStatus(jxcontext.AdminCtx, time.Now().AddDate(0, 0, -1), time.Now())
pdd.GetUnionOrders()
}, 5*time.Second, 5*time.Minute)
// 抖音更新门店商品 ,接口收费暂不使用
//if beego.BConfig.RunMode != "jxgy" {
// ScheduleTimerFunc("RefreshSyncSkuList", func() {
// syncStoreSkuTiktok()
// }, []string{"13:00:00"})
//}
ScheduleTimerFunc("doDailyWork", doDailyWork, dailyWorkTimeList)
//if beego.BConfig.RunMode != model.ServerTypeFruits && beego.BConfig.RunMode != model.ServerTypePet {
// ScheduleTimerFunc("RefreshSyncSkuListTao", func() {
// syncStoreSkuTao()
// }, []string{
// "03:50:00",
// })
//}
ScheduleTimerFunc("InitStation", func() {
//同步油站信息
cms.InitStation(jxcontext.AdminCtx)
}, stationTimeList)
// 刷新抖音门店token
if beego.BConfig.RunMode != model.ServerTypeFruits && beego.BConfig.RunMode != model.ServerTypePet {
ScheduleTimerFuncByInterval(func() {
cms.RefreshTiktokShopToken(jxcontext.AdminCtx)
}, 60*time.Second, 30*time.Minute)
}
// 定时删除打印信息
ScheduleTimerFunc("DeleteTimeOutPrintMsg", func() {
dao.DeletePrintMsg()
}, stationTimeList)
// 定时任务刷新当前订单的物流信息
ScheduleTimerFunc("RefreshMaterialLogistics", func() {
bidding.LoadingLogistics(nil)
}, []string{
"02:45:00",
})
//刷新京东物竞天择订单结算价
ScheduleTimerFunc("RefreshJdShopOrdersEarningPrice", func() {
orderman.RefreshJdShopOrdersEarningPrice(jxcontext.AdminCtx, utils.Time2Str(time.Now().AddDate(0, 0, -2)), utils.Time2Str(time.Now().AddDate(0, 0, -2)))
orderman.RefreshJdShopOrdersEarningPrice(jxcontext.AdminCtx, utils.Time2Str(time.Now().AddDate(0, 0, -1)), utils.Time2Str(time.Now().AddDate(0, 0, -1)))
}, []string{
"05:00:00",
})
//刷新京东售后单结算价
ScheduleTimerFunc("RefreshJdAfsOrderTotalShopMoney", func() {
orderman.RefreshJdAfsOrderTotalShopMoney()
}, []string{
"05:30:00",
})
ScheduleTimerFunc("auto enable remote store", func() {
cms.EnableHaveRestStores(jxcontext.AdminCtx, false, true)
// cms.OpenRemoteStoreByJxStatus(jxcontext.AdminCtx, nil, nil, false, false, true)
}, openRemoteStoreTimeList)
// ScheduleTimerFunc("SaveAndSendAlarmVendorSnapshot", func() {
// cms.SaveAndSendAlarmVendorSnapshot(jxcontext.AdminCtx, nil, nil, false)
// }, cms.WatchVendorStoreTimeList)
ScheduleTimerFunc("RefreshPageActs", func() {
act.RefreshPageActs(jxcontext.AdminCtx, []int{model.VendorIDEBAI}, time.Now().Add(-30*24*time.Hour), false)
}, refreshPageActTimeList)
ScheduleTimerFunc("UpdateActStatusByTime", func() {
dao.UpdateActStatusByTime(dao.GetDB(), time.Now())
}, updateActStatusTimeList)
ScheduleScoreStore()
// ScheduleCheckStoreAlert()
//ScheduleTimerFunc("ChangeStoreSkuSaleStatus", func() {
// cms.CurVendorSync.ChangeStoreSkuSaleStatus(jxcontext.AdminCtx, 0, true, true)
//}, ChangeStoreSkuSaleStatusList)
ScheduleTimerFunc("BeginSavePriceRefer", func() {
report.BeginSavePriceRefer(jxcontext.AdminCtx, nil, nil, true, true)
}, priceReferTimeList)
ScheduleTimerFunc("CreateStorePriceScore", func() {
cms.CreateStorePriceScore(jxcontext.AdminCtx)
}, createStorePriceTimeList)
//ScheduleTimerFunc("AutoFocusStoreSkusForTopSkus", func() {
// cms.AutoFocusStoreSkusForTopSkus(jxcontext.AdminCtx, true, true)
//}, createStorePriceTimeList)
//ScheduleTimerFunc("GetCheckVendorCookie", func() {
// event.GetCheckVendorCookie(jxcontext.AdminCtx, []int{model.VendorIDEBAI, model.VendorIDJD, model.VendorIDMTWM, model.VendorIDMTPS, model.VendorIDJDShop}, true)
//}, checkCookieList)
//ScheduleTimerFunc("SendSeckillSkusCountMsg", func() {
// cms.SendSeckillSkusCountMsg(jxcontext.AdminCtx, []int{model.VendorIDEBAI, model.VendorIDJD, model.VendorIDMTWM}, false, true)
//}, sendSecKillWarnList)
// ScheduleTimerFunc("每日报警心跳", func() {
// globals.SugarLogger.Warnf("每日报警心跳,这不是报警。启动时间:%s", cms.GetServiceInfo(jxcontext.AdminCtx)["startupTime"])
// }, dailyHeartbeat)
ScheduleTimerFunc("AutoPayForPopluarMan", func() {
localjx.AutoPayForPopluarMan(jxcontext.AdminCtx)
}, autoPayForPopluarManList)
ScheduleTimerFunc("CancelPayTimeOutOrder", func() {
localjx.CancelPayTimeOutOrder(jxcontext.AdminCtx)
}, cancelPayTimeOutOrderList)
ScheduleTimerFunc("BackUpStoreSkuBind", func() {
cms.BackUpStoreSkuBind(jxcontext.AdminCtx, true, true)
}, backUpStoreSkuBindList)
// ScheduleTimerFunc("SendNoCatSkusToOperater", func() {
// cms.SendNoCatSkusToOperater(jxcontext.AdminCtx)
// }, autoPayForPopluarManList)
ScheduleTimerFunc("CleanStoreIsBoughtMatter", func() {
cms.CleanStoreIsBoughtMatter(jxcontext.AdminCtx)
}, priceReferTimeList)
ScheduleTimerFunc("CleanUserOrderSMSMark", func() {
cms.CleanUserOrderSMSMark(jxcontext.AdminCtx)
}, priceReferTimeList)
ScheduleTimerFunc("CreateOrderByPriceDefend", func() {
localjx.CreateOrderByPriceDefend(jxcontext.AdminCtx)
}, []string{
"22:00:00",
})
//ScheduleTimerFunc("ChangeJxPriceByDiscountAct", func() {
// act.ChangeJxPriceByDiscountAct(jxcontext.AdminCtx)
//}, discountActJxList)
ScheduleTimerFunc("RefreshUserMemberStatus", func() {
cms.RefreshUserMemberStatus(jxcontext.AdminCtx)
}, updateActStatusTimeList)
//刷优惠券状态
ScheduleTimerFunc("RefreshCouponsStatus", func() {
localjx.RefreshCouponsStatus(jxcontext.AdminCtx)
}, updateActStatusTimeList)
//刷新美团商超门店Token
ScheduleTimerFunc("RefreshMTWMToken", func() {
cms.RefreshMTWMToken(jxcontext.AdminCtx)
}, updateActStatusTimeList)
//获取最新平台流量活动
ScheduleTimerFunc("GetNewVendorPopActs", func() {
act.GetNewVendorPopActs(jxcontext.AdminCtx)
}, dailyHeartbeat)
//企业微信群人数通告(暂时取消)
//ScheduleTimerFunc("SendQywxPeopleCount", func() {
// cms.SendQywxPeopleCount(jxcontext.AdminCtx)
//}, dailyHeartbeat)
ScheduleTimerFunc("doDailyWork1", func() {
//同步商品额外前缀和水印图(打标记)
cms.SyncSkuExperfixAndWatermark(jxcontext.AdminCtx)
}, dailyWorkTimeList)
/*ScheduleTimerFunc("BuildFakeMatterOrder", func() {
orderman.BuildFakeMatterOrder()
}, []string{
"09:00:00",
"15:00:00",
"23:00:00",
})*/
ScheduleTimerFunc("doDailyWork2", func() {
//刷新京东会员
//report.RefreshJDMembers(jxcontext.AdminCtx)
cms.SetSingleStoreSkuSyncModifyStatus(dao.GetDB(), []int{1, 3})
}, dailyWorkTimeList)
ScheduleTimerFunc("doDailyWork2-1", func() {
// 刷新商品,换个时间节点,房子请求超时
cms.CurVendorSync.SyncStoresSkus2(jxcontext.AdminCtx, nil, 0, dao.GetDB(), []int{1, 3}, nil, false, nil, nil, model.SyncFlagSaleMask, true, true)
// 刷新门店平台商品
//syncStoreSku()
}, []string{"02:00:00"})
ScheduleTimerFunc("doDailyWork3", func() {
dao.SetStoresMapSyncStatus(dao.GetDB(), nil, nil, model.SyncFlagStoreStatus)
cms.CurVendorSync.SyncStore2Time(jxcontext.AdminCtx, dao.GetDB(), []int{model.VendorIDMTWM, model.VendorIDJD, model.VendorIDEBAI, model.VendorIDDD}, nil, true, true)
InitEx()
cms.SyncStoresCourierInfo(jxcontext.AdminCtx, nil, false, true)
netprinter.RebindAllPrinters(jxcontext.AdminCtx, false, true)
}, dailyWorkTimeList)
//if beego.BConfig.RunMode != model.ServerTypePet {
ScheduleTimerFunc("doDailyWork4", func() {
curDate := utils.Time2Date(time.Now())
orderman.FixedOrderManager.AmendMissingOrders(jxcontext.AdminCtx, []int{model.VendorIDJD, model.VendorIDMTWM, model.VendorIDEBAI, model.VendorIDDD}, 0, curDate.Add(-72*time.Hour), curDate, true, true)
//只传toDate默认刷新toDate到5天以前的订单
orderman.RefreshOrdersWithoutJxStoreID(jxcontext.AdminCtx, "", "", true, true)
//禁用没有绑定的门店
cms.DisabledStoreWithoutVendor(jxcontext.AdminCtx, true, true)
}, dailyWorkTimeList)
//}
if beego.BConfig.RunMode == model.ServerTypeFruits /*|| beego.BConfig.RunMode == model.ServerTypePet*/ {
ScheduleTimerFuncByInterval(func() {
fromData := utils.Time2Date(time.Now())
toData := time.Now()
orderman.FixedOrderManager.AmendMissingOrders(jxcontext.AdminCtx, []int{model.VendorIDJD, model.VendorIDMTWM, model.VendorIDEBAI, model.VendorIDDD}, 0, fromData, toData, true, true)
}, 5*time.Second, 5*time.Minute)
}
ScheduleTimerFunc("doDailyWork5", func() {
//刷新物料订单状态
localjx.RefreshAllMatterOrderStatus(jxcontext.AdminCtx)
//同步美团配送与否状态及美团门店是否存在
//cms.SetMTPSStatus(jxcontext.AdminCtx, 0, 0)
cms.SetMTPSStatus2(0)
//售后单如果超过12小时没有审核就自动通过
//RefreshAfsOrderStatusAccess(jxcontext.AdminCtx)
//刷新门店分组管理
cms.RefreshStoreBind(jxcontext.AdminCtx)
//更新所有门店的上下线状态
cms.RefreshStoreIsOnline(jxcontext.AdminCtx)
}, dailyWorkTimeList)
ScheduleTimerFunc("RrefreshMtwmVendorAct", func() {
//刷新美团平台活动
act.RrefreshMtwmVendorAct(jxcontext.AdminCtx)
//刷新饿百平台活动
act.RrefreshEbaiVendorAct(jxcontext.AdminCtx)
}, dailyWorkTimeList2)
// 轮询每天更新当前时间一个月
ScheduleTimerFunc("UpdateOrder2Complete", func() {
delivery.UpdateOrder2Complete()
}, []string{
"04:00:00",
})
// 每两小时更新一下订单信息UpdateOrderStatus
ScheduleTimerFuncByInterval(func() {
bidaServer.UpdateOrderStatus()
}, 5*time.Second, 2*time.Hour)
}
//update xuhang 2022/04/06用于同步京东数据以取代爬取订单 但由于京东的v2API已不支持手机号 因此以下代码暂时注释 后续接入虚拟号可再次open
/* ScheduleTimerFuncByInterval(func() {
jdshop.InitKey()
}, 10*time.Second, 8*time.Hour)*/
//此处需要新增一个message 存储操作 服务器启动的30s后开始执行 每10s刷新一次
//进行一个JCQ队列定时任务执行
/* ScheduleTimerFuncByInterval(func() {
jcq.JCQSchedule()
}, 10*time.Second, 10*time.Second)*/
//ScheduleTimerFuncByInterval(func() {
// jdslogin.RefreshQRCode()
//}, 10*time.Second, 10*time.Minute)
ScheduleTimerFunc("AutoSaleStoreSku", func() {
cms.AutoSaleStoreSku(jxcontext.AdminCtx, nil, true)
}, autoSaleStoreSkuTimeList)
// 菜市无聊信息同步到果园
if beego.BConfig.RunMode == model.ServerTypeFruits {
ScheduleTimerFunc("SyncMatterC4ToGy", func() {
cms.SyncMatterC4ToGy(jxcontext.AdminCtx, true, true)
}, dailyWorkTimeList)
}
if beego.BConfig.RunMode == "beta" {
//ScheduleTimerFunc("CancelPayTimeOutOrder", func() {
// localjx.CancelPayTimeOutOrder(jxcontext.AdminCtx)
//}, cancelPayTimeOutOrderList)
ScheduleTimerFunc("GetAndStoreCitiesShops", func() {
netspider.GetAndStoreCitiesShops(jxcontext.AdminCtx, nil, nil, 0, 0, false, false)
}, []string{
"04:05:06",
})
//京东的订单信息解密密钥获取
//ScheduleTimerFuncByInterval(func() {
// jdshop.InitKey()
//}, 10*time.Second, 8*time.Hour)
ScheduleTimerFunc("ChangeJxPriceByDiscountAct", func() {
act.ChangeJxPriceByDiscountAct(jxcontext.AdminCtx)
}, discountActJxList)
//ScheduleTimerFunc("CreateOrderByPriceDefend", func() {
// localjx.CreateOrderByPriceDefend(jxcontext.AdminCtx)
//}, []string{
// "22:00:00",
//})
//刷新门店数据坐标等
ScheduleTimerFunc("RefreshPageStore", func() {
cms.RefreshPageStore()
}, []string{
"20:00:00",
})
}
if configs, err := dao.QueryConfigs(dao.GetDB(), "ebaiStorePageCookie", model.ConfigTypeCookie, ""); err == nil {
ebaiStorePageCookie = configs[0].Value
}
if configs, err := dao.QueryConfigs(dao.GetDB(), "mtwmCookieStr", model.ConfigTypeCookie, ""); err == nil {
mtwmCookieStr = configs[0].Value
}
if configs, err := dao.QueryConfigs(dao.GetDB(), "mtpsStoreToken", model.ConfigTypeCookie, ""); err == nil {
mtpsStoreToken = configs[0].Value
}
if configs, err := dao.QueryConfigs(dao.GetDB(), "jdStorePageCookie", model.ConfigTypeCookie, ""); err == nil {
JdStorePageCookie = configs[0].Value
}
if configs, err := dao.QueryConfigs(dao.GetDB(), "jdStorePageEarning", model.ConfigTypeCookie, ""); err == nil {
jdStorePageEarning = configs[0].Value
}
if configs, err := dao.QueryConfigs(dao.GetDB(), "jd2StorePageCookie", model.ConfigTypeCookie, ""); err == nil {
jd2StorePageCookie = configs[0].Value
}
if configs, err := dao.QueryConfigs(dao.GetDB(), "feiePageCookie", model.ConfigTypeCookie, ""); err == nil {
feiePageCookie = configs[0].Value
}
//if configs, err := dao.QueryConfigs(dao.GetDB(), "jdsCookie", model.ConfigTypeCookie, ""); err == nil {
// jdsCookie = configs[0].Value
// api.JdShopAPI.SetCookieWithStr(jdsCookie)
//}
//if configs, err := dao.QueryConfigs(dao.GetDB(), "yinbaoCookie", model.ConfigTypeCookie, ""); err == nil {
// yinbaoCookie := configs[0].Value
// api.YinBaoAPI.SetCookie(".POSPALAUTH30220", yinbaoCookie)
//}
if globals.Jd2OrgCode != "" {
api.Jd2API.SetJdCookie(jd2StorePageCookie)
}
//api.EbaiAPI.SetCookie("PASSPORT_DELIMONT_TOKEN", ebaiStorePageCookieExdTOKEN)
//api.EbaiAPI.SetCookie("WMUSS", ebaiStorePageCookieWMUSS)
//api.EbaiAPI.SetCookie("WMSTOKEN", ebaiStorePageCookieWMSTOKEN)
//api.Ebai2API.SetCookie("PASSPORT_DELIMONT_TOKEN", ebaiStorePageCookieExdTOKEN)
//api.Ebai2API.SetCookie("WMUSS", ebaiStorePageCookieWMUSS2)
//api.Ebai2API.SetCookie("WMSTOKEN", ebaiStorePageCookieWMSTOKEN2)
api.EbaiAPI.SetCookieWithStr(ebaiStorePageCookie)
api.MtwmAPI.SetCookieWithStr(mtwmCookieStr)
api.MtpsAPI.SetCookie("token", mtpsStoreToken)
//api.JdAPI.SetJdCookie(JdStorePageCookie)
api.JdAPI.SetCookieWithStr(JdStorePageCookie)
api.JdAPI.SetCookie("user", jdStorePageEarning)
api.JdPageAPI.SetCookie(jdapi.AccessStorePageCookieName, JdStorePageCookie)
api.JdPageAPI.SetCookie(jdapi.AccessStorePageCookieName2, JdStorePageCookie)
api.FeieAPI.SetCookieWithStr(feiePageCookie)
}
func syncStoreSku() {
syncFlag := 0
syncFlag |= model.SyncFlagPriceMask // SyncFlagSaleMask
task := tasksch.NewParallelTask("同步京西与平台数据", nil, jxcontext.AdminCtx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
step := batchItemList[0].(int)
errList := errlist.New()
db := dao.GetDB()
switch step {
case 0:
if beego.BConfig.RunMode != model.ServerTypeFruits && beego.BConfig.RunMode != model.ServerTypePet {
errList.AddErr(cms.DeleteSkuNameExPrefixOverdue(db))
errList.AddErr(cms.SetMultiStoreSkuSyncModifyStatus(db, partner.GetMultiStoreVendorIDs()))
_, err = cms.CurVendorSync.LoopMultiStoresVendors(jxcontext.AdminCtx, db, "同步多门店平台商品库", false, true,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
vendorInfo := batchItemList[0].(*cms.MultiStoreVendorInfo)
_, err = cms.FullSyncVendorStuff(jxcontext.AdminCtx, task, 0, vendorInfo.VendorID, vendorInfo.OrgCode, false, true)
return retVal, err
})
errList.AddErr(err)
_, err = cms.CurVendorSync.SyncStoresSkus2(jxcontext.AdminCtx, nil, 0, db, nil, nil, false, nil, []int{27379}, syncFlag, true, true)
//_, err = cms.CurVendorSync.FullSyncStoresSkus(jxcontext.AdminCtx, db, partner.GetMultiStoreVendorIDs(), nil, false, []int{27379}, true, true)
errList.AddErr(err)
}
case 1:
//TODO 暂时不同步银豹可能要从银豹到京西2020-04-27
//errList.AddErr(cms.SetSingleStoreSkuSyncModifyStatus(db, []int{1, 3}))
// errList.AddErr(cms.SetSingleStoreSkuSyncModifyStatus(db, partner.GetSingleStoreVendorIDs()))
// _, err = cms.CurVendorSync.AmendAndPruneStoreStuff(jxcontext.AdminCtx, []int{1, 3}, nil, false, true, cms.AmendPruneAll, false)
// _, err = cms.CurVendorSync.AmendAndPruneStoreStuff(jxcontext.AdminCtx, partner.GetSingleStoreVendorIDs(), nil, false, true, cms.AmendPruneAll, false)
errList.AddErr(err)
SaveImportantTaskID(TaskNameSyncStoreSku, SpecialTaskID)
//taskID, err2 := cms.CurVendorSync.SyncStoresSkus2(jxcontext.AdminCtx, nil, 0, db, []int{1, 3}, nil, false, nil, nil, syncFlag, true, true)
// taskID, err2 := cms.CurVendorSync.SyncStoresSkus2(jxcontext.AdminCtx, nil, 0, db, partner.GetSingleStoreVendorIDs(), nil, false, nil, nil, syncFlag, true, true)
//errList.AddErr(err2)
//SaveImportantTaskID(TaskNameSyncStoreSku, taskID)
}
err = errList.GetErrListAsOne()
return retVal, err
}, []int{0, 1})
tasksch.HandleTask(task, nil, true).Run()
}
func syncStoreSkuTiktok() {
//syncFlag := 0 | model.SyncFlagSaleMask
syncFlag := 0
task := tasksch.NewParallelTask("同步京西商品到抖音平台,方案二使用", nil, jxcontext.AdminCtx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
step := batchItemList[0].(int)
errList := errlist.New()
db := dao.GetDB()
switch step {
case 0:
if beego.BConfig.RunMode != model.ServerTypeFruits && beego.BConfig.RunMode != model.ServerTypePet {
_, err = cms.CurVendorSync.SyncStoresSkus2(jxcontext.AdminCtx, nil, 0, db, []int{model.VendorIDDD}, nil, false, nil, nil, syncFlag, true, true)
errList.AddErr(err)
}
case 1:
errList.AddErr(err)
SaveImportantTaskID(TaskNameSyncStoreSku, SpecialTaskID)
}
err = errList.GetErrListAsOne()
return retVal, err
}, []int{0, 1})
tasksch.HandleTask(task, nil, true).Run()
}
// syncStoreSkuTao 同步商品到淘鲜达
func syncStoreSkuTao() {
syncFlag := 0
task := tasksch.NewParallelTask("syncStoreSkuTao ", nil, jxcontext.AdminCtx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
step := batchItemList[0].(int)
errList := errlist.New()
db := dao.GetDB()
switch step {
case 0:
_, err = cms.CurVendorSync.SyncStoresSkus2(jxcontext.AdminCtx, nil, 0, db, []int{model.VendorIDTaoVegetable}, nil, false, nil, nil, syncFlag, true, true)
errList.AddErr(err)
case 1:
SaveImportantTaskID(TaskNameSyncStoreSku, SpecialTaskID)
}
err = errList.GetErrListAsOne()
return retVal, err
}, []int{0, 1})
tasksch.HandleTask(task, nil, true).Run()
}
func doDailyWork2() {
if beego.BConfig.RunMode == "jxgy" {
syncStoreSku()
refreshPointOrderNewEarningPrice()
}
//同步京东商城门店的商品
// cms.CurVendorSync.SyncJdsStoresSkus(jxcontext.AdminCtx, nil, true, true)
//刷新京东商城的门店库存
// cms.SyncJdsStoreStock(jxcontext.AdminCtx, true, true)
}
func doDailyWork() {
//同步商品额外前缀和水印图(打标记)
cms.SyncSkuExperfixAndWatermark(jxcontext.AdminCtx)
dao.SetStoresMapSyncStatus(dao.GetDB(), nil, nil, model.SyncFlagStoreStatus)
cms.CurVendorSync.SyncStore2(jxcontext.AdminCtx, dao.GetDB(), []int{model.VendorIDMTWM, model.VendorIDJD, model.VendorIDEBAI}, nil, true, true)
if beego.BConfig.RunMode == "prod" {
syncStoreSku()
}
InitEx()
cms.SyncStoresCourierInfo(jxcontext.AdminCtx, nil, false, true)
netprinter.RebindAllPrinters(jxcontext.AdminCtx, false, true)
// 每天补全前一天与当天的订单
// curDate := utils.Time2Date(time.Now())
// orderman.FixedOrderManager.AmendMissingOrders(jxcontext.AdminCtx, nil, 0, curDate.Add(-72*time.Hour), curDate, true, true)
//订单门店归属补漏
//fromDate, toDate都不传默认刷新当前天5天以前的订单只传fromDate默认刷新fromDate到当天的订单
//只传toDate默认刷新toDate到5天以前的订单
orderman.RefreshOrdersWithoutJxStoreID(jxcontext.AdminCtx, "", "", true, true)
//刷新京东门店的等级
// cms.RefreshJdLevel(jxcontext.AdminCtx)
//删除操作日志
// event.DeleteOperateEventAndDetail(jxcontext.AdminCtx, time.Now().AddDate(0, -3, 0))
//禁用没有绑定的门店
cms.DisabledStoreWithoutVendor(jxcontext.AdminCtx, true, true)
//刷新物料订单状态
localjx.RefreshAllMatterOrderStatus(jxcontext.AdminCtx)
//同步银豹到京西
// cms.CurVendorSync.SyncStoreSkusFromYb(jxcontext.AdminCtx, nil, true, true)
//同步上架京东商城待售商品
// cms.RefreshJdsSkusStatus(jxcontext.AdminCtx)
//同步美团配送与否状态及美团门店是否存在
cms.SetMTPSStatus(jxcontext.AdminCtx, 0, 0)
//售后单如果超过12小时没有审核就自动通过
//RefreshAfsOrderStatusAccess(jxcontext.AdminCtx)
//刷新京东商城订单结算价
orderman.RefreshJdShopOrdersEarningPrice(jxcontext.AdminCtx, utils.Time2Str(time.Now().AddDate(0, 0, -2)), utils.Time2Str(time.Now()))
//刷新门店分组管理
cms.RefreshStoreBind(jxcontext.AdminCtx)
//刷新京东会员
report.RefreshJDMembers(jxcontext.AdminCtx)
}
func refreshPointOrderNewEarningPrice() {
var (
db = dao.GetDB()
orders []*model.GoodsOrder
)
sql := `
SELECT * FROM goods_order WHERE earning_type = 2 AND status = 110 AND order_created_at > ?
`
sqlParams := []interface{}{time.Now().AddDate(0, 0, -1)}
dao.GetRows(db, &orders, sql, sqlParams)
if len(orders) > 0 {
for _, v := range orders {
if v.NewEarningPrice == 0 {
v.NewEarningPrice = int64(int(v.TotalShopMoney) * (100 - v.OrderPayPercentage/2) / 100)
dao.UpdateEntity(db, v, "NewEarningPrice")
}
}
}
}
//func RefreshAfsOrderStatusAccess(ctx *jxcontext.Context) {
// var (
// offset = 0
// pageSize = 9999
// db = dao.GetDB()
// )
// afsOrderList, _, err := dao.GetAfsOrdersByPage(db, "", "", "", time.Now().AddDate(0, 0, -7), time.Now(), offset, pageSize)
// if err != nil {
// return
// }
// for _, v := range afsOrderList {
// if v.Status == model.AfsOrderStatusWait4Approve && time.Now().Sub(v.AfsCreatedAt).Hours() > 12 {
// defsch.FixedScheduler.AgreeOrRefuseRefund(ctx, v.AfsOrderID, v.VendorID, model.AfsTypePartRefund, "超时系统同意")
// }
// }
//}
func RefreshRealMobile(ctx *jxcontext.Context, vendorID int, fromTime, toTime time.Time, isAsync, isContinueWhenError bool) (hint string, err error) {
handler := partner.GetPurchasePlatformFromVendorID(vendorID)
if handler == nil {
return "", fmt.Errorf("不合法的vendorID:%d", vendorID)
}
sql := `
SELECT *
FROM goods_order
WHERE vendor_id = ? AND consignee_mobile2 = ''
`
sqlParams := []interface{}{
vendorID,
}
if !utils.IsTimeZero(fromTime) {
sql += " AND order_created_at >= ?"
sqlParams = append(sqlParams, fromTime)
}
if !utils.IsTimeZero(toTime) {
sql += " AND order_created_at <= ?"
sqlParams = append(sqlParams, toTime)
}
var orderList []*model.GoodsOrder
db := dao.GetDB()
if err = dao.GetRows(db, &orderList, sql, sqlParams...); err == nil && len(orderList) > 0 {
task := tasksch.NewParallelTask("misc RefreshRealMobile", tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError), ctx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
order := batchItemList[0].(*model.GoodsOrder)
mobile, err2 := handler.GetOrderRealMobile(ctx, order)
if err = err2; err == nil {
//mobile = jxutils.FormalizeMobile(mobile)
//if jxutils.IsStringLikeMobile(mobile) && strings.Index(order.ConsigneeMobile, mobile) == -1 {
order.ConsigneeMobile2 = mobile
_, err = dao.UpdateEntity(db, order, "ConsigneeMobile2")
//}
} else {
globals.SugarLogger.Infof("RefreshRealMobile orderID:%s failed with error:%v", order.VendorOrderID, err)
}
return nil, err
}, orderList)
tasksch.HandleTask(task, nil, true).Run()
hint = task.ID
if !isAsync {
_, err = task.GetResult(0)
}
}
return hint, err
globals.SugarLogger.Debug("doDailyWork")
//刷新任务过期状态
cms.RefreshJobStatus(jxcontext.AdminCtx)
//刷新任务标签状态
cms.RefreshJobSpan(jxcontext.AdminCtx)
//刷新用户会员时间
cms.RefreshUserMemberStatus(jxcontext.AdminCtx)
//删除聊天记录
event.DeleteMessageRecord(jxcontext.AdminCtx)
//自动确认收货(刷新状态)
cms.RefreshDropShippingJob(jxcontext.AdminCtx)
//刷新京东快递
cms.RefreshJdDelivery(jxcontext.AdminCtx)
//美团联盟活动自动创建
cms.MtUnionJobAutoUpdate(jxcontext.AdminCtx)
}
// 按时间序列循环
@@ -827,7 +78,9 @@ func ScheduleTimerFunc(name string, handler func(), timeList []string) {
now := time.Now()
nextTime := jxutils.GetNextTimeFromList(now, timeList)
duration := nextTime.Sub(now) + 1*time.Second
globals.SugarLogger.Debugf("ScheduleTimerFunc, func:%s, duration:%v", name, duration)
utils.AfterFuncWithRecover(duration, func() {
globals.SugarLogger.Debugf("ScheduleTimerFunc func:%s", name)
handler()
ScheduleTimerFunc(name, handler, timeList)
})
@@ -838,12 +91,15 @@ func ScheduleTimerFuncOnce(name string, handler func(interface{}), timeStr strin
now := time.Now()
nextTime := jxutils.GetNextTimeFromList(now, []string{timeStr})
duration := nextTime.Sub(now) + 1*time.Second
globals.SugarLogger.Debugf("ScheduleTimerFuncOnce, func:%s, duration:%v", name, duration)
utils.AfterFuncWithRecover(duration, func() {
globals.SugarLogger.Debugf("ScheduleTimerFuncOnce func:%s", name)
handler(param)
})
}
func ScheduleTimerFuncByInterval(handler func(), delay, inerval time.Duration) {
globals.SugarLogger.Debugf("ScheduleTimerFuncByInterval, delay:%v, inerval:%v", delay, inerval)
utils.AfterFuncWithRecover(delay, func() {
beginTime := time.Now()
handler()

View File

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

View File

@@ -1,18 +0,0 @@
package misc
import (
"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"
"testing"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
)
func TestStartOrEndOpStore(t *testing.T) {
StartOrEndOpStore(jxcontext.AdminCtx, true, nil, nil, 0, 0, false, true)
}
func TestIssny(t *testing.T) {
cms.CurVendorSync.SyncStore2(jxcontext.AdminCtx, dao.GetDB(), []int{model.VendorIDMTWM, model.VendorIDJD, model.VendorIDEBAI}, nil, true, true)
}

View File

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

View File

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

View File

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

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