Compare commits

1965 Commits

Author SHA1 Message Date
邹宗楠
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
415 changed files with 18687 additions and 94304 deletions

View File

@@ -4,6 +4,7 @@ import (
"bytes"
"encoding/base64"
"errors"
"fmt"
"regexp"
"strings"
"time"
@@ -212,9 +213,6 @@ func SendVerifyCode(authToken, captchaID, captchaValue, authID string) (verfifyC
if handler := authers[authType]; handler == nil {
err = ErrIllegalAuthType
} else {
//if user, _ := dao.GetUserByID(dao.GetDB(), "mobile", authID); user != nil {
// return "", authInfo, fmt.Errorf("该用户已存在,请勿重复注册!")
//}
verfifyCode, err = handler.SendVerifyCode(authID)
}
}
@@ -246,7 +244,6 @@ func LoginInternal(ctx *Context, authType, authID, authIDType, authSecret string
realAuthID = user.GetID()
}
if authBindEx, err = handler.VerifySecret(realAuthID, authSecret); err == nil {
globals.SugarLogger.Debugf("Login authBindEx", utils.Format4Output(authBindEx, false))
if authBindEx == nil { // mobile, email会返回nil表示不会新建AuthBind实体
user = userProvider.GetUser(authID, authIDType)
authBindEx = &AuthBindEx{
@@ -269,10 +266,6 @@ func LoginInternal(ctx *Context, authType, authID, authIDType, authSecret string
// if user != nil {
// authBindEx.UserID = user.GetID()
// }
if user2 := userProvider.GetUser(authBindEx.UserHint.Email, UserIDMobile); user2 != nil {
user = user2
}
} else if authBindEx.UserID != "" {
user = userProvider.GetUser(authBindEx.UserID, UserIDID)
}
@@ -284,9 +277,9 @@ func LoginInternal(ctx *Context, authType, authID, authIDType, authSecret string
//如果是小程序
if authType == "weixinmini" || authType == "weixinapp" {
appID := strings.Split(authSecret, ",")[0]
if appID == "wx08a5c2a8581414ff" || appID == "wx2d6949f724b2541d" || appID == "wx18111a41fd17f24f" || appID == "wx4b5930c13f8b1170" { //菜市或者果园
if authInfo.AuthBindInfo.UserID != "" {
binds, err := dao.GetUserBindAuthInfo(dao.GetDB(), authInfo.AuthBindInfo.UserID, 0, nil, "", "", []string{"wx2bb99eb5d2c9b82c", "wx4b5930c13f8b1170"})
if appID == "wxa4a76d7b4c88604e" || appID == "wx2d6949f724b2541d" || appID == "wx18111a41fd17f24f" { //菜市或者果园
if user != nil {
binds, err := dao.GetUserBindAuthInfo(dao.GetDB(), user.GetID(), 0, nil, "", "", "wx2bb99eb5d2c9b82c")
if err != nil {
return authInfo, err
}
@@ -482,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) {
@@ -495,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

@@ -10,8 +10,6 @@ import (
const (
AuthType = "alipaycode"
AuthKey = "GHp3ojlVYRRu2XID4FX2ew=="
)
type Auther struct {
@@ -31,11 +29,14 @@ func (a *Auther) VerifySecret(dummy, code string) (authBindEx *auth2.AuthBindEx,
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

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

View File

@@ -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,
@@ -69,11 +72,12 @@ 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

@@ -57,12 +57,11 @@ func init() {
}
func (a *Auther) VerifySecret(id, secret string) (authBindEx *auth2.AuthBindEx, err error) {
globals.SugarLogger.Debugf("weixin VerifySecret id:%s secret:%s", id, secret)
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 == "" {
token, err2 := a.getAPI().SNSRetrieveToken(code)
if err = err2; err == nil {

View File

@@ -57,9 +57,9 @@ func (a *MiniAuther) DecryptData(authInfo *auth2.AuthInfo, jsCode, encryptedData
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
// }
@@ -69,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)
}
@@ -88,12 +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
}
return miniApi
}

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -0,0 +1,463 @@
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 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

@@ -71,7 +71,7 @@ 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
}

View File

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

View File

@@ -1,28 +1,24 @@
package cms
import (
"encoding/json"
"fmt"
"git.rosy.net.cn/baseapi/platformapi/mtunionapi"
"git.rosy.net.cn/baseapi/platformapi/tbunionapi"
"reflect"
"regexp"
"strconv"
"strings"
"time"
"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"
@@ -43,61 +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
},
},
}
)
func InitServiceInfo(version string, buildTime time.Time, gitCommit string) {
@@ -111,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,
},
}
}
@@ -195,34 +154,6 @@ func GetPlaces(ctx *jxcontext.Context, keyword string, includeDisabled bool, par
return places, dao.GetRows(nil, &places, sql, sqlParams)
}
func UpdatePlaces(ctx *jxcontext.Context, places []map[string]interface{}, userName string) (num int64, err error) {
if len(places) == 0 {
return 0, ErrMissingInput
}
updateFields := []string{}
for k := range places[0] {
if allowUpdatePlaceFieldsMap[k] {
updateFields = append(updateFields, k)
}
}
for _, place := range places {
if place["code"] == nil {
return 0, ErrMissingInput
}
placeid := &model.Place{}
valid := dao.NormalMakeMapByFieldList(place, updateFields, userName)
if num, err = dao.UpdateEntityLogically(nil, placeid, valid, userName, utils.Params2Map("Code", place["code"])); err != nil {
return num, err
}
}
return num, err
}
func UpdatePlace(ctx *jxcontext.Context, placeCode int, payload map[string]interface{}, userName string) (num int64, err error) {
payload["code"] = placeCode
return UpdatePlaces(ctx, []map[string]interface{}{payload}, userName)
}
func GetCoordinateDistrictCode(ctx *jxcontext.Context, lng, lat float64) (code int, err error) {
return api.AutonaviAPI.GetCoordinateDistrictCode(lng, lat), nil
}
@@ -233,175 +164,14 @@ func GetCoordinateCityInfo(ctx *jxcontext.Context, lng, lat float64) (name strin
}
func SendMsg2Somebody(ctx *jxcontext.Context, mobileNum, verifyCode, msgType, msgContent string) (err error) {
if needConfirmRequestMap[msgType] == 1 {
if _, err = mobile.AutherObj.VerifySecret(mobileNum, verifyCode); err != nil {
return err
}
}
db := dao.GetDB()
//获取门店信息
var (
stores []*model.Store
authBinds []*model.AuthBind
order *model.GoodsOrder
storeName string
storeID int
vendorOrderID string
)
if mobileNum != "" {
sql := `
SELECT * FROM store WHERE (tel1 = ? OR tel2 = ?) AND deleted_at = ?
`
sqlParams := []interface{}{mobileNum, mobileNum, utils.DefaultTimeValue}
err = dao.GetRows(db, &stores, sql, sqlParams)
if len(stores) > 0 {
storeName = stores[0].Name
storeID = stores[0].ID
}
if storeID == 0 {
results := regexpMsgContentOpID.FindStringSubmatch(msgContent)
if len(results) > 0 {
sql3 := `
SELECT * FROM auth_bind WHERE auth_id = ? OR auth_id2 = ?
`
sqlParams3 := []interface{}{results[1], results[1]}
err = dao.GetRows(db, &authBinds, sql3, sqlParams3)
if len(authBinds) > 0 {
user, _ := dao.GetUserByID(db, "user_id", authBinds[0].UserID)
mobileNum = *user.Mobile
sqlParams4 := []interface{}{mobileNum, mobileNum, utils.DefaultTimeValue}
err = dao.GetRows(db, &stores, sql, sqlParams4)
if len(stores) > 0 {
storeName = stores[0].Name
storeID = stores[0].ID
}
}
}
}
} else {
results := regexpMsgContentOpID.FindStringSubmatch(msgContent)
if len(results) > 0 {
sql3 := `
SELECT * FROM auth_bind WHERE auth_id = ? OR auth_id2 = ?
`
sqlParams3 := []interface{}{results[1], results[1]}
err = dao.GetRows(db, &authBinds, sql3, sqlParams3)
if len(authBinds) > 0 {
user, _ := dao.GetUserByID(db, "user_id", authBinds[0].UserID)
mobileNum = *user.Mobile
sql4 := `
SELECT * FROM store WHERE (tel1 = ? OR tel2 = ?) AND deleted_at = ?
`
sqlParams4 := []interface{}{mobileNum, mobileNum, utils.DefaultTimeValue}
err = dao.GetRows(db, &stores, sql4, sqlParams4)
if len(stores) > 0 {
storeName = stores[0].Name
storeID = stores[0].ID
}
}
}
}
sql2 := `
SELECT *
FROM goods_order
WHERE IF(store_id <> '', store_id, jx_store_id) = ?
ORDER BY order_created_at DESC
LIMIT 1
`
sqlParams2 := []interface{}{storeID}
err = dao.GetRow(db, &order, sql2, sqlParams2)
if order != nil {
vendorOrderID = order.VendorOrderID
}
if storeID == 0 {
vendorOrderID = ""
}
msgContent = msgContent + " 门店名称:" + storeName + " 门店ID" + utils.Int2Str(storeID) + " 最新订单号:" + vendorOrderID
for _, v := range receiveMsgUsersMap[msgType] {
user, err2 := dao.GetUserByID(db, "name", v)
if err2 == nil {
ddmsg.SendUserMessage(dingdingapi.MsgTyeText, user.GetID(), msgType, msgContent)
} else if err == nil {
err = err2
}
}
return err
}
func checkSysConfig(key, value string) (err error) {
if limit := SysConfigLimitMap[key]; limit != nil {
if limit.ValueType == reflect.Int {
int64Value, err2 := strconv.ParseInt(value, 10, 64)
if err = err2; err == nil {
if int64Value < limit.MinValue || int64Value > limit.MaxValue {
err = fmt.Errorf("配置%s,值%s超范围[%d,%d]", key, value, limit.MinValue, limit.MaxValue)
}
}
}
}
return err
}
func onSysConfigChanged(key, value string) (err error) {
if limit := SysConfigLimitMap[key]; limit != nil && limit.AfterChanged != nil {
err = limit.AfterChanged()
}
return err
}
func checkConfig(opFlag int, configType, key, value string) (err error) {
switch configType {
case model.ConfigTypePricePack:
if value != "" {
pricePack := dao.PricePercentagePack2Obj(value)
if pricePack == nil {
err = fmt.Errorf("配置:%s不合法", value)
}
}
case model.ConfigTypeFreightPack:
if value != "" {
freightPack := dao.FreightDeductionPack2Obj(value)
if freightPack == nil {
err = fmt.Errorf("配置:%s不合法", value)
} else {
var lastStage *model.FreightDeductionItem
for _, v := range freightPack.FreightDeductionList {
if lastStage != nil && lastStage.DeductFreight > v.DeductFreight {
err = fmt.Errorf("免运设置不合理:门槛:%s,免运金额:%s,门槛:%s,免运金额:%s",
jxutils.IntPrice2StandardString(int64(lastStage.BeginPrice)), jxutils.IntPrice2StandardString(int64(lastStage.DeductFreight)),
jxutils.IntPrice2StandardString(int64(v.BeginPrice)), jxutils.IntPrice2StandardString(int64(v.DeductFreight)))
return err
}
lastStage = v
}
}
}
case model.ConfigTypeBank:
if value != "" {
if model.BankName[key] == "" {
err = fmt.Errorf("此银行代码:%s不支持请联系开发", value)
}
}
case model.ConfigTypeRole:
case model.ConfigTypeSys:
if opFlag&( /*model.SyncFlagNewMask|*/ model.SyncFlagDeletedMask) != 0 {
err = fmt.Errorf("系统参数只支持修改或添加,不支持删除")
} else {
err = checkSysConfig(key, value)
}
case model.ConfigTypeJxStore:
case model.ConfigTypeCookie:
case model.ConfigTypeDiscountCard:
default:
err = fmt.Errorf("当前只支持配置:%s, 传入的配置类型:%s", utils.Format4Output(model.ConfigTypeName, true), configType)
}
return err
}
func AddConfig(ctx *jxcontext.Context, key, configType, value string) (err error) {
if err = checkConfig(model.SyncFlagNewMask, configType, key, value); err != nil {
return err
}
// if err = checkConfig(model.SyncFlagNewMask, configType, key, value); err != nil {
// return err
// }
db := dao.GetDB()
conf := &model.NewConfig{
@@ -412,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("暂不支持删除银行")
@@ -454,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")))
@@ -462,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()
}
@@ -480,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
}
@@ -489,13 +232,10 @@ func UpdateConfig(ctx *jxcontext.Context, key, configType, value string) (hint s
if key == "" {
return "", fmt.Errorf("修改配置必须给定key")
}
if err = checkConfig(model.SyncFlagModifiedMask, configType, key, value); err != nil {
return "", err
}
hint = "1"
db := dao.GetDB()
txDB , _ := dao.Begin(db)
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, txDB)
@@ -515,54 +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
}
@@ -571,16 +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)
func InitStation(ctx *jxcontext.Context) (err error) {
var (
db = dao.GetDB()
stationMap = make(map[string]*model.StationInfo)
stationEjyMap = make(map[string]*ejyapi.GetStationListResult)
addList []*model.StationInfo
updateList []*model.StationInfo
deleteList []*model.StationInfo
)
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
}
}
return info, err
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 {
updateList = append(updateList, stationMap[v.StationID])
}
}
}
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
}
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,
}
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

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

View File

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

View File

@@ -0,0 +1,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,14 +1,9 @@
package permission
package cms
import (
"fmt"
"strings"
"time"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
@@ -16,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) {
@@ -39,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)
}
@@ -89,31 +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, "")
for _, v := range roles {
if v.CityCodes != "" {
if cityInfos, err := dao.GetPlaces(db, jxutils.StrListToIntList(strings.Split(v.CityCodes, ","))); err == nil {
v.CityInfo = cityInfos
}
}
if v.StoreIDs != "" {
if stores, err := dao.GetStoreList(db, jxutils.StrListToIntList(strings.Split(v.StoreIDs, ",")), nil, nil, nil, nil, ""); err == nil {
v.Stores = stores
}
}
}
return roles, err
func 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)
}
@@ -133,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("管理员不允许修改!")
}
@@ -165,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")
@@ -210,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)
}
@@ -247,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
}
@@ -290,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)
}
}
}
@@ -330,102 +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()
// brandIDMap = make(map[int]int)
// cityCodeMap = make(map[int]int)
// storeIDMap = make(map[int]int)
)
resultMap = make(map[int]int)
user, _ := dao.GetUserByID(db, "user_id", userID)
if user != nil {
if user.BindStoreID != "" {
for _, v := range strings.Split(user.BindStoreID, ",") {
resultMap[utils.Str2Int(v)] = utils.Str2Int(v)
}
return resultMap, err
}
}
userRoles, err2 := dao.GetUserRole2(db, []string{userID}, nil)
err = err2
for _, v := range userRoles {
var (
brandIDs, cityCodes, storeIDs []int
)
// if _, ok := brandIDMap[v.BrandID]; !ok {
// brandIDMap[v.BrandID] = 1
// }
// if v.CityCodes != "" {
// for _, cityCode := range jxutils.StrListToIntList(strings.Split(v.CityCodes, ",")) {
// if _, ok := cityCodeMap[cityCode]; !ok {
// cityCodeMap[cityCode] = 1
// }
// }
// }
// if v.StoreIDs != "" {
// for _, storeID := range jxutils.StrListToIntList(strings.Split(v.StoreIDs, ",")) {
// if _, ok := storeIDMap[storeID]; !ok {
// storeIDMap[storeID] = 1
// }
// }
// }
if v.CityCodes == "" && v.StoreIDs == "" {
continue
}
if v.BrandID != 0 {
brandIDs = append(brandIDs, v.BrandID)
}
if v.CityCodes != "0" && v.CityCodes != "" {
cityCodes = append(cityCodes, jxutils.StrListToIntList(strings.Split(v.CityCodes, ","))...)
}
if v.StoreIDs != "" {
storeIDs = append(storeIDs, jxutils.StrListToIntList(strings.Split(v.StoreIDs, ","))...)
}
if stores, err := dao.GetStoreList(db, storeIDs, cityCodes, nil, brandIDs, nil, ""); len(stores) > 0 && err == nil {
for _, v := range stores {
resultMap[v.ID] = v.ID
}
}
}
// for k, _ := range brandIDMap {
// brandIDs = append(brandIDs, k)
// }
// for k, _ := range cityCodeMap {
// cityCodes = append(cityCodes, k)
// }
// for k, _ := range storeIDMap {
// storeIDs = append(storeIDs, k)
// }
// if stores1, err := dao.GetStoreList(db, nil, nil, brandIDs, nil, nil, ""); len(stores1) > 0 && err == nil {
// stores = append(stores, stores1...)
// }
// if stores2, err := dao.GetStoreList(db, nil, cityCodes, nil, nil, nil, ""); len(stores2) > 0 && err == nil {
// stores = append(stores, stores2...)
// }
// if stores3, err := dao.GetStoreList(db, storeIDs, nil, nil, nil, nil, ""); len(stores3) > 0 && err == nil {
// stores = append(stores, stores3...)
// }
return resultMap, err
}
func IsRoled(ctx *jxcontext.Context) bool {
if ctx.GetUserName() != "jxadmin" {
if user, err := dao.GetUserByID(dao.GetDB(), "user_id", ctx.GetUserID()); err == nil {
if user.Type&model.UserTypeRole != 0 {
return true
}
}
}
return false
}
func IsRoledByUserID(userID string) bool {
if user, err := dao.GetUserByID(dao.GetDB(), "user_id", userID); err == nil {
if user.Type&model.UserTypeRole != 0 {
return true
}
}
return false
}

View File

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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

@@ -1,16 +1,7 @@
package common
import (
"fmt"
"sort"
"git.rosy.net.cn/baseapi/platformapi/autonavi"
"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 {
@@ -62,228 +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)
// 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 <> ?
`
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 brandID != 0 {
sql += " AND t1.brand_id = ?"
sqlParams = append(sqlParams, brandID)
}
sql += `
ORDER BY t1.id
`
} 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.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
}
func GetVendorOrgCode(ctx *jxcontext.Context, vendorID int, vendorOrgCode, vendorType string) (vendorOrgs []*model.VendorOrgCode, err error) {
return dao.GetVendorOrgCode(dao.GetDB(), vendorID, vendorOrgCode, vendorType)
}
func UpdateVendorOrgCode(ctx *jxcontext.Context, ID int, payload map[string]interface{}) (err error) {
var (
db = dao.GetDB()
vendorOrgCode = &model.VendorOrgCode{}
)
vendorOrgCode.ID = ID
err = dao.GetEntity(db, vendorOrgCode)
valid := dao.StrictMakeMapByStructObject(payload, vendorOrgCode, ctx.GetUserName())
if len(valid) > 0 {
if valid["key"] != nil {
valid["vendorOrgCode"] = valid["key"]
delete(valid, "key")
}
if valid["code"] != nil {
valid["vendorID"] = valid["code"]
delete(valid, "code")
}
if valid["name"] != nil {
valid["comment"] = valid["name"]
delete(valid, "name")
}
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, txDB)
panic(r)
}
}()
if _, err = dao.UpdateEntityLogically(db, vendorOrgCode, valid, ctx.GetUserName(), nil); err != nil {
dao.Rollback(db, txDB)
return err
}
dao.Commit(db, txDB)
}
return err
}
func AddVendorOrgCode(ctx *jxcontext.Context, vendorOrgCode *model.VendorOrgCode) (err error) {
var (
db = dao.GetDB()
)
list, err := dao.GetVendorOrgCode(db, vendorOrgCode.VendorID, vendorOrgCode.VendorOrgCode, model.VendorOrgTypePlatform)
if err != nil {
return err
}
if len(list) > 0 {
return fmt.Errorf("库里有这个账号了,[%v]", vendorOrgCode.VendorOrgCode)
}
dao.WrapAddIDCULDEntity(vendorOrgCode, ctx.GetUserName())
dao.CreateEntity(db, vendorOrgCode)
return err
}
//
//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

@@ -4,29 +4,179 @@ import (
"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) {
@@ -67,7 +217,7 @@ func AddOperateEvent(ctx *jxcontext.Context, accessUUID, jsonData string, errCod
ErrMsg: errMsg,
UseTime: useTime,
}
txDB , _ := dao.Begin(db)
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, txDB)
@@ -80,7 +230,7 @@ func AddOperateEvent(ctx *jxcontext.Context, accessUUID, jsonData string, errCod
}
func AddOperateEventDetail(db *dao.DaoDB, operateEventDetail *model.OperateEventDetail) (err error) {
txDB , _ := dao.Begin(db)
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, txDB)
@@ -96,7 +246,7 @@ func AddOperateEventDetail(db *dao.DaoDB, operateEventDetail *model.OperateEvent
func DeleteOperateEventAndDetail(ctx *jxcontext.Context, deleteTime time.Time) (err error) {
db := dao.GetDB()
txDB , _ := dao.Begin(db)
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, txDB)
@@ -134,68 +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无效了")
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无效了")
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)
}
globals.SugarLogger.Debugf("cookieCheck", err)
}
case model.VendorIDJD:
result, err := api.JdAPI.GetJdUpcCodeByName("", jdUpcCode, 1, 5)
if len(result) < 1 && err != nil {
if strings.Contains(err.Error(), jdErr) {
errMsg += fmt.Sprintf(" 京东账号:[%v]的Cookie无效了")
flag = true
}
}
case model.VendorIDJDShop:
_, err := api.JdShopAPI.OrderDetail("124350112427")
if err != nil {
if strings.Contains(err.Error(), "登录") {
errMsg += fmt.Sprintf("京东商城:[%v]的Cookie无效了")
flag = true
}
globals.SugarLogger.Debugf("cookieCheck", err)
}
}
cc.VendorID = v
cc.VendorOrgCode = ""
if flag {
cc.Status = "无效"
} else {
cc.Status = "有效"
} 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,388 @@
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()
Poll.Wait()
Poll.Stop()
return
}
}
Poll.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)
} else if pn != "" {
printStatusOff[pn] = 1
}
}
for pn, ip := range PrintIpAndAddr.PrintObject {
if ip == printRemoteAddr {
PrintIpAndAddr.DelPrintIpAndAddr(pn)
} else if pn != "" {
printStatusOff[pn] = 1
}
}
globals.SugarLogger.Debugf("----可能存活打印机打印机:%s", utils.Format4Output(printStatusOff, false))
for pn, _ := range PrintObject.PrintObject {
if printStatusOff[pn] != 1 {
globals.SugarLogger.Debugf("----已经不存在但是未删除打印机:%s", pn)
PrintObject.DelPrintObj(pn)
}
}
}
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
}
}
Poll.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
}
}
}
Poll.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 {
globals.SugarLogger.Debugf("-------close1 := %s", key)
t.getClients(key).C.Close()
close(t.MsgMap[key])
close(t.CallBackMap[key])
t.delConn(key)
// 链接出错,彻底删除换成
if printRemoteAddrIP, have := PrintIpAndAddr.GetPrintIpAndAddr(key); have {
PrintIpAndAddr.DelPrintIpAndAddr(key)
PrintAddrAndIp.DelPrintAddrAndIp(printRemoteAddrIP)
PrintObject.DelPrintObj(key)
}
return
}
}

View File

@@ -0,0 +1,688 @@
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()
globals.SugarLogger.Debugf("-------close3 := %s", key)
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,92 @@
package event
import (
"sync"
)
var Poll *Pool
func init() {
Poll = NewPool(500)
Poll.Start()
}
type Job func()
type Worker struct {
id int
jobChannel chan Job
quit chan bool
}
type Pool struct {
workers []*Worker
jobChannel chan Job
wg sync.WaitGroup
}
func NewWorker(id int, jobChannel chan Job) *Worker {
return &Worker{
id: id,
jobChannel: jobChannel,
quit: make(chan bool),
}
}
func (w *Worker) Start() {
go func() {
for {
select {
case job := <-w.jobChannel:
job()
case <-w.quit:
return
}
}
}()
}
func (w *Worker) Stop() {
go func() {
w.quit <- true
}()
}
func NewPool(numWorkers int) *Pool {
jobChannel := make(chan Job)
pool := &Pool{
workers: make([]*Worker, numWorkers),
jobChannel: jobChannel,
}
for i := 0; i < numWorkers; i++ {
worker := NewWorker(i, jobChannel)
pool.workers[i] = worker
}
return pool
}
func (p *Pool) Start() {
for _, worker := range p.workers {
worker.Start()
}
}
func (p *Pool) Stop() {
for _, worker := range p.workers {
worker.Stop()
}
}
func (p *Pool) AddJob(job Job) {
p.wg.Add(1)
p.jobChannel <- func() {
job()
p.wg.Done()
}
}
func (p *Pool) Wait() {
p.wg.Wait()
}

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,119 +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) {
globals.SugarLogger.Debugf("SendFilesToStores, fileCount:%d isAsync:%t, userName:%s", len(files), isAsync, userName)
if len(files) == 0 {
return "", errors.New("没有文件上传!")
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))
}
}
}
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
}
fileList := make([]*tUploadFileInfo, len(files))
for k, fileHeader := range files {
fileList[k] = &tUploadFileInfo{
FileHeader: fileHeader,
}
fileNameParts := strings.Split(fileHeader.Filename, "_")
if len(fileNameParts) < 3 {
return "", fmt.Errorf("文件名:%s不规范没有包含三个必要的部分", fileHeader.Filename)
}
fileList[k].StoreID = int(utils.Str2Int64WithDefault(fileNameParts[0], 0))
if fileList[k].StoreID < 100000 || fileList[k].StoreID > 1000000 {
return "", fmt.Errorf("文件名:%s不规范不以合法的京西门店ID开始", fileHeader.Filename)
}
}
putPolicy := storage.PutPolicy{
Scope: globals.QiniuBucket,
Expires: 10 * 60,
}
upToken := putPolicy.UploadToken(api.QiniuAPI)
cfg := &storage.Config{}
task := tasksch.NewParallelTask("SendFilesToStores", tasksch.NewParallelConfig().SetIsContinueWhenError(true), ctx,
func(t *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
fileInfo := batchItemList[0].(*tUploadFileInfo)
fileHeader := fileInfo.FileHeader
db := dao.GetDB()
storeID, _ := dao.GetRealLinkStoreID(db, fileInfo.StoreID)
file, err := fileHeader.Open()
globals.SugarLogger.Debugf("SendFilesToStores upload file:%s", fileHeader.Filename)
if err == nil {
ret := storage.PutRet{}
key := "storeBill/" + utils.Int2Str(storeID) + "_" + strings.ToLower(utils.GetUUID()) + path.Ext(fileHeader.Filename)
formUploader := storage.NewFormUploader(cfg)
for i := 0; i < 3; i++ {
if err = formUploader.Put(context.Background(), &ret, upToken, key, file, fileHeader.Size, &storage.PutExtra{}); err == nil {
break
}
}
file.Close()
if err == nil {
billRec := &legacymodel.StoreBill{
Date: time.Now(),
Url: strings.Replace(jxutils.ComposeQiniuResURL(ret.Key), "http://", "https://", -1),
StoreId: storeID,
BillName: fileHeader.Filename,
ShopName: shopName,
BillTitle: title,
}
if err = dao.CreateEntity(db, billRec); err == nil {
err = weixinmsg.NotifySaleBill(storeID, title, shopName, fmt.Sprintf("%s/billshow/?path=%s", globals.BackstageHost, billRec.Url))
if err != nil {
globals.SugarLogger.Infof("SendFilesToStores NotifySaleBill file:%s error:%v", fileHeader.Filename, err)
}
err = nil // 忽略微信发送错误
} else {
globals.SugarLogger.Warnf("SendFilesToStores CreateEntity file:%s error:%v", fileHeader.Filename, err)
}
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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,27 @@
package jds
import (
"git.rosy.net.cn/baseapi/platformapi/jdunionapi"
"git.rosy.net.cn/jx-callback/business/jxstore/partner"
"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 UnionHandler struct {
}
var (
unionHandler *UnionHandler
)
func init() {
partner.UnionHandlerMap[model.VendorIDJDShop] = unionHandler
}
func getAPI() (apiobj *jdunionapi.API) {
if configs, err := dao.QueryConfigs(dao.GetDB(), "jdunionCookie", model.ConfigTypeCookie, ""); err == nil {
api.JdUnionAPI.SetCookieWithStr(configs[0].Value)
}
return api.JdUnionAPI
}

View File

@@ -0,0 +1,48 @@
package jds
import (
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxstore/partner"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
)
func (s *UnionHandler) ShareUnionLink(ctx *jxcontext.Context, linkType, unionActID int, sID, userID string, resourceType int, goodsID string) (link string, err error) {
return "jds", err
}
func (s *UnionHandler) GetUnionActList(ctx *jxcontext.Context, actType int) (actList []*partner.ActivityList, err error) {
if result, err2 := getAPI().ListActivitys(); err2 == nil {
for _, v := range result {
act := &partner.ActivityList{
ActID: v.Activityid,
ActName: v.Activityname,
ActDes: v.Remark,
Ratio: "11%",
Img: v.Imageurl,
}
act.DateBegin = utils.Str2Time(v.Activitystartdate)
act.DateEnd = utils.Str2Time(v.Activityenddate)
actList = append(actList, act)
}
} else {
err = err2
}
return actList, err
}
func (s *UnionHandler) CreateUnionPosition(ctx *jxcontext.Context, userID string) (sID string, err error) {
return sID, err
}
func (s *UnionHandler) GetUnionMatterList(ctx *jxcontext.Context, vendorCatID, keyword string, page, pageSize, sortType int, listID string) (list *partner.MatterList, err error) {
return nil, err
}
func (s *UnionHandler) GetUnionMatterDetail(ctx *jxcontext.Context, goodsID string) (result *partner.GoodsDetail, err error) {
return nil, err
}
func (s *UnionHandler) GetUnionMatterListRcmmd(ctx *jxcontext.Context, goodsID string, rcmmdType, offset, pageSize int) (result *partner.MatterList, err error) {
return nil, err
}

View File

@@ -0,0 +1,34 @@
package mt
import (
"git.rosy.net.cn/baseapi/platformapi/mtunionapi"
"git.rosy.net.cn/jx-callback/business/jxstore/partner"
"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 UnionHandler struct {
}
var (
unionHandler *UnionHandler
)
func init() {
partner.UnionHandlerMap[model.VendorIDMTWM] = unionHandler
}
func getAPI() (apiobj *mtunionapi.API) {
if configs, err := dao.QueryConfigs(dao.GetDB(), "mtunionCookie", model.ConfigTypeCookie, ""); err == nil {
api.MtUnionAPI.SetCookieWithStr(configs[0].Value)
}
return api.MtUnionAPI
}
func GetAPI() (apiobj *mtunionapi.API) {
if configs, err := dao.QueryConfigs(dao.GetDB(), "mtunionCookie", model.ConfigTypeCookie, ""); err == nil {
api.MtUnionAPI.SetCookieWithStr(configs[0].Value)
}
return api.MtUnionAPI
}

View File

@@ -0,0 +1,136 @@
package mt
import (
"git.rosy.net.cn/baseapi/platformapi/mtunionapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxstore/cms"
"git.rosy.net.cn/jx-callback/business/jxstore/partner"
"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"
"strings"
"time"
)
var (
orderStatusMap = map[int]int{
mtunionapi.MtUnionOrderStatusPay: model.UnionOrderStatusPay,
mtunionapi.MtUnionOrderStatusFinished: model.UnionOrderStatusFinish,
mtunionapi.MtUnionOrderStatusCanceled: model.UnionOrderStatusFail,
}
)
func (s *UnionHandler) ShareUnionLink(ctx *jxcontext.Context, linkType, unionActID int, sID, userID string, resourceType int, goodsID string) (link string, err error) {
if linkType == partner.LinkTypeWeiXinMini {
if qrCode, err := api.MtUnionAPI.MiniCode(unionActID, sID); err == nil {
if qrCode != "" {
return qrCode, err
}
}
return
} else {
return api.MtUnionAPI.GenerateLink(unionActID, linkType, sID)
}
return link, err
}
func (s *UnionHandler) GetUnionActList(ctx *jxcontext.Context, actType int) (actList []*partner.ActivityList, err error) {
if result, err2 := getAPI().ActivityList(actType, 20, 0); err2 == nil {
for _, v := range result {
act := &partner.ActivityList{
ActID: v.ID,
ActName: v.ActName,
ActDes: v.ActDes,
Ratio: v.Ratio,
ActSrc: v.ActSrc,
Img: v.URL,
ActRule: v.ActRule,
}
if v.DateBound != "" {
act.DateBegin = utils.Str2Time(v.DateBound[:strings.LastIndex(v.DateBound, "至")-1])
act.DateEnd = utils.Str2Time(v.DateBound[strings.LastIndex(v.DateBound, "至")+4:])
}
actList = append(actList, act)
}
} else {
err = err2
}
return actList, err
}
func (s *UnionHandler) CreateUnionPosition(ctx *jxcontext.Context, userID string) (sID string, err error) {
return sID, err
}
func (s *UnionHandler) GetUnionMatterList(ctx *jxcontext.Context, vendorCatID, keyword string, page, pageSize, sortType int, listID string) (list *partner.MatterList, err error) {
return nil, err
}
func (s *UnionHandler) GetUnionMatterDetail(ctx *jxcontext.Context, goodsID string) (result *partner.GoodsDetail, err error) {
return nil, err
}
func (s *UnionHandler) GetUnionMatterListRcmmd(ctx *jxcontext.Context, goodsID string, rcmmdType, offset, pageSize int) (result *partner.MatterList, err error) {
return nil, err
}
func OnCallback(call *mtunionapi.CallBackResult) (err error) {
var (
db = dao.GetDB()
)
if order, err2 := api.MtUnionAPI.Rtnotify(call.Orderid, call.Type); order != nil && err2 == nil {
unionOrders, err3 := dao.GetUnionOrdersByIDs(db, []string{order.Order.Orderid}, model.VendorIDPDD)
if err2 != nil {
return err2
}
if err3 != nil {
return err3
}
orderStatus := &model.UnionOrderStatus{
VendorOrderID: order.Order.Orderid,
VendorID: model.VendorIDMTWM,
Status: mtunionOrderStatus2Jx(order.Order.Status),
VendorStatus: utils.Int2Str(order.Order.Status),
OrderStatusAt: time.Unix(utils.Str2Int64(order.Order.Modtime), 0),
}
if len(order.Refund) > 0 {
orderStatus.Comment = "售后完成"
}
//change
jxutils.CallMsgHandler(func() {
if len(unionOrders) > 0 {
if unionOrders[0].Status != orderStatus.Status {
cms.ChangeUnionOrder(unionOrders[0], orderStatus)
}
} else {
//new
unionOrder := &model.UnionOrder{
VendorOrderID: order.Order.Orderid,
VendorID: model.VendorIDMTWM,
Status: mtunionOrderStatus2Jx(order.Order.Status),
PID: order.Order.Sid,
PayPrice: int(jxutils.StandardPrice2Int(utils.Str2Float64(order.Order.Direct))),
//PromotionAmount: int(jxutils.StandardPrice2Int(utils.Str2Float64(order.Coupon[0].Profit))),
GoodsName: order.Order.Smstitle,
GoodsID: order.Order.Dealid,
OrderCreateAt: time.Unix(utils.Str2Int64(order.Order.Paytime), 0),
OrderPayAt: time.Unix(utils.Str2Int64(order.Order.Paytime), 0),
OrderReceiveAt: time.Unix(utils.Str2Int64(order.Order.Modtime), 0),
//OrderSettleAt: time.Unix(utils.Str2Int64(order.Coupon[0].Usetime), 0),
}
if len(order.Coupon) > 0 {
unionOrder.PromotionAmount = int(jxutils.StandardPrice2Int(utils.Str2Float64(order.Coupon[0].Profit)))
unionOrder.OrderSettleAt = time.Unix(utils.Str2Int64(order.Coupon[0].Usetime), 0)
}
cms.NewUnionOrder(unionOrder, orderStatus)
}
}, jxutils.ComposeUniversalOrderID(order.Order.Orderid, model.VendorIDMTWM))
}
return err
}
func mtunionOrderStatus2Jx(status int) (jxstatus int) {
return orderStatusMap[status]
}

View File

@@ -0,0 +1,107 @@
package partner
import (
"time"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
)
var (
UnionHandlerMap map[int]UnionInterface
)
const (
LinkTypeWeiXinMini = 5 //微信小程序二维码
LinTypeH5 = 1 //h5链接
LinTypeDeepLink = 2 //deeplink(唤起)链接
LinTypeInto = 3 //中间页唤起链接
LinTypeWx = 4 //微信小程序唤起路径
ShareTypeOther = 1 //分享给别人
ShareTypeOwn = 2 //自己领
MtUnionJxSID = "000000001"
//排序参数,正数升序,负数倒序
JxSortTypeYJ = 1 //佣金比
JxSortTypeXL = 2 //销量
JxSortTypeJG = 3 //价格
)
type UnionOrderInfo struct {
SID string `json:"sid"`
Profit int64 `json:"profit"` //订单实际返佣金额
VendorID int `json:"vendorID"`
}
type ActivityList struct {
ActID int `json:"actID"`
ActName string `json:"actName"`
ActDes string `json:"actDes"`
Ratio string `json:"ratio"` //返现比?
DateBegin time.Time `json:"dateBegin"`
DateEnd time.Time `json:"dateEnd"`
ActSrc string `json:"actSrc"` //物料?
Img string `json:"img"` //活动图
ActRule string `json:"actRule"`
}
type GoodsDetail struct {
GoodsList
MainImg string `json:"mainImg"`
Imgs string `json:"imgs"`
StoreImg string `json:"storeImg"` //店铺图片
StoreName string `json:"storeName"` //店铺名
LgstTxt string `json:"lgstTxt"` //物流分
DescTxt string `json:"descTxt"` //描述分
ServTxt string `json:"servTxt"` //服务分
}
type GoodsDetail2 struct {
MainImg string `json:"mainImg"`
Imgs string `json:"imgs"`
StoreImg string `json:"storeImg"` //店铺图片
StoreName string `json:"storeName"` //店铺名
Tpwd string `json:"tpwd"` //淘口令 非苹果ios14以上版本的设备即其他ios版本、Android系统等可以用此淘口令正常在复制到手淘打开
//针对苹果ios14及以上版本的苹果设备手淘将按照示例值信息格式读取淘口令(需包含:数字+羊角符+url
//识别规则可能根据ios情况变更)。如需更改淘口令内文案、url等内容请务必先验证更改后的淘口令在手淘可被识别打开
TpwdIOS14 string `json:"tpwdIOS14"`
UrlL string `json:"urlL"` //推广地址长链
UrlS string `json:"urlS"` //推广地址短链
}
type GoodsList struct {
GoodsID string `json:"goodsID"`
GoodsName string `json:"goodsName"`
Img string `json:"img"`
CouponDiscount int `json:"couponDiscount"` //优惠券
CouponRemainQuantity int `json:"couponRemainQuantity"` //优惠券剩余数量
MinNormalPrice int `json:"minNormalPrice"` //最小购买价格
SalesCount string `json:"salesCount"` //销量
PromotionRate int `json:"promotionRate"` //佣金比例,千分比
GoodsDetail *GoodsDetail2 `json:"goodsDetail"` //淘宝用
}
type MatterList struct {
GoodsList []*GoodsList
VendorID int `json:"vendorID"`
ListID string `json:"listID"`
TotalCount int `json:"totalCount"`
}
func init() {
UnionHandlerMap = make(map[int]UnionInterface)
}
type UnionInterface interface {
ShareUnionLink(ctx *jxcontext.Context, linkType, unionActID int, sID, userID string, resourceType int, goodsID string) (link string, err error)
GetUnionActList(ctx *jxcontext.Context, actType int) (result []*ActivityList, err error)
CreateUnionPosition(ctx *jxcontext.Context, userID string) (sID string, err error)
GetUnionMatterList(ctx *jxcontext.Context, vendorCatID, keyword string, page, pageSize, sortType int, listID string) (result *MatterList, err error)
GetUnionMatterDetail(ctx *jxcontext.Context, goodsID string) (result *GoodsDetail, err error)
GetUnionMatterListRcmmd(ctx *jxcontext.Context, goodsID string, rcmmdType, offset, pageSize int) (result *MatterList, err error)
}
func GetHandler(vendorID int) UnionInterface {
return UnionHandlerMap[vendorID]
}

View File

@@ -0,0 +1,27 @@
package pdd
import (
"git.rosy.net.cn/baseapi/platformapi/pddapi"
"git.rosy.net.cn/jx-callback/business/jxstore/partner"
"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 UnionHandler struct {
}
var (
unionHandler *UnionHandler
)
func init() {
partner.UnionHandlerMap[model.VendorIDPDD] = unionHandler
}
func getAPI() (apiobj *pddapi.API) {
if configs, err := dao.QueryConfigs(dao.GetDB(), "pddCookie", model.ConfigTypeCookie, ""); err == nil {
api.PddAPI.SetCookieWithStr(configs[0].Value)
}
return api.PddAPI
}

View File

@@ -0,0 +1,280 @@
package pdd
import (
"fmt"
"git.rosy.net.cn/baseapi/platformapi/pddapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxstore/cms"
"git.rosy.net.cn/jx-callback/business/jxstore/partner"
"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/api"
"strings"
"time"
)
var (
sortTypeMap = map[int]int{
0: 0, //综合排序
partner.JxSortTypeYJ: 1, //按佣金比率升序;
-partner.JxSortTypeYJ: 2, //按佣金比例降序;
partner.JxSortTypeJG: 3, //按价格升序;
-partner.JxSortTypeJG: 4, //按价格降序;
partner.JxSortTypeXL: 5, //按销量升序;
-partner.JxSortTypeXL: 6, //按销量降序;
}
orderStatusMap = map[int]int{
pddapi.OrderStatusPay: model.UnionOrderStatusPay,
pddapi.OrderStatus1: model.UnionOrderStatusPay,
pddapi.OrderStatusTakeOver: model.UnionOrderStatusTakeOver,
pddapi.OrderStatusAuditOver: model.UnionOrderStatusAuditOver,
pddapi.OrderStatusAuditFail: model.UnionOrderStatusFail,
pddapi.OrderStatusEaring: model.UnionOrderStatusFinish,
}
)
func (s *UnionHandler) ShareUnionLink(ctx *jxcontext.Context, linkType, unionActID int, sID, userID string, resourceType int, goodsID string) (link string, err error) {
//传了goodsID表示是商品分享
if goodsID != "" {
authBindFlag, err := api.PddAPI.MemberAuthorityQuery(sID)
if err != nil {
return "", err
}
if result, err := api.PddAPI.GoodsPromotionURLGen(sID, goodsID, !authBindFlag); err == nil {
switch linkType {
case partner.LinTypeH5:
return result.MobileURL, err
case partner.LinTypeWx:
return result.WeAppInfo.PagePath, err
default:
return link, fmt.Errorf("暂不支持此链接类型!")
}
}
} else {
if result, err := api.PddAPI.ResourceURLGen(sID, resourceType); err == nil {
switch linkType {
case partner.LinkTypeWeiXinMini:
return "", err
case partner.LinTypeH5:
return result.SingleURLList.URL, err
case partner.LinTypeWx:
return result.WeAppInfo.PagePath, err
default:
return link, fmt.Errorf("暂不支持此链接类型!")
}
}
}
return link, err
}
func (s *UnionHandler) GetUnionActList(ctx *jxcontext.Context, actType int) (actList []*partner.ActivityList, err error) {
if result, err2 := getAPI().ActivityOperationList(); err2 == nil {
for _, v := range result {
act := &partner.ActivityList{
ActID: v.ID,
ActName: v.Name,
ActDes: v.Description,
Ratio: "未知",
ActSrc: v.Fileurl,
Img: v.Bannerimage,
DateBegin: utils.Str2Time(v.Starttime),
DateEnd: utils.Str2Time(v.Endtime),
}
actList = append(actList, act)
}
}
return actList, err
}
func (s *UnionHandler) CreateUnionPosition(ctx *jxcontext.Context, userID string) (sID string, err error) {
if sID, err = api.PddAPI.GoodsOPidGenerate(userID); err != nil {
return "", err
}
return sID, err
}
func jxSortType2PddSortType(jxSortType int) (sortType int) {
return sortTypeMap[jxSortType]
}
func (s *UnionHandler) GetUnionMatterList(ctx *jxcontext.Context, vendorCatID, keyword string, page, pageSize, sortType int, listID string) (list *partner.MatterList, err error) {
var (
goodsList []*partner.GoodsList
)
list = &partner.MatterList{}
params := &pddapi.GoodsSearchParam{
CatID: utils.Str2Int(vendorCatID),
Keyword: keyword,
Page: page,
PageSize: pageSize,
SortType: jxSortType2PddSortType(sortType),
ListID: listID,
}
//-1表示是拼多多的精选
if vendorCatID == "-1" {
params.ActivityTags = []int{pddapi.GoodsActTagBYBT, pddapi.GoodsActTagJXBK, pddapi.GoodsActTagMS, pddapi.GoodsActTagPPGY, pddapi.GoodsActTagPPHB, pddapi.GoodsActTagQWBT, pddapi.GoodsActTagTZTJ}
}
if goods, err2 := api.PddAPI.GoodsSearch(params); err2 != nil {
return nil, err2
} else {
list.ListID = goods.ListID
list.TotalCount = goods.TotalCount
list.VendorID = model.VendorIDPDD
for _, v := range goods.GoodsList {
good := &partner.GoodsList{
GoodsID: v.GoodsSign,
GoodsName: v.GoodsName,
Img: v.GoodsThumbnailURL,
CouponDiscount: v.CouponDiscount,
CouponRemainQuantity: v.CouponRemainQuantity,
MinNormalPrice: v.MinNormalPrice,
SalesCount: v.SalesTip,
PromotionRate: v.PromotionRate,
}
goodsList = append(goodsList, good)
}
list.GoodsList = goodsList
}
return list, err
}
func (s *UnionHandler) GetUnionMatterDetail(ctx *jxcontext.Context, goodsID string) (result *partner.GoodsDetail, err error) {
result = &partner.GoodsDetail{}
if goods, err2 := api.PddAPI.GoodsDetail(goodsID); err2 != nil {
return nil, err2
} else {
result.GoodsID = goods.GoodsSign
result.GoodsName = goods.GoodsName
result.Img = goods.GoodsThumbnailURL
result.CouponDiscount = goods.CouponDiscount
result.MinNormalPrice = goods.MinNormalPrice
result.CouponRemainQuantity = goods.CouponRemainQuantity
result.SalesCount = goods.SalesTip
result.Imgs = strings.Join(goods.GoodsGalleryUrls, ",")
result.MainImg = goods.GoodsImageURL
result.StoreImg = goods.MallImgURL
result.StoreName = goods.MallName
result.LgstTxt = goods.LgstTxt
result.DescTxt = goods.DescTxt
result.ServTxt = goods.ServTxt
result.PromotionRate = goods.PromotionRate
}
return result, err
}
func (s *UnionHandler) GetUnionMatterListRcmmd(ctx *jxcontext.Context, goodsID string, rcmmdType, offset, pageSize int) (list *partner.MatterList, err error) {
var (
goodsList []*partner.GoodsList
)
list = &partner.MatterList{}
if goods, err2 := api.PddAPI.GoodsRecommendGet(goodsID, rcmmdType, offset, pageSize); err2 != nil {
return nil, err2
} else {
list.ListID = goods.ListID
list.TotalCount = goods.Total
list.VendorID = model.VendorIDPDD
for _, v := range goods.List {
good := &partner.GoodsList{
GoodsID: v.GoodsSign,
GoodsName: v.GoodsName,
Img: v.GoodsThumbnailURL,
CouponDiscount: v.CouponDiscount,
CouponRemainQuantity: v.CouponRemainQuantity,
MinNormalPrice: v.MinNormalPrice,
SalesCount: v.SalesTip,
PromotionRate: v.PromotionRate,
}
goodsList = append(goodsList, good)
}
list.GoodsList = goodsList
}
return list, err
}
func GetUnionOrders() {
var (
page = 1
pageSize = 50
db = dao.GetDB()
orderIDs []string
unionOrderIDsMap map[string]*model.UnionOrder
)
orders, err := api.PddAPI.OrderListIncrementGet(time.Now().Add(-time.Minute*5).Unix(), time.Now().Unix(), page, pageSize)
if err != nil {
return
}
for _, v := range orders {
orderIDs = append(orderIDs, v.OrderSn)
}
unionOrders, err := dao.GetUnionOrdersByIDs(db, orderIDs, model.VendorIDPDD)
if err != nil {
return
}
unionOrderIDsMap = make(map[string]*model.UnionOrder)
for _, v := range unionOrders {
unionOrderIDsMap[v.VendorOrderID] = v
}
task := tasksch.NewParallelTask("GetUnionOrders1", tasksch.NewParallelConfig().SetIsContinueWhenError(true), jxcontext.AdminCtx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
order := batchItemList[0].(*pddapi.OrderListIncrementGetResult)
detail, err := api.PddAPI.OrderDetailGet(order.OrderSn)
if err != nil {
return
}
orderStatus := &model.UnionOrderStatus{
VendorOrderID: detail.OrderSn,
VendorID: model.VendorIDPDD,
Status: pddOrderStatus2Jx(detail.OrderStatus),
VendorStatus: utils.Int2Str(detail.OrderStatus),
OrderStatusAt: time.Unix(int64(detail.OrderModifyAt), 0),
}
if detail.ReturnStatus == 1 {
orderStatus.Comment = "售后中"
} else if detail.ReturnStatus == 2 {
orderStatus.Comment = "售后完成"
orderStatus.Status = model.UnionOrderStatusFail
}
//change
jxutils.CallMsgHandler(func() {
globals.SugarLogger.Debugf("GetUnionOrders pdd, orderstatus: %v", utils.Format4Output(orderStatus, true))
if unionOrderIDsMap[order.OrderSn] != nil {
globals.SugarLogger.Debugf("GetUnionOrders pdd, unionorders: %v", utils.Format4Output(unionOrderIDsMap[order.OrderSn], true))
if unionOrderIDsMap[order.OrderSn].Status != orderStatus.Status {
cms.ChangeUnionOrder(unionOrderIDsMap[order.OrderSn], orderStatus)
}
} else {
//new
unionOrder := &model.UnionOrder{
VendorOrderID: detail.OrderSn,
VendorID: model.VendorIDPDD,
Status: pddOrderStatus2Jx(detail.OrderStatus),
PID: detail.Pid,
PayPrice: detail.OrderAmount,
PromotionAmount: detail.PromotionAmount,
GoodsName: detail.GoodsName,
GoodsID: detail.GoodsSign,
GoodsImg: detail.GoodsThumbnailURL,
OrderCreateAt: time.Unix(int64(order.OrderCreateTime), 0),
OrderPayAt: time.Unix(int64(order.OrderPayTime), 0),
OrderReceiveAt: time.Unix(int64(order.OrderReceiveTime), 0),
OrderSettleAt: time.Unix(int64(order.OrderSettleTime), 0),
Comment: order.FailReason,
}
cms.NewUnionOrder(unionOrder, orderStatus)
}
}, jxutils.ComposeUniversalOrderID(order.OrderSn, model.VendorIDPDD))
return retVal, err
}, orders)
tasksch.HandleTask(task, nil, false).Run()
task.GetID()
}
func pddOrderStatus2Jx(status int) (jxstatus int) {
return orderStatusMap[status]
}

View File

@@ -0,0 +1,27 @@
package taobao
import (
"git.rosy.net.cn/baseapi/platformapi/tbunionapi"
"git.rosy.net.cn/jx-callback/business/jxstore/partner"
"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 UnionHandler struct {
}
var (
unionHandler *UnionHandler
)
func init() {
partner.UnionHandlerMap[model.VendorIDTB] = unionHandler
}
func getAPI() (apiobj *tbunionapi.API) {
if configs, err := dao.QueryConfigs(dao.GetDB(), "tbunionCookie", model.ConfigTypeCookie, ""); err == nil {
api.TbUnionAPI.SetCookieWithStr(configs[0].Value)
}
return api.TbUnionAPI
}

View File

@@ -0,0 +1,189 @@
package taobao
import (
"fmt"
"git.rosy.net.cn/baseapi/platformapi/tbunionapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxstore/partner"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/globals/api"
"strings"
)
var (
sortTypeMap = map[int]string{
0: "", //综合排序
partner.JxSortTypeYJ: "tk_total_commi_asc", //按佣金比率升序;
-partner.JxSortTypeYJ: "tk_total_commi_des", //按佣金比例降序;
partner.JxSortTypeJG: "price_asc", //按价格升序;
-partner.JxSortTypeJG: "price_des", //按价格降序;
partner.JxSortTypeXL: "total_sales_asc", //按销量升序;
-partner.JxSortTypeXL: "total_sales_des", //按销量降序;
}
)
func (s *UnionHandler) ShareUnionLink(ctx *jxcontext.Context, linkType, unionActID int, sID, userID string, resourceType int, goodsID string) (link string, err error) {
if result, err2 := api.TbUnionAPI.ActivityInfoGet(userID, utils.Int2Str(unionActID), utils.Str2Int64(sID)); err2 == nil {
switch linkType {
case partner.LinkTypeWeiXinMini:
return result.Data.WxQrcodeURL, err
case partner.LinTypeH5:
return result.Data.ClickURL, err
case partner.LinTypeWx:
return result.Data.WxMiniprogramPath, err
default:
return link, fmt.Errorf("暂不支持此链接类型!")
}
}
return link, err
}
func (s *UnionHandler) GetUnionActList(ctx *jxcontext.Context, actType int) (actList []*partner.ActivityList, err error) {
if result, err2 := getAPI().GatewayUnionpub(); err2 == nil {
for _, v := range result {
act := &partner.ActivityList{
ActID: utils.Str2Int(v.Pageid),
ActName: v.Pagename,
ActDes: v.Eventenname,
Ratio: "6%",
ActSrc: v.Pageurl,
Img: v.Pagepicturl,
DateBegin: utils.Str2Time(v.Pagestarttime),
DateEnd: utils.Str2Time(v.Pageendtime),
}
actList = append(actList, act)
}
}
return actList, err
}
func (s *UnionHandler) CreateUnionPosition(ctx *jxcontext.Context, userID string) (sID string, err error) {
return sID, err
}
func (s *UnionHandler) GetUnionMatterList(ctx *jxcontext.Context, vendorCatID, keyword string, page, pageSize, sortType int, listID string) (list *partner.MatterList, err error) {
list = &partner.MatterList{
VendorID: model.VendorIDTB,
}
var goodsList []*partner.GoodsList
//传了keyword就是物料搜索
//没传就是物料精选。。
if keyword != "" {
params := &tbunionapi.MaterialOptionalParam{
Q: keyword,
AdzoneID: tbunionapi.JxAdzoneID,
PageNo: page,
PageSize: pageSize,
}
if sortType != 0 {
params.Sort = jxSortType2TbunionSortType(sortType)
}
if materResults, err := api.TbUnionAPI.MaterialOptional(params); err == nil {
list.TotalCount = materResults.TotalResults
for _, v := range materResults.ResultList {
good := &partner.GoodsList{
GoodsID: utils.Int64ToStr(v.ItemID),
GoodsName: v.Title,
Img: v.PictURL,
CouponDiscount: utils.Str2Int(v.CouponAmount),
CouponRemainQuantity: v.CouponRemainCount,
MinNormalPrice: utils.Str2Int(v.ReservePrice),
SalesCount: utils.Int2Str(v.Volume),
PromotionRate: utils.Str2Int(v.CommissionRate),
}
good.GoodsDetail.MainImg = v.WhiteImage
good.GoodsDetail.StoreName = v.ShopTitle
good.GoodsDetail.Imgs = strings.Join(v.SmallImages, ",")
good.GoodsDetail.UrlL = v.CouponShareURL
if urlS, err2 := api.TbUnionAPI.SpreadGet(v.CouponShareURL); err2 == nil {
good.GoodsDetail.UrlS = urlS
}
if tpwdCreateResult, err3 := api.TbUnionAPI.TpwdCreate(good.GoodsDetail.UrlL); err3 == nil {
good.GoodsDetail.Tpwd = tpwdCreateResult.PasswordSimple
good.GoodsDetail.TpwdIOS14 = tpwdCreateResult.Model
}
goodsList = append(goodsList, good)
}
list.GoodsList = goodsList
}
} else {
if materResults, err := api.TbUnionAPI.OptimusMaterial(0, utils.Str2Int(vendorCatID), tbunionapi.JxAdzoneID, page, pageSize); err == nil {
for _, v := range materResults {
good := &partner.GoodsList{
GoodsID: utils.Int64ToStr(v.ItemID),
GoodsName: v.Title,
Img: v.PictURL,
CouponDiscount: v.CouponAmount,
CouponRemainQuantity: v.CouponRemainCount,
MinNormalPrice: utils.Str2Int(v.ReservePrice),
SalesCount: utils.Int2Str(v.Volume),
PromotionRate: utils.Str2Int(v.CommissionRate),
}
goodsDetail := &partner.GoodsDetail2{
MainImg: v.WhiteImage,
StoreName: v.ShopTitle,
Imgs: strings.Join(v.SmallImages, ","),
UrlL: v.CouponShareURL,
}
if urlS, err2 := api.TbUnionAPI.SpreadGet("https:" + v.CouponShareURL); err2 == nil {
goodsDetail.UrlS = urlS
}
if tpwdCreateResult, err3 := api.TbUnionAPI.TpwdCreate("https:" + goodsDetail.UrlL); err3 == nil {
goodsDetail.Tpwd = tpwdCreateResult.PasswordSimple
goodsDetail.TpwdIOS14 = tpwdCreateResult.Model
}
good.GoodsDetail = goodsDetail
goodsList = append(goodsList, good)
}
list.GoodsList = goodsList
}
}
return list, err
}
func (s *UnionHandler) GetUnionMatterDetail(ctx *jxcontext.Context, goodsID string) (result *partner.GoodsDetail, err error) {
return nil, err
}
func (s *UnionHandler) GetUnionMatterListRcmmd(ctx *jxcontext.Context, goodsID string, rcmmdType, offset, pageSize int) (list *partner.MatterList, err error) {
list = &partner.MatterList{
VendorID: model.VendorIDTB,
}
var goodsList []*partner.GoodsList
if materResults, err := api.TbUnionAPI.OptimusMaterial(utils.Str2Int(goodsID), 13256, tbunionapi.JxAdzoneID, offset, pageSize); err == nil {
for _, v := range materResults {
good := &partner.GoodsList{
GoodsID: utils.Int64ToStr(v.ItemID),
GoodsName: v.Title,
Img: v.PictURL,
CouponDiscount: v.CouponAmount,
CouponRemainQuantity: v.CouponRemainCount,
MinNormalPrice: utils.Str2Int(v.ReservePrice),
SalesCount: utils.Int2Str(v.Volume),
PromotionRate: utils.Str2Int(v.CommissionRate),
}
goodsDetail := &partner.GoodsDetail2{
MainImg: v.WhiteImage,
StoreName: v.ShopTitle,
Imgs: strings.Join(v.SmallImages, ","),
UrlL: v.CouponShareURL,
}
if urlS, err2 := api.TbUnionAPI.SpreadGet("https:" + v.CouponShareURL); err2 == nil {
goodsDetail.UrlS = urlS
}
if tpwdCreateResult, err3 := api.TbUnionAPI.TpwdCreate("https:" + goodsDetail.UrlL); err3 == nil {
goodsDetail.Tpwd = tpwdCreateResult.PasswordSimple
goodsDetail.TpwdIOS14 = tpwdCreateResult.Model
}
good.GoodsDetail = goodsDetail
goodsList = append(goodsList, good)
}
list.GoodsList = goodsList
}
return list, err
}
func jxSortType2TbunionSortType(sort int) (tbsort string) {
return sortTypeMap[sort]
}

View File

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

File diff suppressed because it is too large Load Diff

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -28,7 +28,7 @@ func ListConfig(key string) (configList []*legacymodel.Config, err error) {
`
sqlParams := []interface{}{}
if key != "" {
sql += " WHERE thirdparty = ?"
sql += " WHERE thirdparty = ?"
sqlParams = append(sqlParams, key)
}
db := dao.GetDB()

View File

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

View File

@@ -1,32 +1,25 @@
package datares
import (
"fmt"
"testing"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/globals/api2"
"git.rosy.net.cn/jx-callback/globals/testinit"
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/ebai"
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/jd"
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/mtwm"
)
func init() {
testinit.Init()
api2.Init()
}
func TestGetQiniuUploadToken(t *testing.T) {
token, err := GetQiniuUploadToken(jxcontext.AdminCtx, "", "")
if err != nil {
t.Fatal(err)
}
fmt.Print(token)
}
//func TestGetQiniuUploadToken(t *testing.T) {
// token, err := GetQiniuUploadToken(jxcontext.AdminCtx, "", "")
// if err != nil {
// t.Fatal(err)
// }
// fmt.Print(token)
//}
func TestGetDataResource(t *testing.T) {
dataRes, err := GetDataResource(jxcontext.AdminCtx, "1D3E4A8259F359FB4CF47D541843950D")

View File

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

View File

@@ -25,6 +25,8 @@ type Context struct {
const (
MaxUserNameLen = 30
RsmDefultToken = "rushSkyMonkeyToken_20201203"
)
var (
@@ -74,6 +76,8 @@ func New(notUsed interface{}, token string, w http.ResponseWriter, r *http.Reque
if err == model.ErrTokenIsInvalid {
if !globals.IsProductEnv() {
err = nil
} else if token == RsmDefultToken {
err = nil
} else {
errCode = model.ErrCodeTokenIsInvalid
}

View File

@@ -7,11 +7,13 @@ import (
"crypto/md5"
"encoding/base64"
"fmt"
"golang.org/x/text/encoding/simplifiedchinese"
"golang.org/x/text/transform"
"io/ioutil"
"math"
"math/rand"
"regexp"
"sort"
"strconv"
"strings"
"time"
@@ -42,36 +44,14 @@ var (
model.VendorIDEBAI: []string{
"image-star.elemecdn.com",
},
model.VendorIDYB: []string{
"pospalstoreimg.area27.pospal.cn",
},
}
)
const fileExt = ".xlsx"
type OrderSkuList []*model.OrderSku
func (l OrderSkuList) Len() int {
return len(l)
}
// Less reports whether the element with
// index i should sort before the element with index j.
func (l OrderSkuList) Less(i, j int) bool {
return l[i].SalePrice < l[j].SalePrice
}
// Swap swaps the elements with indexes i and j.
func (l OrderSkuList) Swap(i, j int) {
tmp := l[i]
l[i] = l[j]
l[j] = tmp
}
func init() {
rand.Seed(time.Now().Unix())
routinePool = routinepool.New(2000, 2000)
routinePool = routinepool.New(1000, 1000)
// Go regex does not support lookarounds.
// https://stackoverflow.com/questions/38933898/error-parsing-regexp-invalid-or-unsupported-perl-syntax
@@ -80,30 +60,6 @@ func init() {
orderNoBeginTimestamp = utils.Str2Time("2010-01-01 00:00:00").Unix()
}
func getJxStoreIDFromOrder(order *model.GoodsOrder) (retVal int) {
if order.JxStoreID != 0 {
return order.JxStoreID
}
return order.StoreID
}
// 此函数得到的是order的销售门店京西ID与GetJxStoreIDFromOrder的区别是order.StoreID的解释不同参考其它相关资料
func GetSaleStoreIDFromOrder(order *model.GoodsOrder) (retVal int) {
return getJxStoreIDFromOrder(order)
}
// 此函数得到的是order的商品的展示门店京西ID与GetJxStoreIDFromOrder的区别是order.StoreID的解释不同参考其它相关资料
func GetShowStoreIDFromOrder(order *model.GoodsOrder) (retVal int) {
return getJxStoreIDFromOrder(order)
}
func GetSkuIDFromOrderSku(sku *model.OrderSku) (skuID int) {
if sku.JxSkuID > 0 {
return sku.JxSkuID
}
return sku.SkuID
}
func GetSaleStoreIDFromAfsOrder(order *model.AfsOrder) (retVal int) {
if order.JxStoreID > 0 {
return order.JxStoreID
@@ -135,46 +91,60 @@ func SplitUniversalOrderID(universalOrderID string) (orderID string, vendorID in
func GetPossibleVendorIDFromVendorOrderID(vendorOrderID string) (vendorID int) {
vendorID = model.VendorIDUnknown
//if vendorOrderIDInt64 := utils.Str2Int64WithDefault(vendorOrderID, 0); vendorOrderIDInt64 > 0 {
orderIDLen := len(vendorOrderID)
globals.SugarLogger.Debugf("GetPossibleVendorIDFromVendorOrderID, orderIDLen: %v", orderIDLen)
// 5287873015048 13 wsc
// 15380342248732 14 old ebai order
// 800402581000221 15,16 jd order
// 33437032333978492 17 mtwm order
// 3022716176275221584 19 elm order, new ebai order
if vendorOrderIDInt64 := utils.Str2Int64WithDefault(vendorOrderID, 0); vendorOrderIDInt64 > 0 {
orderIDLen := len(vendorOrderID)
// 5287873015048 13 wsc
// 15380342248732 14 old ebai order
// 800402581000221 15,16 jd order
// 33437032333978492 17 mtwm order
// 3022716176275221584 19 elm order, new ebai order
// 京东到家从2020年开始订单号的长度都会在现有基础上加一位订单号的前两位取的是当年的最后两位数2020取的20以适应业务的发展。
// 改造点:
// 1、订单号位数变化由原有15位数增加1位数调整为16位数对接商家需检查是否有对订单号位数做长度校验。
// 2、第一位数字发生变化由原来9开头调整为当年年份后两位数如2020年订单开头为20
if orderIDLen == len("925265130002541") || orderIDLen == len("1925265130002541") {
vendorID = model.VendorIDJD
} else if orderIDLen == len("3022716176275221584") {
// vendorID = model.VendorIDELM
vendorID = model.VendorIDEBAI // 饿百零售开放平台订单接口中订单ID“order_id”字段长度将调整为19位和饿了么订单ID“eleme_order_id”字段格式保持一致。
} else if orderIDLen == len("15380342248732") {
if vendorOrderID[:2] == "88" {
// 京东到家从2020年开始订单号的长度都会在现有基础上加一位订单号的前两位取的是当年的最后两位数2020取的20以适应业务的发展。
// 改造点:
// 1、订单号位数变化由原有15位数增加1位数调整为16位数对接商家需检查是否有对订单号位数做长度校验。
// 2、第一位数字发生变化由原来9开头调整为当年年份后两位数如2020年订单开头为20
if orderIDLen == len("925265130002541") || orderIDLen == len("1925265130002541") {
vendorID = model.VendorIDJD
} else if orderIDLen == len("3022716176275221584") {
// vendorID = model.VendorIDELM
vendorID = model.VendorIDEBAI // 饿百零售开放平台订单接口中订单ID“order_id”字段长度将调整为19位和饿了么订单ID“eleme_order_id”字段格式保持一致。
} else if orderIDLen == len("15380342248732") {
if vendorOrderID[:2] == "88" {
vendorID = model.VendorIDJX
} else {
vendorID = model.VendorIDEBAI
}
} else if orderIDLen == len("33437032333978492") {
vendorID = model.VendorIDMTWM
} else if orderIDLen == len("1000004390") {
vendorID = model.VendorIDJX
} else {
vendorID = model.VendorIDEBAI
} else if orderIDLen == len("124557362562000001") || orderIDLen == len("13153183146800000100") {
vendorID = model.VendorIDJDShop
}
} else if orderIDLen == len("33437032333978492") || orderIDLen == len("116379390766579767") {
vendorID = model.VendorIDMTWM
} else if orderIDLen == len("5287873015048") {
vendorID = model.VendorIDWSC
} else if orderIDLen == len("1000004390") {
vendorID = model.VendorIDJX
} else if orderIDLen == len("18100216009800000001") || orderIDLen == len("191075245758000000039") {
vendorID = model.VendorIDJDShop
}
//} else {
// globals.SugarLogger.Debugf("GetPossibleVendorIDFromVendorOrderID, 2: %v", vendorOrderID)
//}
return vendorID
}
func GenRand6() (num int) {
return utils.Str2Int(fmt.Sprintf("%06v", rand.New(rand.NewSource(time.Now().UnixNano())).Int31n(1000000)))
}
func GenOrderNo() (orderNo int64) {
var prefix = utils.Str2Int64(time.Now().Format("20060102"))
const randPartNum = 1000
orderNo = time.Now().Unix() - orderNoBeginTimestamp
orderNo = orderNo * randPartNum
md5Bytes := md5.Sum([]byte(utils.GetUUID()))
randPart := 0
for k, v := range md5Bytes {
randPart += int(v) << ((k % 3) * 8)
}
orderNo += int64(randPart % randPartNum)
orderNo += int64(math.Pow10(int(math.Log10(float64(orderNo)))+1)) * prefix
return orderNo
}
func GenJobOrderNo() (orderNo int64) {
const prefix = 88
const randPartNum = 1000
orderNo = time.Now().Unix() - orderNoBeginTimestamp
@@ -189,6 +159,35 @@ func GenOrderNo() (orderNo int64) {
return orderNo
}
func GenBillID() (billID int64) {
const prefix = 66
const randPartNum = 100
billID = time.Now().Unix() - orderNoBeginTimestamp
billID = billID * randPartNum
md5Bytes := md5.Sum([]byte(utils.GetUUID()))
randPart := 0
for k, v := range md5Bytes {
randPart += int(v) << ((k % 3) * 8)
}
billID += int64(randPart % randPartNum)
billID += int64(math.Pow10(int(math.Log10(float64(billID)))+1)) * prefix
return billID
}
func GenGroupID() (groupID int64) {
const randPartNum = 100
groupID = time.Now().Unix() - orderNoBeginTimestamp
groupID = groupID * randPartNum
md5Bytes := md5.Sum([]byte(utils.GetUUID()))
randPart := 0
for k, v := range md5Bytes {
randPart += int(v) << ((k % 3) * 8)
}
groupID += int64(randPart % randPartNum)
groupID += int64(math.Pow10(int(math.Log10(float64(groupID))) + 1))
return groupID
}
func GenAfsOrderNo() (orderNo int64) {
const prefix = 80
const randPartNum = 100
@@ -222,19 +221,6 @@ func GetPossibleVendorIDFromAfsOrderID(afsOrderID string) (vendorID int) {
func ComposeUniversalOrderID(orderID string, vendorID int) string {
// return fmt.Sprintf("%s|%d", orderID, vendorID)
return orderID // 当前用长度就能区分先不加上vendorID
// return orderID + utils.Int64ToStr(time.Now().Unix())
}
func GetUniversalOrderIDFromWaybill(bill *model.Waybill) string {
return ComposeUniversalOrderID(bill.VendorOrderID, bill.OrderVendorID)
}
func GetUniversalOrderIDFromOrder(order *model.GoodsOrder) string {
return ComposeUniversalOrderID(order.VendorOrderID, order.VendorID)
}
func GetUniversalOrderIDFromOrderStatus(status *model.OrderStatus) string {
return ComposeUniversalOrderID(status.VendorOrderID, status.VendorID)
}
// distance单位为米
@@ -271,26 +257,6 @@ func WalkingDistance(lng1, lat1, lng2, lat2 float64) (distance float64) {
return distance
}
//经纬度坐标转换到平面坐标
func MillierConvertion(lat float64, lon float64) [2]float64 {
var L, H, W, temp, mill, x, y float64
L = 6371.393 * math.Pi * 2 //地球周长
W = L // 平面展开后x轴等于周长
H = L / 2 // y轴约等于周长一半
mill = 2.3 // 米勒投影中的一个常数范围大约在正负2.3之间
temp = math.Pi
x = lon * temp / 180 // 将经度从度数转换为弧度
y = lat * temp / 180 // 将纬度从度数转换为弧度
y = 1.25 * math.Log(math.Tan(0.25*temp+0.4*y)) // 米勒投影的转换
// 弧度转为实际距离
x = (W / 2) + (W/(2*math.Pi))*x
y = (H / 2) - (H/(2*mill))*y
x = utils.Str2Float64(fmt.Sprintf("%.2f", x))
y = utils.Str2Float64(fmt.Sprintf("%.2f", y))
var result = [2]float64{x, y}
return result
}
func StandardCoordinate2Int(value float64) int {
return int(math.Round(value * 1000000))
}
@@ -420,7 +386,7 @@ func ComposeSkuNameOriginal(prefix, name, comment, unit string, spec_quality flo
return skuName
}
func ComposeSkuNameForMTWM(prefix, name, comment, unit string, spec_quality float32, spec_unit string, maxLen int) (skuName string) {
func ComposeSkuNameForJds(prefix, name, comment, unit string, spec_quality float32, spec_unit string, maxLen int) (skuName string) {
strBuilder := &strings.Builder{}
if prefix != "" {
strBuilder.WriteString("[")
@@ -429,16 +395,15 @@ func ComposeSkuNameForMTWM(prefix, name, comment, unit string, spec_quality floa
}
skuName += name
strBuilder.WriteString(name)
strBuilder.WriteString("")
if comment != "" {
strBuilder.WriteString(" ")
strBuilder.WriteString(comment)
}
if unit == "份" {
strBuilder.WriteString("约")
}
if unit != "" {
strBuilder.WriteString(ComposeSkuSpec(spec_quality, spec_unit))
strBuilder.WriteString("/")
strBuilder.WriteString(unit)
}
if comment != "" {
strBuilder.WriteString("(")
strBuilder.WriteString(comment)
strBuilder.WriteString(")")
}
skuName = strBuilder.String()
if maxLen > 0 {
@@ -457,12 +422,10 @@ func ComposeSkuName(prefix, name, comment, unit string, spec_quality float32, sp
return skuName
}
func ComposeSkuNameSync(prefix, name, comment, unit string, spec_quality float32, spec_unit string, maxLen int, exPrefix string, exPrefixBegin, exPrefixEnd *time.Time, isEx bool) (skuName string) {
func ComposeSkuNameSync(prefix, name, comment, unit string, spec_quality float32, spec_unit string, maxLen int, exPrefix string, exPrefixBegin, exPrefixEnd *time.Time) (skuName string) {
if exPrefix != "" && exPrefixBegin != nil && exPrefixEnd != nil {
if utils.Time2Date(time.Now().Add(6*time.Hour)).Sub(*exPrefixBegin) >= 0 && utils.Time2Date(time.Now()).Sub(*exPrefixEnd) <= 0 {
if isEx {
skuName = exPrefix
}
skuName = exPrefix
}
if utils.Time2Date(time.Now().Add(6*time.Hour)).Sub(*exPrefixEnd) > 0 {
skuName = ""
@@ -472,18 +435,16 @@ func ComposeSkuNameSync(prefix, name, comment, unit string, spec_quality float32
return skuName
}
func ComposeSkuNameSync2(prefix, name, comment, unit string, spec_quality float32, spec_unit string, maxLen int, exPrefix string, exPrefixBegin, exPrefixEnd *time.Time, isEx bool) (skuName string) {
func ComposeSkuNameSync2(prefix, name, comment, unit string, spec_quality float32, spec_unit string, maxLen int, exPrefix string, exPrefixBegin, exPrefixEnd *time.Time) (skuName string) {
if exPrefix != "" && exPrefixBegin != nil && exPrefixEnd != nil {
if utils.Time2Date(time.Now().Add(6*time.Hour)).Sub(*exPrefixBegin) >= 0 && utils.Time2Date(time.Now()).Sub(*exPrefixEnd) <= 0 {
if isEx {
skuName = exPrefix
}
skuName = exPrefix
}
if utils.Time2Date(time.Now().Add(6*time.Hour)).Sub(*exPrefixEnd) > 0 {
skuName = ""
}
}
skuName += ComposeSkuNameForMTWM(prefix, name, comment, unit, spec_quality, spec_unit, maxLen)
skuName += ComposeSkuNameForJds(prefix, name, comment, unit, spec_quality, spec_unit, maxLen)
return skuName
}
@@ -584,7 +545,7 @@ func MakeValidationMapFromSlice(validValues []string, flag int) map[string]int {
}
func ComposeQiniuResURL(key string) string {
return "http://image.jxc4.com/" + key
return "https://image.jxc4.com/" + key
}
func IsLegalMobileNumber(num int64) bool {
@@ -624,58 +585,6 @@ func Strings2Objs(strAndObjAddPairs ...interface{}) (err error) {
return nil
}
func RefreshOrderSkuRelated(order *model.GoodsOrder) *model.GoodsOrder {
order.SkuCount = 0
order.GoodsCount = 0
order.SalePrice = 0
order.VendorPrice = 0
order.ShopPrice = 0
order.Weight = 0
order.EarningPrice = 0
for _, sku := range order.Skus {
if sku.SkuID > math.MaxInt32 {
sku.SkuID = sku.JxSkuID
}
sku.OrderCreatedAt = order.OrderCreatedAt
sku.VendorID = order.VendorID
sku.VendorOrderID = order.VendorOrderID
order.SkuCount++
order.GoodsCount += sku.Count
order.SalePrice += sku.SalePrice * int64(sku.Count)
order.VendorPrice += sku.VendorPrice * int64(sku.Count)
order.ShopPrice += sku.ShopPrice * int64(sku.Count)
order.EarningPrice += sku.EarningPrice * int64(sku.Count)
order.Weight += sku.Weight * sku.Count
}
return order
}
func RefreshOrderEarningPrice2(order *model.GoodsOrder, payPercentage int) *model.GoodsOrder {
if order.EarningType == model.EarningTypePoints {
// if order.VendorID == model.VendorIDJDShop || order.VendorID == model.VendorIDJX {
// order.NewEarningPrice = order.TotalShopMoney * int64((100 - payPercentage)) / 100
// } else {
order.NewEarningPrice = order.TotalShopMoney * int64((100 - payPercentage/2)) / 100
// }
} else {
order.NewEarningPrice = order.EarningPrice
}
return order
}
func RefreshOrderEarningPrice3(order *model.GoodsOrder, payPercentage int, bill *model.Waybill) *model.GoodsOrder {
if order.EarningType == model.EarningTypePoints {
// if order.VendorID == model.VendorIDJDShop || order.VendorID == model.VendorIDJX {
// order.NewEarningPrice = (order.TotalShopMoney - bill.DesiredFee) * int64((100 - payPercentage)) / 100
// } else {
order.NewEarningPrice = order.TotalShopMoney*int64((100-payPercentage/2))/100 - bill.DesiredFee
// }
} else {
order.NewEarningPrice = order.EarningPrice
}
return order
}
func RefreshAfsOrderSkuRelated(afsOrder *model.AfsOrder) *model.AfsOrder {
afsOrder.SkuUserMoney = 0
afsOrder.PmSkuSubsidyMoney = 0
@@ -689,56 +598,6 @@ func RefreshAfsOrderSkuRelated(afsOrder *model.AfsOrder) *model.AfsOrder {
return afsOrder
}
func RemoveSkuFromOrder(order *model.GoodsOrder, removedSkuList []*model.OrderSku) *model.GoodsOrder {
removedSkuMap := make(map[int]*model.OrderSku)
removedSkuMap2 := make(map[string]*model.OrderSku)
for _, sku := range removedSkuList {
if skuID := GetSkuIDFromOrderSku(sku); skuID > 0 {
if removedSkuMap[skuID] == nil {
removedSkuMap[skuID] = sku
} else {
removedSkuMap[skuID].Count += sku.Count
}
}
if vendorSkuID := sku.VendorSkuID; vendorSkuID != "" {
if removedSkuMap2[vendorSkuID] == nil {
removedSkuMap2[vendorSkuID] = sku
} else {
removedSkuMap2[vendorSkuID].Count += sku.Count
}
}
}
var skuList []*model.OrderSku
sort.Sort(sort.Reverse(OrderSkuList(order.Skus)))
for _, sku := range order.Skus {
var removedSku *model.OrderSku
if skuID := GetSkuIDFromOrderSku(sku); skuID > 0 {
removedSku = removedSkuMap[skuID]
}
if removedSku == nil {
if vendorSkuID := sku.VendorSkuID; vendorSkuID != "" {
removedSku = removedSkuMap2[vendorSkuID]
}
}
copiedSku := *sku
tmp := &copiedSku
if removedSku != nil {
if removedSku.Count >= sku.Count {
tmp = nil
removedSku.Count -= sku.Count
} else {
tmp.Count -= removedSku.Count
removedSku.Count = 0
}
}
if tmp != nil {
skuList = append(skuList, tmp)
}
}
order.Skus = skuList
return RefreshOrderSkuRelated(order)
}
func UploadExportContent(content []byte, key string) (downloadURL string, err error) {
putPolicy := storage.PutPolicy{
Scope: globals.QiniuBucket,
@@ -826,42 +685,15 @@ func OperationTime2Str2(openTime, closeTime int16) (str string) {
return str
}
func OperationTimeStr4VendorStore(v *model.VendorStoreSnapshot) (str string) {
str = fmt.Sprintf("%s", OperationTime2Str2(v.OpenTime1, v.CloseTime1))
if v.OpenTime2 > 0 && v.CloseTime2 > 0 {
str += fmt.Sprintf(",%s", OperationTime2Str2(v.OpenTime2, v.CloseTime2))
}
return str
}
func OperationTime2HourMinuteFormat(time time.Time) (i int16) {
return int16(time.Hour()*100 + time.Minute())
}
// 得到饿百订单的取货码
func GetEbaiOrderGetCode(order *model.GoodsOrder) (getCode string) {
if order.VendorID == model.VendorIDEBAI && len(order.VendorOrderID2) >= 4 {
getCode = order.VendorOrderID2[len(order.VendorOrderID2)-4:]
}
return getCode
}
func WriteFile(fileName string, binData []byte) error {
err := ioutil.WriteFile(fileName, binData, 0666)
return err
}
func GetRealMobile4Order(order *model.GoodsOrder) (mobileNumber string) {
mobileNumber = order.ConsigneeMobile2
if mobileNumber == "" {
mobileNumber = order.ConsigneeMobile
}
if !IsStringLikeMobile(mobileNumber) {
mobileNumber = ""
}
return mobileNumber
}
func GuessDataResourceVendor(resourceURL string) (vendorID int) {
vendorID = -1
for tmpVendorID, urlList := range resourceTypeMap {
@@ -924,30 +756,23 @@ func GetOneEmailFromStr(str string) (email string) {
// 计算一个坐标点距离一个门店的距离单位为米如果不在有效范围内则返回0
func Point2StoreDistance(lng, lat float64, intStoreLng, intStoreLat int, deliveryRangeType int8, deliveryRange string) (distance int) {
storeLng := IntCoordinate2Standard(intStoreLng)
storeLat := IntCoordinate2Standard(intStoreLat)
if deliveryRangeType == model.DeliveryRangeTypeRadius {
maxDistance := int(utils.Str2Int64WithDefault(deliveryRange, 0))
distance = int(EarthDistance(lng, lat, storeLng, storeLat) * 1000)
if distance > maxDistance {
distance = 0
}
} else {
points := CoordinateStr2Points(deliveryRange)
if utils.IsPointInPolygon(lng, lat, points) {
distance = int(EarthDistance(lng, lat, storeLng, storeLat) * 1000)
}
}
// storeLng := IntCoordinate2Standard(intStoreLng)
// storeLat := IntCoordinate2Standard(intStoreLat)
// if deliveryRangeType == model.DeliveryRangeTypeRadius {
// maxDistance := int(utils.Str2Int64WithDefault(deliveryRange, 0))
// distance = int(EarthDistance(lng, lat, storeLng, storeLat) * 1000)
// if distance > maxDistance {
// distance = 0
// }
// } else {
// points := CoordinateStr2Points(deliveryRange)
// if utils.IsPointInPolygon(lng, lat, points) {
// distance = int(EarthDistance(lng, lat, storeLng, storeLat) * 1000)
// }
// }
return distance
}
func TranslateStorePriceType(storePriceType int8) int8 {
if storePriceType == model.StoreChangePriceTypeManagedStore {
storePriceType = model.StoreChangePriceTypeBossDisabled
}
return storePriceType
}
func TranslateSoundSize(vendorID, soundPercentage int) (soundSize string) {
if vendorID == model.VendorIDYiLianYun || vendorID == model.VendorIDFeiE {
if soundPercentage == 0 {
@@ -962,25 +787,6 @@ func TranslateSoundSize(vendorID, soundPercentage int) (soundSize string) {
if soundPercentage > 66 && soundPercentage <= 100 {
soundSize = "3"
}
} else if vendorID == model.VendorIDJxprint {
if soundPercentage == 0 {
soundSize = "0"
}
if soundPercentage > 0 && soundPercentage <= 20 {
soundSize = "1"
}
if soundPercentage > 20 && soundPercentage <= 40 {
soundSize = "2"
}
if soundPercentage > 40 && soundPercentage <= 60 {
soundSize = "3"
}
if soundPercentage > 60 && soundPercentage <= 80 {
soundSize = "4"
}
if soundPercentage > 80 && soundPercentage <= 100 {
soundSize = "5"
}
}
return soundSize
}
@@ -1018,42 +824,27 @@ func PKCS5UnPadding(origData []byte) []byte {
}
//合成水印图
func MixWatermarkImg(imgWatermark, img string, exPrefixBegin, exPrefixEnd *time.Time) (imgMix string) {
if exPrefixBegin != nil && exPrefixEnd != nil {
if utils.Time2Date(time.Now().Add(6*time.Hour)).Sub(*exPrefixBegin) >= 0 && utils.Time2Date(time.Now()).Sub(*exPrefixEnd) <= 0 {
baseURL := base64.URLEncoding.EncodeToString([]byte(imgWatermark))
var imgUrl string
if strings.Contains(img, "?") {
imgUrl = img + "/imageView2/0/q/75|watermark/1/image/" + baseURL + "/dissolve/100/gravity/Center/dx/0/dy/0"
} else {
imgUrl = img + "?imageView2/0/q/75|watermark/1/image/" + baseURL + "/dissolve/100/gravity/Center/dx/0/dy/0"
func MixWatermarkImg(imgWatermark, img, positon string) (imgMix string) {
baseURL := base64.URLEncoding.EncodeToString([]byte(imgWatermark))
var imgUrl string
if strings.Contains(img, "?") {
imgUrl = img + "/imageView2/0/q/75|watermark/1/image/" + baseURL + "/dissolve/100/gravity/" + positon + "/dx/10/dy/10"
} else {
imgUrl = img + "?imageView2/0/q/75|watermark/1/image/" + baseURL + "/dissolve/100/gravity/" + positon + "/dx/10/dy/10"
}
if resBinary, _, err := DownloadFileByURL(imgUrl); err == nil {
if downloadURL, err := UploadExportContent(resBinary, "image/"+utils.Int64ToStr(time.Now().Unix())+img[strings.LastIndex(img, "/")+1:len(img)]); err == nil {
if err == nil {
return downloadURL
}
if resBinary, _, err := DownloadFileByURL(imgUrl); err == nil {
if downloadURL, err := UploadExportContent(resBinary, utils.Int64ToStr(time.Now().Unix())+img[strings.LastIndex(img, "/")+1:len(img)]); err == nil {
if err == nil {
return downloadURL
}
}
}
}
if utils.Time2Date(time.Now().Add(6*time.Hour)).Sub(*exPrefixEnd) > 0 {
return imgMix
}
}
return imgMix
}
func GetDefendPriceIssue() (issue int) {
if time.Now().Hour() >= 22 {
issue = utils.Str2Int(time.Now().AddDate(0, 0, 1).Format("20060102"))
} else {
issue = utils.Str2Int(time.Now().Format("20060102"))
}
return issue
}
func GetLastDefendPriceIssue() (issue int) {
return utils.Str2Int(time.Now().AddDate(0, 0, 1).Format("20060102"))
func GetIssue() (issue int) {
year, month, _ := time.Now().Date()
return year*100 + int(month)
}
//根据一堆坐标求面积
@@ -1086,16 +877,53 @@ func polarTriangleArea(tan1, lng1, tan2, lng2 float64) (s float64) {
return 2 * math.Atan2(t*math.Sin(deltaLng), 1+t*math.Cos(deltaLng))
}
func IntListToStrList(i []int) (s []string) {
for _, v := range i {
s = append(s, utils.Int2Str(v))
func GenRandomString(l int) string {
str := "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
bytes := []byte(str)
result := []byte{}
r := rand.New(rand.NewSource(time.Now().UnixNano()))
for i := 0; i < l; i++ {
result = append(result, bytes[r.Intn(len(bytes))])
}
return s
return string(result)
}
func StrListToIntList(s []string) (i []int) {
for _, v := range s {
i = append(i, utils.Str2Int(v))
}
return i
func GetDayTime() (dayTimeBegin, dayTimeEnd time.Time) {
dayTimeBegin = utils.Str2Time(utils.Time2Str(utils.Time2Date(time.Now())) + " 00:00:00")
dayTimeEnd = dayTimeBegin.AddDate(0, 0, 1)
return dayTimeBegin, dayTimeEnd
}
func GetWeekTime() (weekTimeBegin, weekTimeEnd time.Time) {
offset := int(time.Now().Weekday() - 1)
if offset == -1 {
offset = -6
}
weekTimeBegin = time.Now().AddDate(0, 0, offset)
weekTimeEnd = weekTimeBegin.AddDate(0, 0, 7)
return weekTimeBegin, weekTimeEnd
}
func Utf8ToGbk(str []byte) (b []byte, err error) {
r := transform.NewReader(bytes.NewReader(str), simplifiedchinese.GBK.NewEncoder())
b, err = ioutil.ReadAll(r)
if err != nil {
return
}
return
}
func Hextob(str string) []byte {
slen := len(str)
bHex := make([]byte, len(str)/2)
ii := 0
for i := 0; i < len(str); i = i + 2 {
if slen != 1 {
ss := string(str[i]) + string(str[i+1])
bt, _ := strconv.ParseInt(ss, 16, 32)
bHex[ii] = byte(bt)
ii = ii + 1
slen = slen - 2
}
}
return bHex
}

View File

@@ -6,7 +6,6 @@ import (
"encoding/base64"
"errors"
"fmt"
beego "github.com/astaxie/beego/server/web"
"image"
"image/png"
"io/ioutil"
@@ -217,42 +216,6 @@ func RegularizeSkuQuality(specQuality float32, specUnit string) (g int) {
return int(specQuality)
}
// 计算SKU价格unitPrice为一斤的单价specQuality为质量单位为克
func CaculateSkuPrice(unitPrice int, specQuality float32, specUnit string, skuNameUnit string) int {
if skuNameUnit != model.SpecialUnit {
return unitPrice
}
specQuality2 := RegularizeSkuQuality(specQuality, specUnit)
floatPrice := float64(unitPrice) * float64(specQuality2) / float64(model.SpecialSpecQuality)
// if specQuality2 < 250 {
// floatPrice = floatPrice * 110 / 100
// } else if specQuality2 < 500 {
// floatPrice = floatPrice * 105 / 100
// }
if floatPrice <= 1 {
floatPrice = 1
}
return int(math.Round(floatPrice))
}
// 计算SKU标准价格CaculateSkuPrice的逆过程
func CaculateUnitPrice(skuPrice int, specQuality float32, specUnit string, skuNameUnit string) (unitPrice int) {
if skuNameUnit != model.SpecialUnit {
return skuPrice
}
specQuality2 := RegularizeSkuQuality(specQuality, specUnit)
unitPrice = skuPrice * model.SpecialSpecQuality / specQuality2
// if specQuality2 < 250 {
// unitPrice = unitPrice * 100 / 110
// } else if specQuality2 < 500 {
// unitPrice = unitPrice * 100 / 105
// }
if unitPrice <= 1 {
unitPrice = 1
}
return unitPrice
}
func ConstrainPricePercentage(percentage int) int {
if percentage < model.MinVendorPricePercentage || percentage > model.MaxVendorPricePercentage {
percentage = model.DefVendorPricePercentage
@@ -288,65 +251,6 @@ func CaculateSkuPriceFromVendor(vendorPrice, percentage, priceAdd int) (price in
return price
}
func GetPricePercentage(l model.PricePercentagePack, price int, defPricePercentage int) (pricePercentage, priceAdd int) {
pricePercentage = defPricePercentage
itemLen := len(l)
if itemLen > 0 {
low := 0
high := itemLen - 1
mid := 0
for low <= high {
mid = low + (high-low)/2
if mid < 0 || mid >= itemLen-1 {
break
}
if price >= l[mid].BeginPrice {
if price < l[mid+1].BeginPrice {
break
} else {
low = mid + 1
}
} else {
high = mid - 1
}
}
if mid >= 0 && mid <= itemLen-1 && low <= high {
pricePercentage = l[mid].PricePercentage
priceAdd = l[mid].PriceAdd
}
}
return pricePercentage, priceAdd
}
func GetPricePercentageByVendorPrice(l model.PricePercentagePack, vendorPrice int, defPricePercentage int) (pricePercentage, priceAdd int) {
pricePercentage = defPricePercentage
if len(l) > 0 {
var lastItem *model.PricePercentageItem
for _, v := range l {
if CaculateSkuVendorPrice(v.BeginPrice, v.PricePercentage, v.PriceAdd) > vendorPrice {
break
}
lastItem = v
}
if lastItem != nil {
pricePercentage = lastItem.PricePercentage
priceAdd = lastItem.PriceAdd
}
}
return pricePercentage, priceAdd
}
func CaculatePriceByPricePack(l model.PricePercentagePack, defPricePercentage, price int) (outPrice int) {
pricePercentage, priceAdd := GetPricePercentage(l, price, defPricePercentage)
return CaculateSkuVendorPrice(price, pricePercentage, priceAdd)
}
func CaculateJxPriceByPricePack(l model.PricePercentagePack, defPricePercentage, vendorPrice int) (jxPrice int) {
pricePercentage, priceAdd := GetPricePercentageByVendorPrice(l, vendorPrice, defPricePercentage)
jxPrice = CaculateSkuPriceFromVendor(vendorPrice, pricePercentage, priceAdd)
return jxPrice
}
func ConstrainPayPercentage(payPerCentage int) int {
if payPerCentage <= 50 {
payPerCentage = 70
@@ -354,10 +258,6 @@ func ConstrainPayPercentage(payPerCentage int) int {
return payPerCentage
}
func IsSkuSpecial(specQuality float32, specUnit string) bool {
return int(specQuality) == model.SpecialSpecQuality && (specUnit == model.SpecialSpecUnit || specUnit == model.SpecialSpecUnit2)
}
var lastFakeID int64
var lastFakeIDMutex sync.RWMutex
@@ -441,28 +341,6 @@ func FormatSkuWeight(specQuality float32, specUnit string) int {
return RegularizeSkuQuality(specQuality, specUnit)
}
type SkuList []*model.Sku
func (s SkuList) Len() int {
return len(s)
}
func (s SkuList) Less(i, j int) bool {
if s[i].NameID == s[j].NameID {
if s[i].SpecUnit == s[j].SpecUnit {
return s[i].SpecQuality < s[j].SpecQuality
}
return s[i].SpecUnit < s[j].SpecUnit
}
return s[i].NameID < s[j].NameID
}
func (s SkuList) Swap(i, j int) {
tmp := s[i]
s[i] = s[j]
s[j] = tmp
}
func DownloadFileByURL(fileURL string) (bodyData []byte, fileMD5 string, err error) {
response, err := http.Get(fileURL)
if err == nil {
@@ -504,19 +382,9 @@ func GetVendorName(vendorID int) (vendorName string) {
}
func CaculateSkuEarningPrice(shopPrice, salePrice int64, storePayPercentage int) (earningPrice int64) {
//TODO 2021-07-05 16:50菜市和果园一样取低的
//TODO 2021-07-05 18:48 还是改回来
if beego.BConfig.RunMode == "jxgy" {
earningPrice = salePrice
if salePrice != 0 {
if shopPrice > 0 && shopPrice < earningPrice {
earningPrice = shopPrice
}
}
} else {
if shopPrice == 0 {
earningPrice = salePrice * 70 / 100
} else {
earningPrice = salePrice
if salePrice != 0 {
if shopPrice > 0 && shopPrice < earningPrice {
earningPrice = shopPrice
}
}
@@ -593,3 +461,11 @@ func CalcPolygonAreaAutonavi(points [][2]float64) (area float64) {
d += eee*point[1]*c - k*g2
return 0.5 * math.Abs(d) / float64(1000000)
}
func BuildErr(errs []error) (err error) {
var errStr = strings.Builder{}
for _, v := range errs {
errStr.WriteString(v.Error())
}
return fmt.Errorf(errStr.String())
}

View File

@@ -90,7 +90,6 @@ func TestSplitUniversalOrderID(t *testing.T) {
[]interface{}{
"3022716176275221584",
"3022716176275221584",
model.VendorIDELM,
},
[]interface{}{
"15380342248732",
@@ -105,7 +104,6 @@ func TestSplitUniversalOrderID(t *testing.T) {
[]interface{}{
"5287873015048",
"5287873015048",
model.VendorIDWSC,
},
}
for _, v := range testData {
@@ -151,7 +149,6 @@ func TestGetPossibleVendorIDFromVendorOrderID(t *testing.T) {
},
[]interface{}{
"5287873015048",
model.VendorIDWSC,
},
}
for _, v := range testData {

View File

@@ -4,7 +4,6 @@ import (
"fmt"
"git.rosy.net.cn/jx-callback/business/jxutils/ddmsg"
"git.rosy.net.cn/jx-callback/business/jxutils/weixinmsg"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/baseapi/platformapi/dingdingapi"
@@ -33,7 +32,7 @@ func SendUserMessage(msgType string, user *model.User, title, content string) (e
}
err = ddmsg.SendDDUserMessage(msgType, auth.AuthID, title, content)
} else if auth.Type == weixin.AuthTypeMP && msgType != dingdingapi.MsgTypeMarkdown {
err = weixinmsg.NotifyStoreStatusChanged(auth.AuthID, title, content)
//err = weixinmsg.NotifyStoreStatusChanged(auth.AuthID, title, content)
}
break
}

View File

@@ -1,238 +0,0 @@
package netprinter
import (
"fmt"
"strings"
"time"
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/partner"
"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"
)
const (
testVendorOrderID = "test"
realTestVendorOrderID = "901234567890123"
realTestOrderVendorID = model.VendorIDJD
)
const (
PrinterNotifyUserApplyCancel = 1
PrinterNotifyNewAfsOrder = 2
)
func PrintOrder(ctx *jxcontext.Context, vendorOrderID string, vendorID int) (printResult *partner.PrinterStatus, err error) {
storeID := vendorID
if vendorOrderID == testVendorOrderID {
vendorOrderID = realTestVendorOrderID
vendorID = realTestOrderVendorID
}
order, err := partner.CurOrderManager.LoadOrder(vendorOrderID, vendorID)
if err == nil {
if vendorOrderID == realTestVendorOrderID {
order.StoreID = storeID
order.JxStoreID = storeID
}
printResult, err = PrintOrderByOrder(ctx, order)
}
return printResult, err
}
func PrintOrderByOrder(ctx *jxcontext.Context, order *model.GoodsOrder) (printResult *partner.PrinterStatus, err error) {
return PrintOrderByOrder4Store(ctx, order, jxutils.GetSaleStoreIDFromOrder(order))
}
func getStore4Print(db *dao.DaoDB, storeID int) (store *model.Store, err error) {
for i := 0; i < 3; i++ {
store2 := &model.Store{}
store2.ID = storeID
if err = dao.GetEntity(db, store2); err == nil {
store = store2
if store.LinkStoreID != 0 {
storeID = store.LinkStoreID
} else {
break
}
} else {
break
}
}
if store != nil {
err = nil
}
return store, err
}
func PrintOrderByOrder4Store(ctx *jxcontext.Context, order *model.GoodsOrder, storeID int) (printResult *partner.PrinterStatus, err error) {
globals.SugarLogger.Debugf("PrintOrderByOrder4Store orderID:%s", order.VendorOrderID)
db := dao.GetDB()
store, err := getStore4Print(db, storeID)
if err == nil {
handler, err := GetHandlerFromStore(store)
if err != nil {
return &partner.PrinterStatus{
PrintResult: partner.PrintResultNoPrinter,
}, nil
}
storeDetail, _ := dao.GetStoreDetail(db, storeID, order.VendorID, order.VendorOrgCode)
if storeDetail == nil && order.VendorOrderID == testVendorOrderID {
storeDetail = &dao.StoreDetail{
BrandName: testVendorOrderID,
BrandIsPrint: model.NO,
}
}
printResult, err = handler.PrintOrder(ctx, store, storeDetail, order)
if err == nil {
dao.SetOrderPrintFlag(db, ctx.GetUserName(), order.VendorOrderID, order.VendorID, true)
}
}
if err != nil {
globals.SugarLogger.Infof("PrintOrderByOrder4Store orderID:%s failed with error:%v", order.VendorOrderID, err)
}
return printResult, err
}
func GetNetPrinterStatus(ctx *jxcontext.Context, storeID int) (printResult *partner.PrinterStatus, err error) {
store := &model.Store{}
store.ID = storeID
db := dao.GetDB()
if err = dao.GetEntity(db, store); err == nil {
return getNetPrinterStatus(ctx, store)
}
return nil, err
}
func getNetPrinterStatus(ctx *jxcontext.Context, store *model.Store) (printResult *partner.PrinterStatus, err error) {
handler, err := GetHandlerFromStore(store)
if err != nil {
return &partner.PrinterStatus{
PrintResult: partner.PrintResultNoPrinter,
}, nil
}
return handler.GetPrinterStatus(ctx, store.PrinterSN, store.PrinterKey)
}
func GetHandlerFromStore(store *model.Store) (printerHandler partner.IPrinterHandler, err error) {
if store.IsPrinterDisabled() {
return nil, fmt.Errorf("门店%s没有启用网络打印机", store.Name)
}
if printerHandler = partner.GetPrinterPlatformFromVendorID(store.PrinterVendorID); printerHandler == nil {
return nil, fmt.Errorf("门店%s没有配置网络打印机", store.Name)
}
return printerHandler, nil
}
func BindPrinter(ctx *jxcontext.Context, storeID int, data string) (printResult *partner.PrinterStatus, err error) {
store := &model.Store{}
store.ID = storeID
db := dao.GetDB()
if err = dao.GetEntity(db, store); err == nil {
var mapData map[string]interface{}
if err = utils.UnmarshalUseNumber([]byte(data), &mapData); err == nil {
printerVendorID := model.VendorIDUnknown
if mapData["machineCode"] != nil {
printerVendorID = model.VendorIDYiLianYun
}
if handler := partner.GetPrinterPlatformFromVendorID(printerVendorID); handler != nil {
if store.PrinterVendorID > 0 && store.PrinterVendorID != printerVendorID {
err = fmt.Errorf("门店:%d已经绑定了%s打印机如果需要重新绑定请联系运营先解绑", storeID, model.VendorChineseNames[store.PrinterVendorID])
} else {
bindResult, err2 := handler.BindPrinter(ctx, mapData)
if err = err2; err == nil {
store.PrinterVendorID = printerVendorID
store.PrinterSN = bindResult.PrinterSN
store.PrinterKey = bindResult.PrinterKey
store.PrinterBindInfo = string(utils.MustMarshal(bindResult))
if _, err = dao.UpdateEntity(db, store); err == nil {
err = handler.EmptyPrintList(ctx, bindResult.PrinterSN, bindResult.PrinterKey)
printResult, err = handler.GetPrinterStatus(ctx, bindResult.PrinterSN, bindResult.PrinterKey)
}
}
}
} else {
err = fmt.Errorf("打印机类型:%d当前不支持", printerVendorID)
}
} else {
err = fmt.Errorf("请扫描正确的二维码,如需要帮助,请联系运营!")
}
}
return printResult, err
}
func RebindAllPrinters(ctx *jxcontext.Context, isForce, isAsync bool) (hint string, err error) {
storeList, err := dao.GetRebindPrinterStoreList(dao.GetDB())
if err == nil {
var needRebindList []*model.Store
bindResultMap := make(map[int]*partner.BindPrinterResult)
now := time.Now()
for _, v := range storeList {
var bindResult partner.BindPrinterResult
if err = utils.UnmarshalUseNumber([]byte(v.PrinterBindInfo), &bindResult); err == nil {
if isForce || now.Sub(utils.Timestamp2Time(bindResult.ExpiresAt)) > -3*24*time.Hour {
needRebindList = append(needRebindList, v)
bindResultMap[v.ID] = &bindResult
}
}
}
globals.SugarLogger.Debugf("RebindAllPrinters len(needRebindList):%d", len(needRebindList))
if len(needRebindList) > 0 {
db := dao.GetDB()
task := tasksch.NewParallelTask("RebindAllPrinters", tasksch.NewParallelConfig().SetIsContinueWhenError(true).SetParallelCount(4), ctx,
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
store := batchItemList[0].(*model.Store)
if handler := partner.GetPrinterPlatformFromVendorID(store.PrinterVendorID); handler != nil {
bindResult, err2 := handler.RebindPrinter(ctx, bindResultMap[store.ID])
globals.SugarLogger.Debugf("RebindAllPrinters storeID:%d, result:%s, err:%v", store.ID, utils.Format4Output(bindResult, true), err2)
if err = err2; err == nil {
store.PrinterSN = bindResult.PrinterSN
store.PrinterKey = bindResult.PrinterKey
store.PrinterBindInfo = string(utils.MustMarshal(bindResult))
if _, err = dao.UpdateEntity(db, store); err == nil {
retVal = []int{1}
}
}
} else {
globals.SugarLogger.Warnf("RebindAllPrinters strange PrinterVendorID:%d", store.PrinterVendorID)
}
return retVal, err
}, needRebindList)
tasksch.ManageTask(task).Run()
if !isAsync {
hint = task.GetID()
} else {
result, err2 := task.GetResult(0)
if err = err2; err == nil {
hint = utils.Int2Str(len(result))
}
}
}
}
return hint, err
}
func NofityOrderMsg(ctx *jxcontext.Context, storeID int, orderID, notifyMsg string) (err error) {
if notifyMsg != "" {
notifyMsg = strings.ReplaceAll(notifyMsg, ",", "")
db := dao.GetDB()
store := &model.Store{}
store.ID = storeID
if err = dao.GetEntity(db, store); err == nil {
handler, err := GetHandlerFromStore(store)
if err == nil {
if globals.EnableStoreWrite {
_, err = handler.PlayText(ctx, store.PrinterSN, store.PrinterKey, orderID, notifyMsg)
}
}
}
}
return err
}

View File

@@ -8,8 +8,6 @@ import (
"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/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"
)
@@ -23,13 +21,13 @@ var (
}
)
func SendSMSMsg(mobileList []string, signName, templateCode string, templateParam map[string]interface{}, order *model.GoodsOrder) (err error) {
func SendSMSMsg(mobileList []string, signName, templateCode string, templateParam map[string]interface{}) (err error) {
if len(mobileList) > 0 {
errList := errlist.New()
mobileList = jxutils.StringMap2List(jxutils.StringList2Map(mobileList))
for _, mobileNum := range mobileList {
if mobileNum != "" {
globals.SugarLogger.Debugf("SendSMSMsg mobileNum:%s, templateCode:%s", mobileNum, templateCode)
globals.SugarLogger.Debugf("SendSMSMsg 1 mobileNum:%s, templateCode:%s", mobileNum, templateCode)
if true { //globals.EnableStoreWrite {
if response, err := api.SMSClient.Execute(globals.AliKey, globals.AliSecret, mobileNum, signName, templateCode, string(utils.MustMarshal(templateParam))); err != nil {
globals.SugarLogger.Warnf("SendSMSMsg mobileNum:%s failed with error:%v", mobileNum, err)
@@ -43,11 +41,6 @@ func SendSMSMsg(mobileList []string, signName, templateCode string, templatePara
globals.SugarLogger.Infof(errMsg)
}
}
// else {
// if order != nil {
// err = updateStoreSMSNotifyMark(order)
// }
// }
}
}
}
@@ -55,174 +48,3 @@ func SendSMSMsg(mobileList []string, signName, templateCode string, templatePara
}
return err
}
func getOrderNotifyPhone(order *model.GoodsOrder) (phoneList []string) {
return dao.GetOrderNotifyPhones(dao.GetDB(), jxutils.GetSaleStoreIDFromOrder(order))
}
func NotifyNewOrder(order *model.GoodsOrder) (err error) {
if isPushSMS(order) {
temp := ""
var price int64
store, _ := dao.GetStoreDetail(dao.GetDB(), jxutils.GetSaleStoreIDFromOrder(order), order.VendorID, order.VendorOrgCode)
if store.VendorPayPercentage < 50 && store.VendorPayPercentage != 0 {
temp = globals.SMSNewOrderTemplate
price = order.ActualPayPrice
} else if store.VendorPayPercentage > 50 {
temp = globals.SMSNewOrderTemplateQ
price = order.ShopPrice
} else if store.VendorPayPercentage == 0 {
if store.PayPercentage > 50 {
temp = globals.SMSNewOrderTemplateQ
price = order.ShopPrice
} else {
temp = globals.SMSNewOrderTemplate
price = order.ActualPayPrice
}
}
err = SendSMSMsg(getOrderNotifyPhone(order), globals.SMSSignName, temp, map[string]interface{}{
"daySeq": order.OrderSeq,
"consigneeName": order.ConsigneeName,
"payMoney": jxutils.IntPrice2StandardString(price),
}, order)
}
return err
}
func NotifyOrderCanceled(order *model.GoodsOrder) (err error) {
err = SendSMSMsg(getOrderNotifyPhone(order), globals.SMSSignName, globals.SMSOrderCanceledTemplate, map[string]interface{}{
"vendorName": model.VendorChineseNames[order.VendorID],
"seq": order.OrderSeq,
"orderID": order.VendorOrderID,
}, order)
return err
}
func isPushSMS(order *model.GoodsOrder) bool {
storeID := 0
if order.StoreID == 0 {
storeID = order.JxStoreID
} else {
storeID = order.StoreID
}
stores, _ := dao.GetStoresMapList(dao.GetDB(), []int{order.VendorID}, []int{storeID}, nil, model.StoreStatusAll, model.StoreIsSyncAll, "", "", "")
if len(stores) > 0 {
if stores[0].IsOrder == model.NO {
if storeID == model.MatterStoreID || storeID == model.JdShopMainStoreID {
return false
} else {
return true
}
} else {
return false
}
} else {
return false
}
}
func updateStoreSMSNotifyMark(order *model.GoodsOrder) (err error) {
var db = dao.GetDB()
stores, _ := dao.GetStoreList(db, []int{order.StoreID}, nil, nil, nil, nil, "")
if len(stores) > 0 {
stores[0].SMSNotifyMark = model.YES
_, err = dao.UpdateEntity(db, stores[0], "SMSNotifyMark")
}
return err
}
//每月向用户发送
func NotifyNewUserOrder(order *model.GoodsOrder) (err error) {
var (
db = dao.GetDB()
storeTel string
storeID int
mobile string
)
if order.StoreID == 0 {
storeID = order.JxStoreID
} else {
storeID = order.StoreID
}
if order.ConsigneeMobile2 != "" {
mobile = order.ConsigneeMobile2
uoSMS, err := dao.GetUserOrderSMS(db, mobile, "")
stores, _ := dao.GetStoreList(db, []int{storeID}, nil, nil, nil, nil, "")
if len(stores) > 0 {
if stores[0].Tel1 == "" {
storeTel = stores[0].Tel2
} else {
storeTel = stores[0].Tel1
}
}
if uoSMS == nil {
uoSMSc := &model.UserOrderSms{
Mobile: mobile,
Name: order.ConsigneeName,
VendorUserID: order.VendorUserID,
TotalCount: 0,
SMSMark: model.NO,
}
err = dao.CreateEntity(db, uoSMSc)
err = SendSMSMsg([]string{uoSMSc.Mobile}, globals.SMSSignName, globals.SMSNewUserOrderTemplate, map[string]interface{}{
"tel": storeTel,
}, nil)
if err == nil {
uoSMS2, _ := dao.GetUserOrderSMS(db, mobile, "")
uoSMS2.SMSMark = model.YES
uoSMS2.TotalCount++
_, err = dao.UpdateEntity(db, uoSMS2, "SMSMark", "TotalCount")
}
} else {
if uoSMS.SMSMark != model.YES {
err = SendSMSMsg([]string{uoSMS.Mobile}, globals.SMSSignName, globals.SMSNewUserOrderTemplate, map[string]interface{}{
"tel": storeTel,
}, nil)
if err == nil {
uoSMS.SMSMark = model.YES
uoSMS.TotalCount++
_, err = dao.UpdateEntity(db, uoSMS, "SMSMark", "TotalCount")
}
}
}
}
return err
}
//给配送员发短信
func NotifyNewCourierOrder(bill *model.Waybill) (err error) {
var (
db = dao.GetDB()
storeTel string
storeID int
)
order := &model.GoodsOrder{}
order.VendorOrderID = bill.VendorOrderID
err = dao.GetEntity(db, order, "VendorOrderID")
if order.StoreID == 0 {
storeID = order.JxStoreID
} else {
storeID = order.StoreID
}
stores, _ := dao.GetStoreList(db, []int{storeID}, nil, nil, nil, nil, "")
if len(stores) > 0 {
if stores[0].Tel1 == "" {
storeTel = stores[0].Tel2
} else {
storeTel = stores[0].Tel1
}
}
err = SendSMSMsg([]string{bill.CourierMobile}, globals.SMSSignName, globals.SMSNewOrderTemplate, map[string]interface{}{
"tel": storeTel,
}, nil)
return err
}
//京西订单配送员取货后,给用户发短信提醒
func NotifyJxOrder(order *model.GoodsOrder, bill *model.Waybill) (err error) {
err = SendSMSMsg([]string{order.ConsigneeMobile}, globals.SMSSignName, globals.SMSJxOrderDelivering, map[string]interface{}{
"phone": bill.CourierMobile,
}, order)
return err
}

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