Compare commits

1089 Commits

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

1
.gitignore vendored
View File

@@ -2,7 +2,6 @@
jx-callback
*.tmp
swagger/
debug
.DS_Store
*.log

View File

@@ -10,8 +10,8 @@ import (
"time"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/dao"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/globals/api"
"github.com/dchest/captcha"
@@ -340,6 +340,18 @@ func AddAuthBind(user IUser, newAuthInfo *AuthInfo) (err error) {
return err
}
func AddAuthBindWithMobile(authInfo *AuthInfo, mobile string) (err error) {
if handler := authers[authInfo.AuthBindInfo.Type]; handler != nil {
user, _ := dao.GetUserByID(dao.GetDB(), "mobile", mobile)
authInfo.AuthBindInfo.UserID = user.UserID
//handler.UnbindAuth(user.GetID(), newAuthInfo.GetAuthType(), newAuthInfo.GetAuthTypeID(), user.GetName())
err = handler.AddAuthBind(authInfo.AuthBindInfo, user.GetName())
} else {
err = ErrIllegalAuthType
}
return err
}
func UnbindAuth(userID, authType, authTypeID, userName string) (err error) {
globals.SugarLogger.Debugf("UnbindAuth userID:%s, authType:%s, authTypeID:%s, userName:%s", userID, authType, authTypeID, userName)
if handler := authers[authType]; handler != nil {

View File

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

View File

@@ -9,8 +9,8 @@ import (
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/auth2"
"git.rosy.net.cn/jx-callback/business/dao"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/globals/api"
)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -5,9 +5,10 @@ import (
"errors"
"fmt"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/dao"
"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"
@@ -267,6 +268,10 @@ func DelPrinter(appID int, printNos []string, storeId string) (err error) {
return err
}
func QueryPrintList(printNo, printKey string, status, isOnline int64, page, size int64) ([]*model.Printer, int, error) {
prints, count, err := dao.QueryPrintList(dao.GetDB(), printNo, printKey, status, isOnline, page, size)
return prints, count, err
}
func UpdatePrinter(appID int, printNo string, name, sim, sound *string, volume *int) (err error) {
var (
db = dao.GetDB()
@@ -333,7 +338,7 @@ func DelPrinterSeq(appID int, printNo string) (err error) {
if printers, _ := dao.GetPrinters(db, appID, printNo, 0, 0); len(printers) == 0 {
return fmt.Errorf("该应用下未找到该打印机print_no : %v", printNo)
} else {
printMsgs, _ := dao.GetPrintMsgs(db, printNo, "", model.PrintMsgAll, model.PrintMsgSuccess)
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 {
@@ -378,7 +383,25 @@ func DoPrintMsg(appID int, msgID, printNo, content string, orderNo string) (err
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
@@ -399,7 +422,7 @@ func GetPrintMsg(appID int, msgID string) (printMsg *GetPrintMsgResult, err erro
var (
db = dao.GetDB()
)
if printMsgs, _ := dao.GetPrintMsgs(db, "", msgID, model.PrintMsgAll, model.PrintMsgAll); len(printMsgs) > 0 {
if printMsgs, _ := dao.GetPrintMsgs2(db, "", msgID, model.PrintMsgAll, model.PrintMsgAll); len(printMsgs) > 0 {
result := printMsgs[0]
printMsg = &GetPrintMsgResult{
MsgID: result.MsgID,
@@ -420,48 +443,25 @@ func GetPrinterStatus(appID int, printNo string) (status int, err error) {
db = dao.GetDB()
)
//看有没有
if printers, _ := dao.GetPrinters(db, appID, printNo, 0, 0); len(printers) == 0 {
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
//server := "print.jxcs.net:8000"
//tcpAddr, err := net.ResolveTCPAddr("tcp4", server)
//if err != nil {
// //os.Exit(1)
// return status, err
//}
//conn, err := net.DialTCP("tcp", nil, tcpAddr)
//if err != nil {
// return status, err
//}
//status = connHandler(conn, &PrintInfo{
// PrintNo: printNo,
// AppID: appID,
//})
//return status, nil
}
}
func connHandler(c net.Conn, printInfo *PrintInfo) (status int) {
defer c.Close()
//缓冲
buf := make([]byte, 1024)
data, _ := json.Marshal(printInfo)
//写入数据
c.Write(data)
//服务器端返回的数据写入buf
n, _ := c.Read(buf)
status = utils.Str2Int(string(buf[:n]))
//服务器端回传的信息
fmt.Println("server response:", string(buf[:n]))
return status
}
//#region 打印机拼装模板
// QueryPrinterSetting 查询用户设置
func QueryPrinterSetting() {
}
//#endregion 打印机

View File

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

View File

@@ -1,18 +1,29 @@
package cms
import (
"encoding/json"
"fmt"
"git.rosy.net.cn/baseapi/platformapi/mtunionapi"
"git.rosy.net.cn/baseapi/platformapi/tbunionapi"
"reflect"
"regexp"
"strconv"
"time"
"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/jx-callback/business/authz/autils"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/dao"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/globals/api"
)
const (
@@ -43,36 +54,60 @@ func InitServiceInfo(version string, buildTime time.Time, gitCommit string) {
"buildTime": buildTimeStr,
"gitCommit": gitCommit,
"metaData": map[string]interface{}{
"vendorTypeName": model.VendorTypeName,
"vendorName": model.VendorChineseNames,
//"vendorImg": model.VendorImg,
//"vendorColors": model.VendorColors,
"vendorTypeName": model.VendorTypeName,
"vendorName": model.VendorChineseNames,
"vendorImg": model.VendorImg,
"vendorColors": model.VendorColors,
"orderStatus": model.OrderStatusName,
"waybillStatus": model.WaybillStatusName,
"orderTypeName": model.OrderTypeName,
"taskStatusName": tasksch.TaskStatusName,
"storeMsgSendStatusName": model.StoreMsgSendStatusName,
"shopChineseNames": model.ShopChineseNames,
"printerVendorInfo": model.PrinterVendorInfo,
"purchaseVendorInfo": model.PurchaseVendorInfo,
"afsReasonTypeName": model.AfsReasonTypeName,
"afsAppealTypeName": model.AfsAppealTypeName,
"actTypeName": model.ActTypeName,
"actStatusName": model.ActStatusName,
"actCreateTypeName": model.ActCreateTypeName,
"configTypeName": model.ConfigTypeName,
"userTypeName": model.UserTypeName,
"payStatusName": model.PayStatusName,
"refundStatusName": model.RefundStatusName,
"complaintReasons": model.ComplaintReasons,
"supplementType": model.SupplementTypeName,
"operateType": model.OperateTypeName,
"apiFunctionName": model.ApiFunctionName,
"vendorStatus": model.VendorStatus,
"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.VendorIDTB: map[int]interface{}{
tbunionapi.TbElmActTypeBDH: "本地化",
},
model.VendorIDPDD: map[int]interface{}{
1: "进行中的活动",
},
model.VendorIDJDShop: map[int]interface{}{
2: "进行中",
},
@@ -119,6 +154,15 @@ func GetPlaces(ctx *jxcontext.Context, keyword string, includeDisabled bool, par
return places, dao.GetRows(nil, &places, sql, sqlParams)
}
func GetCoordinateDistrictCode(ctx *jxcontext.Context, lng, lat float64) (code int, err error) {
return api.AutonaviAPI.GetCoordinateDistrictCode(lng, lat), nil
}
func GetCoordinateCityInfo(ctx *jxcontext.Context, lng, lat float64) (name string, err error) {
name, _ = api.AutonaviAPI.GetCoordinateCityInfo(lng, lat)
return name, err
}
func SendMsg2Somebody(ctx *jxcontext.Context, mobileNum, verifyCode, msgType, msgContent string) (err error) {
return err
@@ -143,6 +187,47 @@ func AddConfig(ctx *jxcontext.Context, key, configType, value string) (err error
return err
}
func DeleteConfig(ctx *jxcontext.Context, key, configType string) (err error) {
// if err = checkConfig(model.SyncFlagDeletedMask, configType, key, ""); err != nil {
// return err
// }
db := dao.GetDB()
switch configType {
case model.ConfigTypePricePack:
case model.ConfigTypeFreightPack:
case model.ConfigTypeBank:
//todo
return fmt.Errorf("暂不支持删除银行")
case model.ConfigTypeRole:
errList := errlist.New()
userIDs, err2 := api2.RoleMan.GetRoleUserList(autils.NewRole(key, 0))
if err = err2; err == nil && len(userIDs) > 0 {
userList, totalCount, err2 := dao.GetUsers(dao.GetDB(), 0, "", "", userIDs, nil, nil, 0, -1)
if err = err2; err == nil && totalCount > 0 {
// todo
// err = fmt.Errorf("还有人员在使用角色:%s人员信息:%s", key, utils.MustMarshal(utils.Struct2Map(userList, "compact")))
err = fmt.Errorf("还有人员在使用角色:%s人员信息:%s", key, utils.Format4Output(userList, false))
}
}
errList.AddErr(err)
errList.AddErr(err)
err = errList.GetErrListAsOne()
}
if err == nil {
_, err = dao.DeleteEntityLogically(db, &model.NewConfig{}, nil, ctx.GetUserName(), map[string]interface{}{
"Key": key,
"Type": configType,
})
}
if configType == model.ConfigTypeSys && err == nil {
// err = onSysConfigChanged(key, "")
}
return err
}
func UpdateConfig(ctx *jxcontext.Context, key, configType, value string) (hint string, err error) {
if key == "" {
return "", fmt.Errorf("修改配置必须给定key")
@@ -183,3 +268,106 @@ func UpdateConfig(ctx *jxcontext.Context, key, configType, value string) (hint s
func QueryConfigs(key, configType, keyword string) (configList []*model.NewConfig, err error) {
return dao.QueryConfigs(dao.GetDB(), key, configType, keyword)
}
func 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
}
}
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,11 +0,0 @@
package cms
import (
"fmt"
"testing"
)
func TestConn(t *testing.T) {
err := DelPrinterSeq(1000, "120220915001012")
fmt.Println(err)
}

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

File diff suppressed because it is too large Load Diff

View File

@@ -4,10 +4,10 @@ import (
"time"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/dao"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
)
type MessageStatusExt struct {

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

@@ -0,0 +1,287 @@
package cms
import (
"fmt"
"time"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
)
func GetMenu(ctx *jxcontext.Context, userID string) (menus []*model.Menu, err error) {
if userID == "" {
return dao.GetMenu(dao.GetDB(), "", 0, userID)
} else {
return dao.GetMenuWithUser(dao.GetDB(), "", 0, userID)
}
}
func AddMenu(ctx *jxcontext.Context, menu *model.Menu) (err error) {
var (
db = dao.GetDB()
)
if menu == nil {
return fmt.Errorf("添加失败menu nil")
}
if menu.Name == "" || menu.Level == 0 {
return fmt.Errorf("添加失败menu 名称和等级必须有值!")
}
menus, err := dao.GetMenu(db, menu.Name, menu.Level, "")
if len(menus) > 0 {
return fmt.Errorf("添加失败!已存在相同名称的 menu name : %v", menu.Name)
}
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, txDB)
panic(r)
}
}()
dao.WrapAddIDCULDEntity(menu, ctx.GetUserName())
err = dao.CreateEntity(db, menu)
dao.Commit(db, txDB)
return err
}
func UpdateMenu(ctx *jxcontext.Context, menuID int, payload map[string]interface{}, isDelete bool) (num int64, err error) {
var (
db = dao.GetDB()
)
menu := &model.Menu{}
menu.ID = menuID
err = dao.GetEntity(db, menu)
if err != nil {
return 0, err
}
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, txDB)
panic(r)
}
}()
if !isDelete {
valid := dao.StrictMakeMapByStructObject(payload, menu, ctx.GetUserName())
if len(valid) > 0 {
if num, err = dao.UpdateEntityLogically(db, menu, valid, ctx.GetUserName(), nil); err != nil {
dao.Rollback(db, txDB)
return 0, err
}
}
} else {
menu.DeletedAt = time.Now()
num, err = dao.UpdateEntity(db, menu, "DeletedAt")
}
dao.Commit(db, txDB)
return num, err
}
func GetRole(ctx *jxcontext.Context) (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)
if len(roles) > 0 {
return fmt.Errorf("添加失败!已存在相同名称的 role name : %v", name)
}
role := &model.Role{
Name: name,
}
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, txDB)
panic(r)
}
}()
dao.WrapAddIDCULDEntity(role, ctx.GetUserName())
err = dao.CreateEntity(db, role)
dao.Commit(db, txDB)
return err
}
func UpdateRole(ctx *jxcontext.Context, roleID int, name string, isDelete bool) (num int64, err error) {
var (
db = dao.GetDB()
)
if roleID == 1 {
return 0, fmt.Errorf("管理员不允许修改!")
}
role := &model.Role{}
role.ID = roleID
err = dao.GetEntity(db, role)
if err != nil {
return 0, err
}
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, txDB)
panic(r)
}
}()
if !isDelete {
role.Name = name
role.UpdatedAt = time.Now()
role.LastOperator = ctx.GetUserName()
num, err = dao.UpdateEntity(db, role, "Name", "UpdatedAt", "LastOperator")
} else {
role.DeletedAt = time.Now()
num, err = dao.UpdateEntity(db, role, "DeletedAt")
}
dao.Commit(db, txDB)
return num, err
}
func GetUserRole(ctx *jxcontext.Context, userID string) (userRoles []*model.UserRole, err error) {
return dao.GetUserRole(dao.GetDB(), []string{userID}, nil)
}
func UpdateUserRole(ctx *jxcontext.Context, userIDs []string, roleIDs []int) (err error) {
var (
db = dao.GetDB()
roleIDMap = make(map[int]int)
nowRoleIDMap = make(map[int]int)
userRoleMap = make(map[string][]int)
addUserRoleMap = make(map[string][]int)
deleteUserRoleMap = make(map[string][]int)
)
for _, v := range roleIDs {
roleIDMap[v] = 1
}
userRoles, err := dao.GetUserRole(db, userIDs, nil)
if err != nil {
return err
}
if len(userRoles) > 0 {
for _, v := range userRoles {
userRoleMap[v.UserID] = append(userRoleMap[v.UserID], v.RoleID)
}
}
for _, userID := range userIDs {
nowRoleIDs := userRoleMap[userID]
for _, nowRoleID := range nowRoleIDs {
if roleIDMap[nowRoleID] == 0 {
deleteUserRoleMap[userID] = append(deleteUserRoleMap[userID], nowRoleID)
}
nowRoleIDMap[nowRoleID] = 1
}
for _, roleID := range roleIDMap {
if nowRoleIDMap[roleID] == 0 {
addUserRoleMap[userID] = append(addUserRoleMap[userID], roleID)
}
}
}
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, txDB)
panic(r)
}
}()
if len(addUserRoleMap) > 0 {
for userID, roleIDs := range addUserRoleMap {
for _, roleID := range roleIDs {
userRole := &model.UserRole{
UserID: userID,
RoleID: roleID,
}
dao.WrapAddIDCULDEntity(userRole, ctx.GetUserName())
err = dao.CreateEntity(db, userRole)
}
}
}
if len(deleteUserRoleMap) > 0 {
for userID, roleIDs := range deleteUserRoleMap {
for _, roleID := range roleIDs {
userRoles, _ := dao.GetUserRole(db, []string{userID}, []int{roleID})
if len(userRoles) > 0 {
userRoles[0].DeletedAt = time.Now()
userRoles[0].LastOperator = ctx.GetUserName()
_, err = dao.UpdateEntity(db, userRoles[0], "DeletedAt", "LastOperator")
}
}
}
}
dao.Commit(db, txDB)
return err
}
func GetRoleMenu(ctx *jxcontext.Context, roleID int) (roleMenus []*model.RoleMenu, err error) {
return dao.GetRoleMenu(dao.GetDB(), []int{roleID}, nil)
}
func UpdateRoleMenu(ctx *jxcontext.Context, roleIDs, menuIDs []int) (err error) {
var (
db = dao.GetDB()
menuIDMap = make(map[int]int)
nowMenuIDMap = make(map[int]int)
roleMenuMap = make(map[int][]int)
addRoleMenuMap = make(map[int][]int)
deleteRoleMenuMap = make(map[int][]int)
)
for _, v := range menuIDs {
menuIDMap[v] = 1
}
roleMenus, err := dao.GetRoleMenu(db, roleIDs, nil)
if err != nil {
return err
}
if len(roleMenus) > 0 {
for _, v := range roleMenus {
roleMenuMap[v.RoleID] = append(roleMenuMap[v.RoleID], v.MenuID)
}
}
for _, roleID := range roleIDs {
nowMenuIDs := roleMenuMap[roleID]
for _, nowMenuID := range nowMenuIDs {
if menuIDMap[nowMenuID] == 0 {
deleteRoleMenuMap[roleID] = append(deleteRoleMenuMap[roleID], nowMenuID)
}
nowMenuIDMap[nowMenuID] = 1
}
for _, menuID := range menuIDMap {
if nowMenuIDMap[menuID] == 0 {
addRoleMenuMap[menuID] = append(addRoleMenuMap[menuID], menuID)
}
}
}
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, txDB)
panic(r)
}
}()
if len(addRoleMenuMap) > 0 {
for roleID, menuIDs := range addRoleMenuMap {
for _, menuID := range menuIDs {
roleMenu := &model.RoleMenu{
RoleID: roleID,
MenuID: menuID,
}
dao.WrapAddIDCULDEntity(roleMenu, ctx.GetUserName())
err = dao.CreateEntity(db, roleMenu)
}
}
}
if len(deleteRoleMenuMap) > 0 {
for roleID, menuIDs := range deleteRoleMenuMap {
for _, menuID := range menuIDs {
roleMenus, _ := dao.GetRoleMenu(db, []int{roleID}, []int{menuID})
if len(roleMenus) > 0 {
roleMenus[0].DeletedAt = time.Now()
roleMenus[0].LastOperator = ctx.GetUserName()
_, err = dao.UpdateEntity(db, roleMenus[0], "DeletedAt", "LastOperator")
}
}
}
}
dao.Commit(db, txDB)
return err
}

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("参数电话号码异常")
}

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

@@ -2,14 +2,27 @@ package cms
import (
"errors"
"fmt"
"sync"
"time"
"git.rosy.net.cn/jx-callback/business/jxutils/smsmsg"
"git.rosy.net.cn/jx-callback/business/jxstore/event"
"git.rosy.net.cn/jx-callback/business/jxstore/financial"
"git.rosy.net.cn/baseapi/platformapi/dingdingapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/auth2"
"git.rosy.net.cn/jx-callback/business/dao"
"git.rosy.net.cn/jx-callback/business/auth2/authprovider/dingding"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/jxutils/jsonerr"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/globals/api"
)
var (
@@ -48,6 +61,18 @@ type JdUserStruct struct {
type UserProvider struct {
}
func (*UserProvider) GetUser(authID, authIDType string) (user auth2.IUser) {
globals.SugarLogger.Debugf("GetUser, authID:%s, authIDType:%s", authID, authIDType)
fieldName := authTypeFieldMap[authIDType]
if fieldName != "" {
user2, err := dao.GetUserByID(dao.GetDB(), fieldName, authID)
if err == nil {
user = user2 // 这样写的原因是golang nil的比较问题
}
}
return user
}
func (*UserProvider) UpdateUserMobile(userID string, mobile string) (err error) {
_, err = dao.UpdateEntityLogically(dao.GetDB(), &model.User{}, map[string]interface{}{
"Mobile": mobile,
@@ -96,6 +121,91 @@ func (*UserProvider) UpdateLastLogin(userID string, lastLoginType, fromIP string
return err
}
func init() {
auth2.Init(userProvider)
}
func RegisterUserWithMobile(ctx *jxcontext.Context, user *model.User, mobileVerifyCode string, inAuthInfo, manTokenInfo *auth2.AuthInfo) (outAuthInfo *auth2.AuthInfo, err error) {
var mobileAuth *auth2.AuthInfo
fakeMobile := false
createName := ctx.GetRealRemoteIP()
authType := auth2.AuthTypeMobile
if manTokenInfo != nil && mobileVerifyCode == "" {
_, err2 := dao.GetUserByID(dao.GetDB(), "user_id", manTokenInfo.GetID())
if err = err2; err != nil {
return nil, err
}
if utils.Pointer2String(user.Mobile) == "" {
return nil, fmt.Errorf("管理员添加必须指定用户手机号")
}
mobileVerifyCode = auth2.InternalAuthSecret
fakeMobile = true
createName = manTokenInfo.GetName()
}
if mobileVerifyCode != "" {
if fakeMobile {
mobileAuth, err = auth2.LoginInternal(ctx.Context, auth2.AuthTypeMobile, user.GetMobile(), auth2.UserIDMobile, mobileVerifyCode)
} else {
mobileAuth, err = auth2.Login(ctx.Context, auth2.AuthTypeMobile, user.GetMobile(), auth2.UserIDMobile, mobileVerifyCode)
}
if err != nil {
return nil, err
}
if mobileAuth != nil && !mobileAuth.IsUserEmpty() {
return nil, jsonerr.New(mobileAuth, model.ErrCodeJsonUserAlreadyExist)
// auth2.RemoveUserInfo(mobileAuth.Token)
// if newAuthInfo, err := auth2.BindUser(mobileAuth, user); err == nil {
// globals.SugarLogger.Debugf("testRegisterUserWithMobile", utils.Format4Output(mobileAuth, false), utils.Format4Output(newAuthInfo, false))
// return nil, jsonerr.New(newAuthInfo, model.ErrCodeJsonUserAlreadyExist)
// } else {
// return nil, err
// }
}
} else if inAuthInfo != nil {
// user.Mobile = nil
} else {
return nil, fmt.Errorf("短信验证码与其它认证方式至少要指定一种")
}
if inAuthInfo != nil {
createName += "," + inAuthInfo.GetAuthID()
authType = inAuthInfo.GetAuthType()
if user.Avatar == "" {
user.Avatar = inAuthInfo.GetAvatar()
}
}
if err = CreateUser(user, utils.LimitUTF8StringLen(createName, 32)); err == nil {
userProvider.UpdateLastLogin(user.GetID(), authType, ctx.GetRealRemoteIP())
// TryAddStoreBossRole4User(ctx, user)
if mobileAuth != nil {
if outAuthInfo, err = auth2.BindUser(mobileAuth, user); err == nil && inAuthInfo != nil {
err = auth2.AddAuthBind(&outAuthInfo.UserBasic, inAuthInfo)
}
} else {
outAuthInfo, err = auth2.BindUser(inAuthInfo, user)
}
//给用户添加一条账单记录
err = AddUserBill(user)
} else if dao.IsDuplicateError(err) {
err = auth2.ErrUserID2AlreadyExist
}
return outAuthInfo, err
}
func AddUserBill(user *model.User) (err error) {
var (
db = dao.GetDB()
)
userBill := &model.UserBill{
BillID: jxutils.GenBillID(),
UserID: user.UserID,
}
dao.WrapAddIDCULDEntity(userBill, jxcontext.AdminCtx.GetUserName())
return dao.CreateEntity(db, userBill)
}
func GetUserBindAuthInfo(ctx *jxcontext.Context) (authList []*model.AuthBind, err error) {
authInfo, err := ctx.GetV2AuthInfo()
if err == nil {
@@ -104,6 +214,34 @@ func GetUserBindAuthInfo(ctx *jxcontext.Context) (authList []*model.AuthBind, er
return nil, err
}
func CreateUser(user *model.User, creatorName string) (err error) {
globals.SugarLogger.Debugf("CreateUser user:%s, creatorName:%s", utils.Format4Output(user, true), creatorName)
if user == nil || user.UserID2 == "" || user.Name == "" {
return ErrUserIDAndNameMustGiven
}
if user.GetMobile() == "" {
user.Mobile = nil
}
if user.GetEmail() == "" {
user.Email = nil
}
dao.WrapAddIDCULDEntity(user, creatorName)
user.UserID = utils.GetUUID()
user.Status = model.UserStatusNormal
//推广码
popCode := ""
for {
popCode = jxutils.GenRandomString(6)
user2, _ := dao.GetUserByID(dao.GetDB(), "pop_code", popCode)
if user2 == nil {
user.PopCode = popCode
break
}
}
return dao.CreateEntity(nil, user)
}
func DisableUser(ctx *jxcontext.Context, userID string) (err error) {
userName := ctx.GetUserName()
if _, err = dao.UpdateEntityLogically(dao.GetDB(), &model.User{}, map[string]interface{}{
@@ -115,3 +253,536 @@ func DisableUser(ctx *jxcontext.Context, userID string) (err error) {
}
return err
}
func OnDingDingMsg(msg map[string]interface{}) (callbackResponse *dingdingapi.CallbackResponse) {
eventType := utils.Interface2String(msg[dingdingapi.KeyEventType])
if eventType == dingdingapi.CBTagUserLeaveOrg {
var (
authBind *model.AuthBind
err error
)
db := dao.GetDB()
for _, userID := range msg[dingdingapi.KeyUserID].([]interface{}) {
userIDStr := utils.Interface2String(userID)
globals.SugarLogger.Debugf("OnDingDingMsg dingding user:%s left company", userIDStr)
if authBind, err = dao.GetAuthBind(db, model.AuthBindTypeAuth, dingding.AuthTypeStaff, userIDStr); err == nil { // 直接找到了
globals.SugarLogger.Debugf("OnDingDingMsg dingding user:%s, userID:%s left company", userIDStr, authBind.UserID)
if err = DisableUser(jxcontext.AdminCtx, authBind.UserID); err != nil {
globals.SugarLogger.Errorf("OnDingDingMsg failed with error:%v", err)
}
}
}
}
return api.DingDingAPI.Err2CallbackResponse(nil)
}
func GetUsers(ctx *jxcontext.Context, keyword string, userID string, pop int, mobile string, fromTime, toTime string, timeType int, cityCodes, consumeTypes []int, offset, pageSize int) (pagedInfo *model.PagedInfo, err error) {
return dao.GetUsers2(dao.GetDB(), keyword, userID, pop, mobile, utils.Str2Time(fromTime), utils.Str2Time(toTime), timeType, cityCodes, consumeTypes, offset, pageSize)
}
func GetUser(ctx *jxcontext.Context, userID string) (user *model.GetUserResult, err error) {
return dao.GetUser(dao.GetDB(), userID)
}
func checkUserType(userID string, userType int8) (err error) {
userList, _, err := dao.GetUsers(dao.GetDB(), 0, "", "", []string{userID}, nil, nil, 0, 0)
if err != nil {
return err
}
if len(userList) == 0 {
return fmt.Errorf("找不到用户:%s", userID)
}
if userList[0].Type&userType == 0 {
return fmt.Errorf("用户:%s不能用于当前操作", userID)
}
return nil
}
func getAddressInfoFromCoord(db *dao.DaoDB, lng, lat float64) (formattedAddress string, districtCode, cityCode int, err error) {
regeoInfo, err := api.AutonaviAPI.GeoCodeRegeoSingle(lng, lat, 0, false, nil, 0, 0)
if err == nil {
formattedAddress = regeoInfo.FormattedAddress
districtCode = int(utils.Str2Int64WithDefault(regeoInfo.AddressComponent.Adcode, 0))
if districtCode == 0 {
err = fmt.Errorf("坐标lng:%f,lat:%f找不到位置信息", lng, lat)
} else if districtInfo, err2 := dao.GetPlaceByCode(db, districtCode); err2 == nil {
cityCode = districtInfo.ParentCode
}
}
return formattedAddress, districtCode, cityCode, err
}
func AddMyDeliveryAddress(ctx *jxcontext.Context, address *model.UserDeliveryAddress) (outAddress *dao.UserDeliveryAddressEx, err error) {
globals.SugarLogger.Debugf("AddMyDeliveryAddress address:%s", utils.Format4Output(address, true))
_, address.UserID = ctx.GetMobileAndUserID()
out, err := AddUserDeliveryAddress(ctx, address)
list, _, err := dao.QueryUserDeliveryAddress(dao.GetDB(), int64(out.ID), nil, 0, 0, -1)
globals.SugarLogger.Debugf("AddMyDeliveryAddress2 address:%s, err:%v", utils.Format4Output(address, true), err)
return list[0], err
}
func DeleteUserDeliveryAddress(ctx *jxcontext.Context, userID string, addressID int) (err error) {
num, err := dao.DeleteEntityLogically(dao.GetDB(), &model.UserDeliveryAddress{}, nil, ctx.GetUserName(), map[string]interface{}{
model.FieldID: addressID,
"UserID": userID,
})
if err == nil {
if num == 0 {
err = fmt.Errorf("地址ID:%d不存在", addressID)
}
}
return err
}
func DeleteMyDeliveryAddress(ctx *jxcontext.Context, addressID int) (err error) {
_, userID := ctx.GetMobileAndUserID()
return DeleteUserDeliveryAddress(ctx, userID, addressID)
}
func UpdateUserDeliveryAddress(ctx *jxcontext.Context, userID string, addressID int, payload map[string]interface{}) (err error) {
if userID == "" {
return fmt.Errorf("操作用户配送地址时必须指定UserID")
}
address := &model.UserDeliveryAddress{
UserID: userID,
}
address.ID = addressID
db := dao.GetDB()
if err = dao.GetEntity(db, address, model.FieldID, "UserID"); err == nil {
var outAddress *model.UserDeliveryAddress
valid := dao.StrictMakeMapByStructObject2(payload, address, &outAddress, ctx.GetUserName())
delete(valid, "autoAddress")
delete(valid, "districtCode")
delete(valid, "cityCode")
if len(valid) > 0 {
if valid["lng"] != nil || valid["lat"] != nil {
valid["autoAddress"], valid["districtCode"], valid["cityCode"], err = getAddressInfoFromCoord(db, outAddress.Lng, outAddress.Lat)
if err != nil {
return err
}
}
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, txDB)
panic(r)
}
}()
if utils.ForceInterface2Int64(valid["isDefault"]) == 1 {
if err = dao.ClearUserDeliveryAddressDefault(db, userID, 0); err != nil {
dao.Rollback(db, txDB)
return err
}
}
if _, err = dao.UpdateEntityLogically(db, address, valid, ctx.GetUserName(), nil); err == nil {
dao.Commit(db, txDB)
} else {
dao.Rollback(db, txDB)
}
}
}
return err
}
func UpdateMyDeliveryAddress(ctx *jxcontext.Context, addressID int, payload map[string]interface{}) (err error) {
_, userID := ctx.GetMobileAndUserID()
return UpdateUserDeliveryAddress(ctx, userID, addressID, payload)
}
func QueryUserDeliveryAddress(ctx *jxcontext.Context, userIDs []string, offset, pageSize int) (pagedInfo *model.PagedInfo, err error) {
addressList, totalCount, err := dao.QueryUserDeliveryAddress(dao.GetDB(), 0, userIDs, 0, offset, pageSize)
if err == nil {
pagedInfo = &model.PagedInfo{
TotalCount: totalCount,
Data: addressList,
}
}
return pagedInfo, err
}
func QueryMyDeliveryAddress(ctx *jxcontext.Context, addType int) (addressList []*dao.UserDeliveryAddressEx, err error) {
_, userID := ctx.GetMobileAndUserID()
addressList, _, err = dao.QueryUserDeliveryAddress(dao.GetDB(), 0, []string{userID}, addType, 0, model.UnlimitedPageSize)
return addressList, err
}
func AddUserDeliveryAddress(ctx *jxcontext.Context, address *model.UserDeliveryAddress) (outAddress *model.UserDeliveryAddress, err error) {
globals.SugarLogger.Debugf("AddUserDeliveryAddress1 address:%s", utils.Format4Output(address, true))
if address.UserID == "" {
return nil, fmt.Errorf("操作用户配送地址时必须指定UserID")
}
db := dao.GetDB()
lng := address.Lng
lat := address.Lat
autoAddress := ""
autoAddress, address.DistrictCode, address.CityCode, err = getAddressInfoFromCoord(db, lng, lat)
if address.AutoAddress == "" {
address.AutoAddress = autoAddress
}
if err == nil {
globals.SugarLogger.Debugf("AddUserDeliveryAddress2 address:%s", utils.Format4Output(address, true))
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, txDB)
panic(r)
}
}()
dao.WrapAddIDCULDEntity(address, ctx.GetUserName())
if address.IsDefault == 1 {
if err = dao.ClearUserDeliveryAddressDefault(db, address.UserID, 0); err != nil {
dao.Rollback(db, txDB)
return nil, err
}
}
if err = dao.CreateEntity(db, address); err == nil {
dao.Commit(db, txDB)
outAddress = address
} else {
dao.Rollback(db, txDB)
}
}
globals.SugarLogger.Debugf("AddUserDeliveryAddress3 address:%s", utils.Format4Output(address, true))
return outAddress, err
}
func SaveUserCart(ctx *jxcontext.Context, userID string, storeID int, cartItems []*model.UserCartItem) (err error) {
if userID == "" || storeID == 0 {
return fmt.Errorf("用户与门店必须要指定")
}
for _, v := range cartItems {
v.UserID = userID
v.StoreID = storeID
dao.WrapAddIDCULEntity(v, userID)
}
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)
}
}
}()
_, err = dao.ExecuteSQL(db, `
DELETE t1
FROM user_cart_item t1
WHERE t1.user_id = ? AND t1.store_id = ?
`, userID, storeID)
if err != nil {
return err
}
if len(cartItems) > 0 {
err = dao.CreateMultiEntities(db, cartItems)
}
if err == nil {
dao.Commit(db, txDB)
}
return err
}
func LoadUserCart(ctx *jxcontext.Context, userID string, storeIDs []int) (cartItems []*model.UserCartItem, err error) {
if userID == "" || len(storeIDs) == 0 {
return nil, fmt.Errorf("用户与门店必须要指定")
}
sql := `
SELECT t1.*
FROM user_cart_item t1
WHERE t1.user_id = ? AND t1.store_id IN (` + dao.GenQuestionMarks(len(storeIDs)) + `)
ORDER BY t1.sku_id
`
err = dao.GetRows(dao.GetDB(), &cartItems, sql, userID, storeIDs)
return cartItems, err
}
func GetSelfInfo(ctx *jxcontext.Context) (getSelfInfoResult *dao.GetSelfInfoResult, err error) {
tokenInfo, err := auth2.GetTokenInfo(ctx.GetToken())
if err == nil {
if getSelfInfoResult, err = dao.GetUserByIDWithMembers(dao.GetDB(), "user_id", tokenInfo.GetID()); err == nil {
if userMembers, err3 := dao.GetUserMember(dao.GetDB(), getSelfInfoResult.User.UserID, 0); err3 == nil {
getSelfInfoResult.UserMembers = userMembers
} else {
err = err3
}
if price, err := dao.GetUserAllWaitCashPrice(dao.GetDB(), getSelfInfoResult.User.UserID); err == nil {
getSelfInfoResult.WaitCashPrice = price
}
if price, err := dao.GetUserAllWaitRealCashPrice(dao.GetDB(), getSelfInfoResult.User.UserID); err == nil {
getSelfInfoResult.WaitRealCashPrice = price
}
}
}
return getSelfInfoResult, err
}
func RefreshUserMemberStatus(ctx *jxcontext.Context) (err error) {
var (
db = dao.GetDB()
)
userMembers, err := dao.GetUserMember(db, "", 0)
for _, userMember := range userMembers {
if time.Now().Sub(userMember.EndAt) > 0 {
userMember.DeletedAt = time.Now()
dao.UpdateEntity(db, userMember, "DeletedAt")
}
}
return err
}
func InvestMember(ctx *jxcontext.Context, memberID int, userID string, isFree bool) (errCode string, err error) {
var (
db = dao.GetDB()
memberCards []*model.MemberCard
memberCard *model.MemberCard
userIDReal string
)
if !isFree {
userIDReal = ctx.GetUserID()
} else {
userIDReal = userID
}
userMembers, err := dao.GetUserMember(db, userIDReal, model.MemberTypeNormal)
configList, err := dao.QueryConfigs(db, model.ConfigTypeName[model.ConfigTypeMemberCard], model.ConfigTypeMemberCard, "")
userBill, err := dao.GetUserBill(db, userIDReal, "")
if len(configList) <= 0 {
return "", fmt.Errorf("未找到会员卡配置!")
}
config := configList[0]
err = jxutils.Strings2Objs(config.Value, &memberCards)
if err != nil {
return "", err
}
for _, v := range memberCards {
if v.ID == memberID {
memberCard = v
}
}
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, txDB)
panic(r)
}
}()
if !isFree {
//验证微信绑定
if err = auth2.CheckWeixinminiAuthBind(userIDReal); err != nil {
return "", err
}
if userBill.AccountBalance < memberCard.ActPrice {
//if _, err := financial.WXInvestMember(ctx, userMembers[0].MemberTypeID, userMembers[0].UserID); err != nil {
// dao.Rollback(db, txDB)
//}
return model.ErrCodeAccountBalanceNotEnough, fmt.Errorf("用户余额不足,请充值!")
}
}
//证明已经开了会员了,相当于续费
if len(userMembers) > 0 {
userMember := userMembers[0]
if memberID == model.MemberCardTypeMonth {
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 {
dao.Rollback(db, txDB)
return
}
} else {
userMember2 := &model.UserMember{
UserID: userIDReal,
MemberType: model.MemberTypeNormal,
MemberTypeID: memberID,
}
if memberID == model.MemberCardTypeMonth {
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 {
dao.Rollback(db, txDB)
return
}
}
if !isFree {
//支出明细
if err = financial.AddExpendUpdateAccount(txDB, userBill, model.BillTypeMember, memberCard.ActPrice, 0); err != nil {
dao.Rollback(db, txDB)
return
}
}
dao.Commit(db, txDB)
return errCode, err
}
func UpdateUser(ctx *jxcontext.Context, payload map[string]interface{}) (err error) {
var (
db = dao.GetDB()
userID string
)
if payload["userID"] != nil {
userID = payload["userID"].(string)
} else {
userID = ctx.GetUserID()
}
user := &model.User{
UserID: userID,
}
dao.GetEntity(db, user, "UserID")
if payload["lng"] != nil && payload["lat"] != nil {
if address, districtCode, cityCode, err := getAddressInfoFromCoord(db, utils.MustInterface2Float64(payload["lng"]), utils.MustInterface2Float64(payload["lat"])); err == nil {
delete(payload, "lng")
delete(payload, "lat")
payload["address"] = address
payload["districtCode"] = districtCode
payload["cityCode"] = cityCode
} else {
return err
}
}
//暂时用这个字段作为更新他的推广人
if payload["popCode"] != nil {
if user, err := dao.GetUserByID(db, "pop_code", payload["popCode"].(string)); err == nil {
if user != nil {
payload["popUser"] = user.UserID
delete(payload, "popCode")
} else {
return fmt.Errorf("未查询到此推广人!%v", payload["popCode"])
}
}
}
valid := dao.StrictMakeMapByStructObject(payload, user, ctx.GetUserName())
if len(valid) > 0 {
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, txDB)
panic(r)
}
}()
if _, err = dao.UpdateEntityByKV(db, user, valid, nil); err != nil {
dao.Rollback(db, txDB)
return err
}
dao.Commit(db, txDB)
}
if payload["popUser"] != nil {
// InvestMemberAndUpdate := func(user *model.User) (err error) {
// if _, err = InvestMember(ctx, 1, user.UserID, true); err == nil {
// }
// user.PopFlag = model.YES
// _, err = dao.UpdateEntity(db, user, "PopFlag")
// return err
// }
user2, err2 := dao.GetUserByID(db, "user_id", payload["popUser"].(string))
err = err2
do := func(user *model.User, flag bool) (err error) {
if user.PopCount%4 == 0 && user.PopFlag == model.NO {
if _, err = InvestMember(ctx, 1, user.UserID, true); err == nil {
//发短信,公众号消息通知
smsmsg.SendSMSMsg([]string{*user.Mobile}, globals.SMSSignName, globals.SMSPopSuccessTemplate, nil)
// weixinmsg.SendMsgToUser(userID, templateID, data)
event.SendSysMessageSimple("您好您已成功邀请4人加入我们成功免费获得1个月会员", user.UserID)
}
user.PopFlag = model.YES
dao.UpdateEntity(db, user, "PopFlag")
if flag {
if users, _, err := dao.GetUsers(db, 0, "", user.UserID, nil, nil, nil, 0, 999); err == nil {
for _, v := range users {
v.PopedFlag = model.YES
dao.UpdateEntity(db, v, "PopedFlag")
}
}
_, err = event.CreateMessageGroup(ctx, user.UserID, "", "", 5, 100)
}
}
return err
}
if user2 != nil {
user2.PopCount++
messageGroupsResult, err3 := dao.GetMessageGroups(db, user2.UserID, 0, model.GroupTypeMulit, false, "")
err = err3
//如果他已经有群了,被邀请人直接进群
//如果他没群在邀请到4个人的时候,自动创一个群,所有被邀请人打上标志
if len(messageGroupsResult) > 0 {
err = event.AddMessageGroup(ctx, messageGroupsResult[0].GroupID, user.UserID)
//邀请过4人直接开通一个月会员
do(user2, false)
} else {
//邀请过4人直接开通一个月会员并创建群组
do(user2, true)
}
dao.UpdateEntity(db, user2, "PopCount")
}
}
return err
}
func AcceptAddGroup(ctx *jxcontext.Context, flag int) (err error) {
var (
db = dao.GetDB()
userID = ctx.GetUserID()
)
user, err := dao.GetUserByID(db, "user_id", userID)
if user == nil {
return fmt.Errorf("获取用户信息失败!")
}
if err != nil {
return err
}
if user.PopedFlag == model.NO {
return fmt.Errorf("获取用户邀请信息失败")
}
//同意加入
if flag == model.YES {
//1、找到这个人的邀请人
//2、这个邀请人有群就直接进没群就加入失败了
messageGroupsResult, err := dao.GetMessageGroups(db, user.PopUser, 0, model.GroupTypeMulit, false, "")
if err != nil {
return fmt.Errorf("获取邀请人群信息失败! %v", err)
}
if len(messageGroupsResult) > 0 {
err = event.AddMessageGroup(ctx, messageGroupsResult[0].GroupID, user.UserID)
} else {
return fmt.Errorf("获取邀请人群信息失败!")
}
}
//同步同意都清标志
user.PopedFlag = model.NO
dao.UpdateEntity(db, user, "PopedFlag")
return err
}
type GetUserSerachKeywordResult struct {
AllSpan []*model.UserSearch `json:"allSpan"`
UserSpan []*model.UserSearch `json:"userSpan"`
}
func GetUserSerachKeyword(ctx *jxcontext.Context) (getUserSerachKeywordResult *GetUserSerachKeywordResult, err error) {
var (
db = dao.GetDB()
userID = ctx.GetUserID()
userSearchAll []*model.UserSearch
userSearch []*model.UserSearch
)
getUserSerachKeywordResult = &GetUserSerachKeywordResult{}
sql := `
SELECT keyword, SUM(count) count FROM user_search WHERE created_at > ? GROUP BY 1 ORDER BY SUM(count) DESC LIMIT 20
`
sqlParams := []interface{}{time.Now().AddDate(0, -1, 0)}
err = dao.GetRows(db, &userSearchAll, sql, sqlParams)
getUserSerachKeywordResult.AllSpan = userSearchAll
sql2 := `
SELECT keyword, SUM(count) count FROM user_search WHERE created_at > ? AND user_id = ? GROUP BY 1 ORDER BY SUM(count) DESC LIMIT 20
`
sqlParams2 := []interface{}{time.Now().AddDate(0, -1, 0), userID}
err = dao.GetRows(db, &userSearch, sql2, sqlParams2)
getUserSerachKeywordResult.UserSpan = userSearch
return getUserSerachKeywordResult, err
}

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

View File

@@ -1,15 +1,20 @@
package event
import (
"fmt"
"regexp"
"strings"
"sync"
"time"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/dao"
"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"
"github.com/gorilla/websocket"
)
var (
@@ -19,12 +24,161 @@ var (
"UpdateUser": "UpdateUser",
}
regexpToken = regexp.MustCompile(`,"token":".*"`)
wsClient = &WSClient{}
//广播频道(通道)
broadcast = make(chan *model.ImMessageRecord)
)
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) {
var (
apiFunction string
@@ -129,3 +283,506 @@ func GetOperateEvents(ctx *jxcontext.Context, name string, apiFunctions []string
}
return pageInfo, err
}
func CreateMessageGroup(ctx *jxcontext.Context, userID, userID2, groupName string, dividePercentage, quitPrice int) (messageGroupResult *dao.GetMessageGroupsResult, err error) {
var (
db = dao.GetDB()
groupID int
)
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,
}
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)
}
}
}
} 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)
}
}
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 messageGroupResult, err
}
func GetMessageGroupByUser(ctx *jxcontext.Context, userID string) (messageGroupResult []*dao.GetMessageGroupsResult, err error) {
var (
db = dao.GetDB()
)
messageGroups, err := dao.GetMessageGroups(db, "", model.SysGroupID, 0, false, "")
messageGroups2, err := dao.GetMessageGroups(db, userID, 0, 0, true, "")
messageGroups = append(messageGroups, messageGroups2...)
messageGroupMembers, err := dao.GetMessageGroupMembers(db, 0, 0, userID)
for _, v := range messageGroupMembers {
if messageGroupList, err := dao.GetMessageGroups(db, "", v.GroupID, 0, false, ""); err == nil {
messageGroups = append(messageGroups, messageGroupList...)
}
}
for _, v := range messageGroups {
//是这个人创建的群聊,如果是单聊就返回对方的头像
if v.Type == model.GroupTypeSingle {
var userID2 string
if v.UserID == userID {
userID2 = v.MessageGroupMembers[0].MemberUserID
} else {
userID2 = userID
}
if user, err := dao.GetUserByID(db, "user_id", userID2); err == nil {
v.Avatar = user.Avatar
v.Name = user.Name
}
}
var (
imMessageRecord *model.ImMessageRecord
sql string
sqlParams = []interface{}{}
)
if v.GroupID != model.SysGroupID {
//最后一条记录和时间和人
sql = `
SELECT * FROM im_message_record WHERE group_id = ? ORDER BY created_at DESC LIMIT 1
`
sqlParams = append(sqlParams, v.GroupID)
} else {
//最后一条记录和时间和人
sql = `
SELECT * FROM im_message_record WHERE group_id = ? AND to_user_id = ? ORDER BY created_at DESC LIMIT 1
`
sqlParams = append(sqlParams, v.GroupID, userID)
}
if err = dao.GetRow(db, &imMessageRecord, sql, sqlParams); err == nil {
v.LastTime = imMessageRecord.CreatedAt
v.LastContent = imMessageRecord.Content
v.LastMessageType = imMessageRecord.MessageType
if user3, err := dao.GetUserByID(db, "user_id", imMessageRecord.UserID); err == nil {
v.LastUserName = user3.Name
}
} else {
err = nil
}
//该用户各组的未读消息数
var unReadCount int
if messageGroupReads, err := dao.GetMessageGroupRead(db, userID, v.GroupID); err == nil && len(messageGroupReads) > 0 {
for _, vv := range messageGroupReads {
unReadCount += vv.UnReadCount
}
}
v.UnReadMessageCount = unReadCount
}
return messageGroups, err
}
func AddMessageGroup(ctx *jxcontext.Context, groupID int, userID string) (err error) {
var (
db = dao.GetDB()
)
messageGroupMembers, err := dao.GetMessageGroupMembers(db, groupID, 0, userID)
messageGroupMembers3, err := dao.GetMessageGroupMembers(db, 0, 0, userID)
messageGroupsResult, err := dao.GetMessageGroups(db, userID, groupID, model.GroupTypeMulit, false, "")
messageGroupsResult2, err := dao.GetMessageGroups(db, "", groupID, model.GroupTypeMulit, false, "")
messageGroupsResult3, err := dao.GetMessageGroups(db, userID, 0, model.GroupTypeMulit, false, "")
messageGroupMembers2, err := dao.GetMessageGroupMembers(db, groupID, 0, "")
if err != nil {
return err
}
if len(messageGroupMembers) > 0 {
return fmt.Errorf("此用户已经在该群组中了!")
}
if len(messageGroupMembers3) > 0 {
return fmt.Errorf("您已经有群组[%v]了,不能申请加入其它群!", messageGroupMembers3[0].GroupID)
}
if len(messageGroupsResult) > 0 {
return fmt.Errorf("请不要加入自己创建的群!")
}
if len(messageGroupsResult2) > 0 && len(messageGroupMembers2) > 0 {
if len(messageGroupMembers2)+1 > messageGroupsResult2[0].MaxCount {
return fmt.Errorf("抱歉该群组已经满员了!")
}
}
if len(messageGroupsResult3) > 0 {
return fmt.Errorf("您已经拥有[%v]群了,不能再加入其它群!", messageGroupsResult3[0].GroupID)
}
messageGroupMember := &model.MessageGroupMember{
GroupID: groupID,
MemberUserID: userID,
Type: model.GroupMemberTypeNormal,
}
dao.WrapAddIDCULDEntity(messageGroupMember, ctx.GetUserName())
if err = dao.CreateEntity(db, messageGroupMember); err == nil {
messageGroupRead := &model.MessageGroupRead{
GroupID: groupID,
UserID: userID,
}
dao.WrapAddIDCULEntity(messageGroupRead, ctx.GetUserName())
if err = dao.CreateEntity(db, messageGroupRead); err == nil {
if messageGroupReads, err := dao.GetMessageGroupRead(db, userID, model.SysGroupID); len(messageGroupReads) == 0 && err == nil {
messageGroupRead := &model.MessageGroupRead{
GroupID: model.SysGroupID,
UserID: userID,
}
dao.WrapAddIDCULEntity(messageGroupRead, ctx.GetUserName())
dao.CreateEntity(db, messageGroupRead)
}
}
}
return err
}
func UpdateMessageGroup(ctx *jxcontext.Context, groupID int, payload map[string]interface{}) (num int64, err error) {
var (
db = dao.GetDB()
messageGroup = &model.MessageGroup{
GroupID: groupID,
}
)
if err = dao.GetEntity(db, messageGroup, "GroupID"); err != nil {
return 0, err
}
if messageGroup.UserID != ctx.GetUserID() {
return 0, fmt.Errorf("只有群主才能修改群信息!")
}
valid := dao.StrictMakeMapByStructObject(payload, messageGroup, ctx.GetUserName())
if len(valid) > 0 {
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, txDB)
panic(r)
}
}()
if num, err = dao.UpdateEntityLogically(db, messageGroup, valid, ctx.GetUserName(), nil); err != nil {
dao.Rollback(db, txDB)
return 0, err
}
dao.Commit(db, txDB)
}
return num, err
}
func DeleteMessageGroup(ctx *jxcontext.Context, groupID int, userID string, flag bool) (errCode string, err error) {
var (
db = dao.GetDB()
messageGroup = &model.MessageGroup{
GroupID: groupID,
}
)
if err = dao.GetEntity(db, messageGroup, "GroupID"); err != nil {
return errCode, err
}
//解散群
if flag {
if messageGroup.UserID != ctx.GetUserID() {
return errCode, fmt.Errorf("只有群主才能解散群!")
}
messageGroup.DeletedAt = time.Now()
messageGroup.LastOperator = ctx.GetUserName()
dao.UpdateEntity(db, messageGroup, "DeletedAt", "LastOperator")
messageGroupMembers, _ := dao.GetMessageGroupMembers(db, groupID, 0, "")
for _, v := range messageGroupMembers {
v.DeletedAt = time.Now()
v.LastOperator = ctx.GetUserName()
dao.UpdateEntity(db, v, "DeletedAt", "LastOperator")
}
} else {
//token中用户与传入user不一致就判定为踢人
if ctx.GetUserID() != userID {
if messageGroup.UserID != ctx.GetUserID() {
messageGroupMembers, err := dao.GetMessageGroupMembers(db, groupID, 0, ctx.GetUserID())
if err != nil {
return errCode, err
}
if messageGroupMembers[0].Type == model.GroupMemberTypeNormal {
return errCode, fmt.Errorf("只有创建者和管理员才能踢人!")
}
}
} else {
quitPrice := messageGroup.QuitPrice
userBill, err := dao.GetUserBill(db, userID, "")
userBillGroupMaster, err := dao.GetUserBill(db, messageGroup.UserID, "")
if err != nil {
return errCode, err
}
if userBill.AccountBalance < quitPrice {
return model.ErrCodeAccountBalanceNotEnough, fmt.Errorf("用户余额不足,请充值!")
}
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, txDB)
panic(r)
}
}()
//账户支出
if err = financial.AddExpendUpdateAccount(txDB, userBill, model.BillTypeQuitGroup, quitPrice, 0); err != nil {
dao.Rollback(db, txDB)
return errCode, err
}
//群主收到退团金额
if err = financial.AddIncomeUpdateAccount(txDB, userBillGroupMaster, model.BillTypeQuitGroup, quitPrice, 0); err != nil {
dao.Rollback(db, txDB)
return errCode, err
}
dao.Commit(db, txDB)
}
messageGroupMembers, err := dao.GetMessageGroupMembers(db, groupID, 0, userID)
if err != nil {
return errCode, err
}
messageGroupMembers[0].DeletedAt = time.Now()
messageGroupMembers[0].LastOperator = ctx.GetUserName()
dao.UpdateEntity(db, messageGroupMembers[0], "DeletedAt", "LastOperator")
}
return errCode, err
}
func TransferMessageGroupMaster(ctx *jxcontext.Context, groupID int, userID string) (err error) {
var (
db = dao.GetDB()
messageGroup = &model.MessageGroup{
GroupID: groupID,
}
)
if err = dao.GetEntity(db, messageGroup, "GroupID"); err != nil {
return err
}
if messageGroup.UserID != ctx.GetUserID() {
return fmt.Errorf("只有群主才能转让群主!")
}
//群主换成选的那个人
messageGroup.UserID = userID
messageGroup.LastOperator = ctx.GetUserName()
//之前那个群成员换成之前的群主
messageGroupMembers, err := dao.GetMessageGroupMembers(db, groupID, 0, userID)
if err != nil && len(messageGroupMembers) == 0 {
return err
}
messageGroupMember := messageGroupMembers[0]
messageGroupMember.MemberUserID = ctx.GetUserID()
messageGroupMember.LastOperator = ctx.GetUserName()
txDB, _ := dao.Begin(db)
defer func() {
if r := recover(); r != nil {
dao.Rollback(db, txDB)
panic(r)
}
}()
if _, err = dao.UpdateEntity(db, messageGroup, "UserID", "LastOperator"); err != nil {
dao.Rollback(db, txDB)
return err
}
if _, err = dao.UpdateEntity(db, messageGroupMember, "MemberUserID", "LastOperator"); err != nil {
dao.Rollback(db, txDB)
return err
}
dao.Commit(db, txDB)
return err
}
func SendSysMessageSimple(content, toUserID string) (err error) {
return SendSysMessage(jxcontext.AdminCtx, &model.ImMessageRecord{
Content: sysMessageTitle + " " + content,
ToUserID: toUserID,
GroupID: model.SysGroupID,
MessageType: 1, // 普通文字消息
})
}
func SendSysMessage(ctx *jxcontext.Context, imMessageRecord *model.ImMessageRecord) (err error) {
var (
db = dao.GetDB()
userID = imMessageRecord.ToUserID
groupID = imMessageRecord.GroupID
)
if groupID != model.SysGroupID {
return fmt.Errorf("只能给系统组发消息!")
}
imMessageRecord.CreatedAt = time.Now()
imMessageRecord.LastOperator = ctx.GetUserName()
imMessageRecord.DeletedAt = utils.DefaultTimeValue
imMessageRecord.UpdatedAt = utils.DefaultTimeValue
imMessageRecord.Seq = time.Now().Unix()
err = dao.CreateEntity(db, imMessageRecord)
if userID == "" {
//循环map客户端
for _, client := range wsClient.Clients[groupID] {
globals.SugarLogger.Debugf("msg %v", utils.Format4Output(imMessageRecord, false))
err = client.WriteJSON(imMessageRecord)
if err != nil {
globals.SugarLogger.Debugf("client.WriteJSON error: %v", err)
client.Close() //关闭
// delete(wsClient.Clients[msg.GroupID], userID)
}
}
} else {
client := wsClient.Clients[groupID][userID]
globals.SugarLogger.Debugf("msg %v", utils.Format4Output(imMessageRecord, false))
if client == nil {
return
}
err = client.WriteJSON(imMessageRecord)
if err != nil {
globals.SugarLogger.Debugf("client.WriteJSON error: %v", err)
client.Close() //关闭
// delete(wsClient.Clients[msg.GroupID], userID)
}
}
return err
}
func DeleteMessageRecord(ctx *jxcontext.Context) (err error) {
var (
db = dao.GetDB()
)
sql := `
DELETE FROM im_message_record WHERE created_at < ? AND group_id <> ?
`
sqlParams := []interface{}{
time.Now().AddDate(0, 0, -3), model.SysGroupID,
}
_, err = dao.ExecuteSQL(db, sql, sqlParams)
return err
}
func UpdateUserMessageGroupRead(ctx *jxcontext.Context, reads []*model.MessageGroupRead) (err error) {
var (
db = dao.GetDB()
userID = ctx.GetUserID()
)
for _, v := range reads {
if messageReads, err := dao.GetMessageGroupRead(db, userID, v.GroupID); err == nil {
if len(messageReads) > 0 {
messageReads[0].UnReadCount += v.UnReadCount
dao.UpdateEntity(db, messageReads[0], "UnReadCount")
} else {
}
}
}
return err
}
type GetUserStatisticsResult struct {
RegisterUserCount int `json:"registerUserCount"` //注册数
OnlineUserCount int `json:"onlineUserCount"` //在线用户数
ConsumeUserCount int `json:"consumeUserCount"` //消费用户数
MemberUserCount int `json:"memberUserCount"` //会员用户数
}
func GetUserStatistics(ctx *jxcontext.Context) (getUserStatisticsResult *GetUserStatisticsResult, err error) {
var (
db = dao.GetDB()
)
getUserStatisticsResult = &GetUserStatisticsResult{}
sql := `
SELECT a.member_user_count, b.consume_user_count FROM
( SELECT DISTINCT COUNT(a.user_id) member_user_count
FROM user a
JOIN user_member b ON a.user_id = b.user_id AND b.deleted_at = ? )a,
( SELECT DISTINCT COUNT(a.user_id) consume_user_count
FROM user a
JOIN ` + "`order`" + `b ON a.user_id = b.user_id AND b.status = ?)b
`
sqlParams := []interface{}{
utils.DefaultTimeValue, model.OrderStatusFinished,
}
err = dao.GetRow(db, &getUserStatisticsResult, sql, sqlParams)
paged, _ := dao.GetUsers2(db, "", "", 0, "", utils.ZeroTimeValue, utils.ZeroTimeValue, 0, nil, nil, 0, -1)
getUserStatisticsResult.RegisterUserCount = paged.TotalCount
getUserStatisticsResult.OnlineUserCount = GetOnlineUserCount()
return getUserStatisticsResult, err
}

View File

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

View File

@@ -0,0 +1,373 @@
package event
import (
"encoding/hex"
"errors"
"fmt"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/globals"
"io"
"net"
"strings"
"time"
"unicode/utf8"
)
// ConnRead 获取链接数据
func ConnRead(c net.Conn) ([]byte, int, error) {
buffer := make([]byte, 1024*2)
n, err := c.Read(buffer)
return buffer, n, err
}
// ListenTcp 入口
func ListenTcp() {
l, err := net.Listen("tcp", ":8000")
if err != nil {
fmt.Println("listen error:", err)
return
}
for {
c, err := l.Accept()
if err != nil || c == nil {
fmt.Println("accept error:", err)
break
}
fn := func() {
// 捕获异常 防止waitGroup阻塞
defer func() {
if err := recover(); err != nil {
fmt.Println("recover err = ", err)
return
}
}()
if err := handleConn(c); err != nil {
c.Close()
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)
PrintIpAndAddr.DelPrintIpAndAddr(pn)
PrintObject.DelPrintObj(printNo)
} else if pn != "" {
printStatusOff[pn] = 1
}
}
}
return err
}
//看是心跳还是打印回调
data := hex.EncodeToString(buffer[:n])
var (
printNo string = "" //打印机编号
heartbeat bool = false
callback bool = false
)
if strings.Contains(data, heartText) || strings.Contains(data, heartTextNew) {
printNoData, _ := hex.DecodeString(data[len(heartText) : len(data)-8])
printNo = string(printNoData)
heartbeat = true
} else if strings.Contains(data, printText) || strings.Contains(data, printTextNew) { //打印回调
_, printNo = getCallbackMsgInfo(data)
callback = true
}
t, ok := PrintObject.GetPrintObj(printNo)
if !ok || t.Clients[printNo] == nil || time.Now().Sub(t.Clients[printNo].StatusTime).Seconds() >= 120 {
t = NewTcpClient()
}
if heartbeat {
// 证明是心跳
Heartbeat(c, t, data, printNo, printRemoteAddr)
} else if callback {
// 打印回调
Callback(c, t, data, printNo)
}
}
}
func (t *TcpClient) printFail() (err error) {
//新开机的打印失败和错误的
var (
db = dao.GetDB()
)
prints, _ := dao.GetPrintMsgs(db, "", []int{printMsgFail, printMsgErr, PrintMsgAlreadyLoad, printMsgAlreadySend}, time.Now().Add(-time.Hour*3), time.Now(), 0, 999)
for _, printMsg := range prints {
t.addMsgChan(printMsg)
}
return err
}
func (t *TcpClient) changePrintMsg(data string, orderNo int64, printNo string) (err error) {
var (
db = dao.GetDB()
comment string
status int
)
//1、先找出打印机编号和订单序列号这两个确定唯一一条消息?
//通过参数传进来
//2、打印成功改变打印表的状态
if strings.Contains(data, printSuccessText) || strings.Contains(data, printSuccessTextNew) {
status = printMsgSuccess
comment = "回调成功,修改打印状态"
} else {
//打印失败也改变状态并更新失败原因
status = printMsgFail
comment = printErrMap[data[12:14]]
}
//这里序号重复会有问题
if printMsgs, err := dao.GetPrintMsgNoPage(db, printNo, orderNo); err != nil {
globals.SugarLogger.Debugf("changePrintMsg err :[%v]", err)
return err
} else if len(printMsgs) == 0 {
globals.SugarLogger.Debugf("changePrintMsg err ,not found printMsg printNo:[%v], orderNo :[%v]", printNo, orderNo)
} else if len(printMsgs) > 0 {
for _, v := range printMsgs {
v.Comment = comment
v.Status = status
dao.UpdateEntity(db, v, "Comment", "Status")
}
}
return err
}
func HandleTcpMessages(t *TcpClient, printNo string) {
var (
db = dao.GetDB()
offset, pageSize = 0, 10
)
if !t.isExistMsg(printNo) {
return
}
fn := func() {
//for {
// time.Sleep(2 * time.Second)
if t.TimeoutMap[printNo] == true {
timeNow := time.Now()
timeStart := time.Date(timeNow.Year(), timeNow.Month(), timeNow.Day(), 0, 0, 0, 0, timeNow.Location())
timeEnd := time.Date(timeNow.Year(), timeNow.Month(), timeNow.Day(), 23, 59, 59, 0, timeNow.Location())
prints, _ := dao.GetPrintMsgs(db, printNo, []int{PrintMsgWait}, timeStart.AddDate(0, 0, -1), timeEnd, offset, pageSize)
for _, printMsg := range prints {
printMsg.Status = PrintMsgAlreadyLoad
//先避免重复读再插到channel
if _, err := dao.UpdateEntity(db, printMsg, "Status"); err == nil {
if err = t.addMsgChan(printMsg); err != nil {
globals.SugarLogger.Debugf("HandleTcpMessages addMsgChan Err: %v", err)
}
}
}
} else {
globals.SugarLogger.Debugf("HandleTcpMessages timeout")
return
}
}
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 {
t.getClients(key).C.Close()
close(t.MsgMap[key])
close(t.CallBackMap[key])
//t.delConn(key)
t.clear(key)
// 链接出错,彻底删除换成
if printRemoteAddrIP, have := PrintIpAndAddr.GetPrintIpAndAddr(key); have {
PrintIpAndAddr.DelPrintIpAndAddr(key)
PrintAddrAndIp.DelPrintAddrAndIp(printRemoteAddrIP)
PrintObject.DelPrintObj(key)
}
return
}
}

View File

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

View File

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

View File

@@ -0,0 +1,104 @@
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() {
w.quit <- true
close(w.quit)
//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) AddJob(job Job) {
p.wg.Add(1)
go func() {
p.jobChannel <- func() {
defer p.wg.Done()
job()
}
}()
}
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

@@ -0,0 +1,410 @@
package financial
import (
"crypto/hmac"
"crypto/md5"
"crypto/sha256"
"encoding/json"
"fmt"
"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/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/globals"
"git.rosy.net.cn/jx-callback/globals/api"
)
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 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
}
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 {
p.Order.Status = model.OrderStatusCanceled
}
dao.UpdateEntity(dao.GetDB(), p.Order)
if result.ReturnMsg == "" {
err = OnCashFinished(p.Order)
}
} else {
return err2
}
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 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 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

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

View File

@@ -1,15 +1,76 @@
package misc
import (
"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/jxstore/event"
"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/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/globals"
)
func Init() {
var (
dailyWorkTimeList = []string{
"00:18:35",
}
stationTimeList = []string{
"11:35:00",
}
startDeleteTime = []string{
"04:00:00",
}
)
func Init() {
if globals.IsMainProductEnv() {
//拼多多订单轮询
ScheduleTimerFuncByInterval(func() {
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() {
bidaServer.UpdateOrderStatus()
}, 5*time.Second, 2*time.Hour)
}
}
func doDailyWork() {
globals.SugarLogger.Debug("doDailyWork")
//刷新任务过期状态
cms.RefreshJobStatus(jxcontext.AdminCtx)
//刷新任务标签状态
cms.RefreshJobSpan(jxcontext.AdminCtx)
//刷新用户会员时间
cms.RefreshUserMemberStatus(jxcontext.AdminCtx)
//删除聊天记录
event.DeleteMessageRecord(jxcontext.AdminCtx)
//自动确认收货(刷新状态)
cms.RefreshDropShippingJob(jxcontext.AdminCtx)
//刷新京东快递
cms.RefreshJdDelivery(jxcontext.AdminCtx)
//美团联盟活动自动创建
cms.MtUnionJobAutoUpdate(jxcontext.AdminCtx)
}
// 按时间序列循环

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

@@ -4,8 +4,8 @@ import (
"fmt"
"sync"
"git.rosy.net.cn/jx-callback/business/dao"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/business/model/legacymodel"
)
@@ -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,18 +3,22 @@ package datares
import (
"bytes"
"fmt"
"git.rosy.net.cn/jx-callback/globals/api"
"github.com/qiniu/api.v7/storage"
"image"
"image/gif"
"image/jpeg"
"image/png"
"net/http"
"git.rosy.net.cn/jx-callback/business/dao"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/globals"
//"git.rosy.net.cn/jx-callback/globals/api"
//"github.com/qiniu/api.v7/storage"
)
const (
@@ -48,24 +52,23 @@ func Binary2Image(binaryData []byte, mimeType string) (img image.Image, outMimeT
}
func GetQiniuUploadToken(ctx *jxcontext.Context, suffix, hashCode string) (upTokenInfo *UploadResTokenInfo, err error) {
//imgURL := ""
//if hashCode != "" {
// imgURL, _ = GetDataResource(ctx, hashCode)
//}
//
//putPolicy := storage.PutPolicy{
// Scope: globals.QiniuBucket,
// Expires: qiniuTokenExpires,
//}
//upTokenInfo = &UploadResTokenInfo{
// Token: putPolicy.UploadToken(api.QiniuAPI),
// Expires: putPolicy.Expires,
// FileName: jxutils.GenPicFileName(suffix),
// Hit: imgURL != "",
// Img: imgURL,
//}
//return upTokenInfo, err
return nil, err
imgURL := ""
if hashCode != "" {
imgURL, _ = GetDataResource(ctx, hashCode)
}
putPolicy := storage.PutPolicy{
Scope: globals.QiniuBucket,
Expires: qiniuTokenExpires,
}
upTokenInfo = &UploadResTokenInfo{
Token: putPolicy.UploadToken(api.QiniuAPI),
Expires: putPolicy.Expires,
FileName: jxutils.GenPicFileName(suffix),
Hit: imgURL != "",
Img: imgURL,
}
return upTokenInfo, err
}
// 此函数要求resBinary不能空mimeType与hashCode必须是正确的

View File

@@ -1,7 +1,6 @@
package datares
import (
"fmt"
"testing"
"git.rosy.net.cn/baseapi/utils"
@@ -14,13 +13,13 @@ func init() {
testinit.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

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

View File

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

View File

@@ -106,7 +106,7 @@ func (h *Hub) GetToken(tokenType, oldToken string, waitTime time.Duration) (toke
token = string(utils.MustMarshal(weimobToken))
}
case EventTypePushToken:
token = api.PushAPI.CBGetToken()
//token = api.PushAPI.CBGetToken()
}
if token != oldToken {

View File

@@ -7,6 +7,7 @@ import (
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/auth2"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/business/model/dao"
"git.rosy.net.cn/jx-callback/globals"
)
@@ -73,10 +74,9 @@ 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 {
if !globals.IsProductEnv() {
err = nil
} else if token == RsmDefultToken {
err = nil
} else {
errCode = model.ErrCodeTokenIsInvalid
@@ -162,3 +162,14 @@ func (ctx *Context) GetUserID() (userID string) {
}
return userID
}
func (ctx *Context) GetFullUser() (user *model.User) {
token := ctx.GetToken()
authInfo, err2 := auth2.GetTokenInfo(token)
if err2 == nil {
if authInfo.TokenType == auth2.TokenTypeNormal {
user, _ = dao.GetUserByID(dao.GetDB(), "user_id", authInfo.GetID())
}
}
return user
}

View File

@@ -1,20 +1,31 @@
package jxutils
import (
"bytes"
"context"
"crypto/aes"
"crypto/md5"
"encoding/base64"
"fmt"
"golang.org/x/text/encoding/simplifiedchinese"
"golang.org/x/text/transform"
"io/ioutil"
"math"
"math/rand"
"regexp"
"strconv"
"strings"
"time"
"git.rosy.net.cn/baseapi"
"git.rosy.net.cn/baseapi/platformapi/autonavi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/baseapi/utils/routinepool"
"git.rosy.net.cn/jx-callback/business/jxutils/excel"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/jx-callback/globals/api"
"github.com/qiniu/api.v7/storage"
)
var (
@@ -34,14 +45,6 @@ var (
"image-star.elemecdn.com",
},
}
letterBytes = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
flowUnitMap = map[string]string{
"KB": "KB",
"MB": "MB",
"GB": "GB",
}
)
const fileExt = ".xlsx"
@@ -57,12 +60,69 @@ func init() {
orderNoBeginTimestamp = utils.Str2Time("2010-01-01 00:00:00").Unix()
}
func RandStringBytes(n int) string {
b := make([]byte, n)
for i := range b {
b[i] = letterBytes[rand.Intn(len(letterBytes))]
func GetSaleStoreIDFromAfsOrder(order *model.AfsOrder) (retVal int) {
if order.JxStoreID > 0 {
return order.JxStoreID
}
return string(b)
return order.StoreID
}
func GetSkuIDFromOrderSkuFinancial(sku *model.OrderSkuFinancial) (skuID int) {
if sku.JxSkuID > 0 {
return sku.JxSkuID
}
return sku.SkuID
}
func SplitUniversalOrderID(universalOrderID string) (orderID string, vendorID int) {
index := strings.Index(universalOrderID, "|")
if index != -1 {
orderID = universalOrderID[:index]
vendorID = int(utils.Str2Int64(universalOrderID[index+1:]))
} else {
if vendorID = GetPossibleVendorIDFromVendorOrderID(universalOrderID); vendorID == model.VendorIDUnknown {
// globals.SugarLogger.Errorf("unkown order type:%v", universalOrderID)
panic(fmt.Sprintf("unkown order type, orderID:%s", universalOrderID))
}
orderID = universalOrderID
}
return orderID, vendorID
}
func GetPossibleVendorIDFromVendorOrderID(vendorOrderID string) (vendorID int) {
vendorID = model.VendorIDUnknown
if vendorOrderIDInt64 := utils.Str2Int64WithDefault(vendorOrderID, 0); vendorOrderIDInt64 > 0 {
orderIDLen := len(vendorOrderID)
// 5287873015048 13 wsc
// 15380342248732 14 old ebai order
// 800402581000221 15,16 jd order
// 33437032333978492 17 mtwm order
// 3022716176275221584 19 elm order, new ebai order
// 京东到家从2020年开始订单号的长度都会在现有基础上加一位订单号的前两位取的是当年的最后两位数2020取的20以适应业务的发展。
// 改造点:
// 1、订单号位数变化由原有15位数增加1位数调整为16位数对接商家需检查是否有对订单号位数做长度校验。
// 2、第一位数字发生变化由原来9开头调整为当年年份后两位数如2020年订单开头为20
if orderIDLen == len("925265130002541") || orderIDLen == len("1925265130002541") {
vendorID = model.VendorIDJD
} else if orderIDLen == len("3022716176275221584") {
// vendorID = model.VendorIDELM
vendorID = model.VendorIDEBAI // 饿百零售开放平台订单接口中订单ID“order_id”字段长度将调整为19位和饿了么订单ID“eleme_order_id”字段格式保持一致。
} else if orderIDLen == len("15380342248732") {
if vendorOrderID[:2] == "88" {
vendorID = model.VendorIDJX
} else {
vendorID = model.VendorIDEBAI
}
} else if orderIDLen == len("33437032333978492") {
vendorID = model.VendorIDMTWM
} else if orderIDLen == len("1000004390") {
vendorID = model.VendorIDJX
} else if orderIDLen == len("124557362562000001") || orderIDLen == len("13153183146800000100") {
vendorID = model.VendorIDJDShop
}
}
return vendorID
}
func GenRand6() (num int) {
@@ -84,6 +144,85 @@ func GenOrderNo() (orderNo int64) {
return orderNo
}
func GenJobOrderNo() (orderNo int64) {
const prefix = 88
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 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
orderNo = time.Now().Unix() - orderNoBeginTimestamp
orderNo = orderNo * randPartNum
md5Bytes := md5.Sum([]byte(utils.GetUUID()))
randPart := 0
for k, v := range md5Bytes {
randPart += int(v) << ((k % 3) * 8)
}
orderNo += int64(randPart % randPartNum)
orderNo += int64(math.Pow10(int(math.Log10(float64(orderNo)))+1)) * prefix
return orderNo
}
func GetPossibleVendorIDFromAfsOrderID(afsOrderID string) (vendorID int) {
vendorID = model.VendorIDUnknown
if afsOrderIDInt64 := utils.Str2Int64WithDefault(afsOrderID, 0); afsOrderIDInt64 > 0 {
orderIDLen := len(afsOrderID)
if orderIDLen == len("22586438") { // 8
vendorID = model.VendorIDJD
} else if orderIDLen == len("1413138834") { // 10
vendorID = model.VendorIDEBAI
} else if orderIDLen == len("29488498752") { // 11
vendorID = model.VendorIDMTWM
}
}
return vendorID
}
func ComposeUniversalOrderID(orderID string, vendorID int) string {
// return fmt.Sprintf("%s|%d", orderID, vendorID)
return orderID // 当前用长度就能区分先不加上vendorID
}
// distance单位为米
func ConvertDistanceToLogLat(lng, lat, distance, angle float64) (newLng, newLat float64) {
oneDu := 111319.55 // 单位为米
@@ -108,6 +247,16 @@ func EarthDistance(lng1, lat1, lng2, lat2 float64) float64 {
return dist * radius
}
// 返回结果单元为公里
func WalkingDistance(lng1, lat1, lng2, lat2 float64) (distance float64) {
if distance = api.AutonaviAPI.WalkingDistance(lng1, lat1, lng2, lat2); distance == 0 {
distance = EarthDistance(lng1, lat1, lng2, lat2) * 1.4
} else {
distance /= 1000
}
return distance
}
func StandardCoordinate2Int(value float64) int {
return int(math.Round(value * 1000000))
}
@@ -116,6 +265,25 @@ func IntCoordinate2Standard(value int) float64 {
return float64(value) / 1000000
}
func IntCoordinate2MarsStandard(gpsLng, gpsLat int, coordinateType int) (marsLng, marsLat float64, err error) {
marsLng = IntCoordinate2Standard(gpsLng)
marsLat = IntCoordinate2Standard(gpsLat)
coordSys := ""
switch coordinateType {
case model.CoordinateTypeGPS:
coordSys = autonavi.CoordSysGPS
case model.CoordinateTypeMars:
return marsLng, marsLat, nil
case model.CoordinateTypeBaiDu:
coordSys = autonavi.CoordSysBaidu
case model.CoordinateTypeMapbar:
coordSys = autonavi.CoordSysMapbar
default:
panic(fmt.Sprintf("known coordinate type:%d", coordinateType))
}
return api.AutonaviAPI.CoordinateConvert(marsLng, marsLat, coordSys)
}
func IntPrice2Standard(value int64) float64 {
return float64(value) / 100
}
@@ -417,6 +585,49 @@ func Strings2Objs(strAndObjAddPairs ...interface{}) (err error) {
return nil
}
func RefreshAfsOrderSkuRelated(afsOrder *model.AfsOrder) *model.AfsOrder {
afsOrder.SkuUserMoney = 0
afsOrder.PmSkuSubsidyMoney = 0
for _, orderSku := range afsOrder.Skus {
if orderSku.SkuID > math.MaxInt32 {
orderSku.SkuID = orderSku.JxSkuID
}
afsOrder.SkuUserMoney += orderSku.UserMoney
afsOrder.PmSkuSubsidyMoney += orderSku.PmSkuSubsidyMoney
}
return afsOrder
}
func UploadExportContent(content []byte, key string) (downloadURL string, err error) {
putPolicy := storage.PutPolicy{
Scope: globals.QiniuBucket,
Expires: 10 * 60,
DeleteAfterDays: 1,
}
upToken := putPolicy.UploadToken(api.QiniuAPI)
cfg := &storage.Config{}
formUploader := storage.NewFormUploader(cfg)
ret := storage.PutRet{}
for i := 0; i < 3; i++ {
if err = formUploader.Put(context.Background(), &ret, upToken, key, bytes.NewReader(content), int64(len(content)), &storage.PutExtra{}); err == nil {
break
}
}
if err == nil {
downloadURL = ComposeQiniuResURL(key)
}
return downloadURL, err
}
func UploadExeclAndPushMsg(sheetList []*excel.Obj2ExcelSheetConfig, name string) (downloadURL, fileName string, err error) {
excelBin := excel.Obj2Excel(sheetList)
timeStr := utils.Int64ToStr(time.Now().Unix())
fileName = name + timeStr + fileExt
baseapi.SugarLogger.Debugf("WriteToExcel:save %s success", fileName)
downloadURL, err = UploadExportContent(excelBin, fileName)
return downloadURL, fileName, err
}
func TaskResult2Hint(resultList []interface{}) (hint string) {
strList := make([]string, len(resultList))
for k, v := range resultList {
@@ -612,6 +823,25 @@ func PKCS5UnPadding(origData []byte) []byte {
return origData[:(length - unpadding)]
}
//合成水印图
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
}
}
}
return imgMix
}
func GetIssue() (issue int) {
year, month, _ := time.Now().Date()
return year*100 + int(month)
@@ -674,47 +904,26 @@ func GetWeekTime() (weekTimeBegin, weekTimeEnd time.Time) {
return weekTimeBegin, weekTimeEnd
}
func BuildErr(errs []error) (err error) {
var errStr = strings.Builder{}
for _, v := range errs {
errStr.WriteString(v.Error())
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 fmt.Errorf(errStr.String())
return
}
func SplitFlowAndUnit(flowStr string) (flow float64, unit string) {
for _, v := range flowUnitMap {
if strings.Contains(flowStr, v) {
return utils.Str2Float64WithDefault(flowStr[:len(flowStr)-2], 0), flowStr[len(flowStr)-2:]
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 flow, unit
}
func Flow2KB(flow float64, unit string) (flowKB float64) {
if unit == "KB" {
return flow
} else if unit == "MB" {
return flow * 1024
} else if unit == "GB" {
return flow * 1024 * 1024
}
return flowKB
}
func FlowKB2Other(flowKB float64) (flow float64, unit string) {
if flowKB < 1024 {
return flowKB, "KB"
} else {
flowMB := math.Round(flowKB / float64(1024))
if flowMB < 1024 {
return flowMB, "MB"
} else {
flowGB := math.Round(flowMB / float64(1024))
if flowGB < 1024 {
return flowGB, "GB"
}
}
}
return flow, unit
return bHex
}

View File

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

View File

@@ -20,6 +20,7 @@ import (
"git.rosy.net.cn/baseapi/platformapi"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/globals"
"github.com/boombuler/barcode"
"github.com/boombuler/barcode/code128"
"github.com/boombuler/barcode/qr"
@@ -96,6 +97,20 @@ func SplitStoreName(fullName, separator, defaultPrefix string) (prefix, bareName
return TrimDecorationChar(prefix), TrimDecorationChar(bareName)
}
func ComposeStoreName(bareName string, vendorID int) (fullName string) {
bareName = TrimDecorationChar(strings.Trim(bareName, "-"))
storeName := globals.StoreName
if vendorID == model.VendorIDJD {
fullName = storeName + "-" + bareName
} else {
if globals.IsMainProductEnv() && model.ShopChineseNames[vendorID] != "" {
storeName = model.ShopChineseNames[vendorID]
}
fullName = storeName + "(" + bareName + ")"
}
return fullName
}
func StrTime2JxOperationTime(strTime string, defValue int16) int16 {
if timeValue, err := time.Parse("15:04:05", strTime); err == nil {
return int16(timeValue.Hour()*100 + timeValue.Minute())
@@ -446,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

@@ -27,7 +27,7 @@ func SendSMSMsg(mobileList []string, signName, templateCode string, templatePara
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)

View File

@@ -8,9 +8,9 @@ import (
"git.rosy.net.cn/baseapi/platformapi"
"git.rosy.net.cn/jx-callback/business/dao"
"git.rosy.net.cn/jx-callback/business/jxutils/eventhub/syseventhub"
"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/api"
@@ -138,60 +138,6 @@ func RefreshWeixinToken() (err error) {
return err
}
func RefreshPushToken() (err error) {
if api.PushAPI != nil {
err = RefreshConfig("push", pushTokenExpires, func() (token string, expireTimeStr string) {
globals.SugarLogger.Debugf("RefreshPushToken RunMode:%s", beego.BConfig.RunMode)
if globals.IsMainProductEnv() {
if tokenInfo, err := api.PushAPI.CBRetrieveToken(); err == nil {
globals.SugarLogger.Debugf("RefreshPushToken tokenInfo:%s", utils.Format4Output(tokenInfo, true))
token = tokenInfo.Token
} else {
globals.SugarLogger.Errorf("RefreshPushToken RefreshToken failed with error:%v", err)
}
} else {
if tokenInfo := getPushTokenFromRemote(api.PushAPI.CBGetToken()); tokenInfo != nil {
expireTimeStr = utils.Time2Str(time.Now().Add(-pushTokenExpires))
token = tokenInfo.Token
}
}
return token, expireTimeStr
}, func(value string) {
globals.SugarLogger.Debugf("RefreshPushToken setter value:%s", value)
syseventhub.SysEventHub.OnNewPushToken(value)
api.PushAPI.CBSetToken(value)
})
}
return err
}
func RefreshWeixin3Token() (err error) {
// if api.WeixinMiniAPI3 != nil {
// err = RefreshConfig("wechat3", weixinTokenExpires, func() (token string, expireTimeStr string) {
// globals.SugarLogger.Debugf("RefreshWeixin3Token RunMode:%s", beego.BConfig.RunMode)
// if globals.IsMainProductEnv() {
// if tokenInfo, err := api.WeixinMiniAPI3.CBRetrieveToken(); err == nil {
// globals.SugarLogger.Debugf("RefreshWeixin3Token tokenInfo:%s", utils.Format4Output(tokenInfo, true))
// token = tokenInfo.AccessToken
// } else {
// globals.SugarLogger.Errorf("RefreshWeixin3Token RefreshToken failed with error:%v", err)
// }
// } else {
// if tokenInfo := getWX3TokenFromRemote(api.WeixinMiniAPI3.CBGetToken()); tokenInfo != nil {
// expireTimeStr = utils.Time2Str(time.Now().Add(-weixinTokenExpires))
// token = tokenInfo.Token
// }
// }
// return token, expireTimeStr
// }, func(value string) {
// globals.SugarLogger.Debugf("RefreshWeixinToken setter value:%s", value)
// syseventhub.SysEventHub.OnNewWX3Token(value)
// api.WeixinMiniAPI3.CBSetToken(value)
// })
// }
return err
}
func RefreshWeimobToken() (err error) {
if api.WeimobAPI != nil {
err = RefreshConfig("weimob", weimobTokenExpires, func() (token string, expireTimeStr string) {

View File

@@ -7,7 +7,9 @@ import (
"sync"
"time"
"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/globals"
)
@@ -474,7 +476,9 @@ func (t *BaseTask) run(taskHandler func()) {
if t.finishHook != nil {
t.finishHook(t)
} else {
SendMessage(t)
if globals.IsMainProductEnv() {
SendMessage(t)
}
}
})
}
@@ -484,20 +488,20 @@ func SendMessage(t *BaseTask) {
time.Sleep(10 * time.Millisecond) // 等待GetResult中的isGetResultCalled赋值
globals.SugarLogger.Debugf("BaseTask task ID:%s, name:%s finished, isGetResultCalled:%t", t.ID, t.Name, t.isGetResultCalled)
if !t.isGetResultCalled && t.parent == nil && len(GetTasks(t.ID, TaskStatusBegin, TaskStatusEnd, 24, "")) > 0 {
//if authInfo, err := t.ctx.GetV2AuthInfo(); err == nil { // 这里应该是不管登录类型,直接以可能的方式发消息
// var content string
// taskDesc := fmt.Sprintf("你的异步任务[%s],ID[%s],开始于:%s,结束于:%s,", t.Name, t.ID, utils.Time2Str(t.CreatedAt), utils.Time2Str(t.TerminatedAt))
// content = fmt.Sprintf("%s执行%s", taskDesc, TaskStatusName[t.Status])
// if t.Error() == "" {
// noticeMsg := t.GetNoticeMsg()
// if noticeMsg != "" {
// content += ",通知消息:" + noticeMsg
// }
// } else {
// content += ",\n" + t.Error()
// }
// ddmsg.SendUserMessage(dingdingapi.MsgTyeText, authInfo.UserID, "异步任务完成", content)
//}
if authInfo, err := t.ctx.GetV2AuthInfo(); err == nil { // 这里应该是不管登录类型,直接以可能的方式发消息
var content string
taskDesc := fmt.Sprintf("你的异步任务[%s],ID[%s],开始于:%s,结束于:%s,", t.Name, t.ID, utils.Time2Str(t.CreatedAt), utils.Time2Str(t.TerminatedAt))
content = fmt.Sprintf("%s执行%s", taskDesc, TaskStatusName[t.Status])
if t.Error() == "" {
noticeMsg := t.GetNoticeMsg()
if noticeMsg != "" {
content += ",通知消息:" + noticeMsg
}
} else {
content += ",\n" + t.Error()
}
ddmsg.SendUserMessage(dingdingapi.MsgTyeText, authInfo.UserID, "异步任务完成", content)
}
}
}

View File

@@ -0,0 +1,82 @@
package push
func pushToSingle(content, title string, storeID int) {
//var (
// db = dao.GetDB()
//)
//if !globals.IsProductEnv() {
// return
//}
//storePushs, err := dao.GetStorePushClient(db, storeID, "")
//if err != nil {
// return
//}
//for _, v := range storePushs {
//
// status, err2 := api.PushAPI.PushToSingle(v.ClientID, false, &unipushapi.Notification{
// Title: title,
// Body: content,
// })
// if err = err2; err != nil {
// globals.SugarLogger.Debugf("NotifyNewOrder push error: [%v]", err)
// continue
// }
// if status == unipushapi.SuccessOffLine {
// _, err = api.PushAPI.PushToSingle(v.ClientID, true, &unipushapi.Notification{
// Body: content,
// })
// if err != nil {
// globals.SugarLogger.Debugf("NotifyNewOrder push2 error: [%v]", err)
// continue
// }
// }
//
//}
}
//
//func NotifyNewOrder(order *model.GoodsOrder) {
// globals.SugarLogger.Debugf("NotifyNewOrder push begin orderID :[%v]", order.VendorOrderID)
// sb := new(strings.Builder)
// sb.WriteString("老板,")
// sb.WriteString(order.ConsigneeName)
// sb.WriteString("购买了商品")
// sb.WriteString(getOrderDetailBrief(order))
// pushToSingle(sb.String(), "京西菜市新订单推送", jxutils.GetSaleStoreIDFromOrder(order))
//}
//
//func getOrderDetailBrief(order *model.GoodsOrder) (brief string) {
// sb := new(strings.Builder)
// sb.WriteString(order.Skus[0].SkuName)
// sb.WriteString("等共")
// sb.WriteString(utils.Int2Str(order.Skus[0].Count))
// sb.WriteString("份(")
// sb.WriteString(jxutils.IntPrice2StandardString(order.Skus[0].SalePrice))
// sb.WriteString("元/份)等,预计收入")
// //TODO 2020-07-20 果园和菜市不同
// var price int64
// if beego.BConfig.RunMode == "jxgy" {
// price = order.EarningPrice
// } else {
// if order.EarningType == model.EarningTypePoints {
// price = order.ActualPayPrice
// } else {
// price = order.ShopPrice
// }
// }
// sb.WriteString(jxutils.IntPrice2StandardString(price))
// sb.WriteString("元")
// return sb.String()
//}
//
//func NotifyAfsOrder(afsOrder *model.AfsOrder) (err error) {
// globals.SugarLogger.Debugf("NotifyAfsOrder push begin orderID :[%v]", afsOrder.VendorOrderID)
// pushToSingle("老板,您有新的售后单,请尽快处理!", "京西菜市售后单推送", jxutils.GetSaleStoreIDFromAfsOrder(afsOrder))
// return err
//}
//
//func NotifyOrderCanceled(order *model.GoodsOrder) (err error) {
// title := fmt.Sprintf("老板,您的订单%s第%d号订单, %s被取消了", model.VendorChineseNames[order.VendorID], order.OrderSeq, order.VendorOrderID)
// pushToSingle(title, "京西菜市取消单推送", jxutils.GetSaleStoreIDFromOrder(order))
// return err
//}

View File

@@ -0,0 +1,122 @@
package weixinmsg
import (
"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"
"git.rosy.net.cn/jx-callback/globals/api"
)
const (
WX_TO_ORDER_PAGE_URL = "/#/?jxStoreId="
WX_TO_STORE_SKU_PAGE_URL = "/#/shop?jxStoreId="
WX_TO_SHOW_COMMENTS_DETAIL_URL = "/#/assess-list?jxStoreId=" //展示差评详情的页面
WX_TO_SHOW_MSG = "/#/message-detail?msgID=%d&msgStatusID=%d"
WX_MINI_TO_ORDER_PAGE_URL = "pages/order-manager/main"
WX_MINI_TO_STORE_SKU_PAGE_URL = "pages/goods-manager/main"
WX_MINI_TO_SHOW_COMMENTS_DETAIL_URL = "pages/pagesStore/store-comment/main"
WX_MINI_TO_SHOW_MSG = "pages/pagesStore/msg-page/main?msgID=%d&msgStatusID=%d"
//新订单模板消息文字颜色
WX_NEW_ORDER_TEMPLATE_COLOR = "#173177"
WX_HIGHLEVEL_TEMPLATE_COLOR = "#FF0000" //红色
WX_HIGHLEVEL_TEMPLATE_COLOR2 = "#333333" //黑色
WX_TEMPLATE_VENDERCOLOR_JDDJ = "#47B34F"
WX_TEMPLATE_VENDERCOLOR_MT = "#F4A800"
WX_TEMPLATE_VENDERCOLOR_ELM = "#0191EA" //蓝色
WX_TEMPLATE_VENDERCOLOR_BAD_COMMENTS = "#4F4DA0"
WX_NEWORDER_TEMPLATE_ID = "_DtNGwmOeR6TkkTVUblxLIlkV2MAPOX57TkvfdqG6nY" //微信新订单推送
WX_ADJUSTORDER_TEMPLATE_ID = "N5rmV2-PDf3opjkv23IdLc76VnFThr_uOKSh5FzT13M" //微信调整订单推送
WX_MTPS_DELIVERY_GRABDONE_TEMPLATE_ID = "h4dkON6AgnHz1XmaksEUB_8Bcir4V8MSexUhC149pPE" //微信美团配送员接单推送
WX_MTPS_DELIVERY_DONE_TEMPLATE_ID = "YXdCrQAHZlcZX1htYUiarrLmtkmKAjp7rynjwObgODo" //微信美团配送员配送完成推送
WX_MTPS_UNABLE_DELIVER_TEMPLATE_ID = "ZFph5Hp7oLlrzVRXbsKIC_StmaBeB9Dlp4tlHeAmUQ8" //微信美团配送配送能力不足推送
WX_MTPS_DELIVERY_EXCEPTION_TEMPLATE_ID = "RkfOFHgR1N75L4-a6Gv0DljpCsVfOHhLm_vyXh8MR-w" //微信美团配送异常推送
WX_BAD_COMMENT_PUSH_TEMPLATE_ID = "NaMEzjctvVPQ9ishTI1dKpp5QSYV2FWcWftSSjDrpN8" //微信中差评消息推送
WX_DADA_DELIVERY_GRABDONE_TEMPLATE_ID = "h4dkON6AgnHz1XmaksEUB_8Bcir4V8MSexUhC149pPE" //微信达达众包配送员接单推送
WX_DADA_DELIVERY_DONE_TEMPLATE_ID = "YXdCrQAHZlcZX1htYUiarrLmtkmKAjp7rynjwObgODo" //微信达达众包配送员配送完成推送
WX_SALE_BILL_TEMPLATE_ID = "eTUuFZMWH7IsVBfcxNMpmaHYaxRkUaD6zG8wSGJDcic"
WX_NORMAL_STORE_MSG_TEMPLATE_ID = "EUeIJEz2TLUAn4TU2EffOGYLd3dEaYndD_y6Sw9FcSU"
WX_CHANGE_APPROVED_TEMPLATE_ID = "gIG2olBZtQbjXmp6doNB_dESu60By5xuXYOGxksLv3Y"
WX_CHANGE_REJECTED_TEMPLATE_ID = "OBF4-d5inK95epHcUltpdb1zq9boVp2HESpASVRh1Oo"
WX_ORDER_APPLY_CANCEL_TEMPLATE_ID = "e6urTtcm4PL0rgDMG_1qWNOwrE3Qxqcm_dx0kWWCmEI"
WX_ORDER_ORDER_CANCELED_TEMPLATE_ID = "HXjuSAbIk77Xh18hjgwoxHzbciR9jX3Rn2CpLJz9dZw"
WX_ORDER_CHANGE_INFO_TEMPLATE_ID = "cjmEQFEpvcOuBNqQpTfMU5FeBpGRbQh_gWKz-WPW8Ro"
WX_AFS_ORDER_WAIT4APPROVE_TEMPLATE_ID = "X29udtANvhX6x1Lyh-T40NGNjRXBbUj5oSBTfDhZAqU"
WX_AFS_ORDER_STATUS_CHANGED_TEMPLATE_ID = "99T33rrXX0VboO1hljs4x8dDoLiSj3QX_rOikPHIXkg"
WS_NOTIFY_STORE_STATUS_CHHANGED_TEMPLATE_ID = "Fl0vOnBKTQqRFx3-shGKxdCnxMdQXNeODzgkuwd7oxw"
WX_STORE_ALERT_TEMPLATE_ID = "0AjzVl1wPl6iO4nFOS4IEsJYSzBymlT37DciIvcCOxE"
)
var (
VendorColors = map[int]string{
model.VendorIDJD: WX_TEMPLATE_VENDERCOLOR_JDDJ,
model.VendorIDMTWM: WX_TEMPLATE_VENDERCOLOR_MT,
//model.VendorIDELM: WX_TEMPLATE_VENDERCOLOR_ELM,
model.VendorIDEBAI: WX_TEMPLATE_VENDERCOLOR_ELM,
}
testMiniProgramStoreMap = map[int]int{
101089: 1,
100888: 1,
100204: 1,
100205: 1,
100147: 1,
}
debugOpenIDMap = map[string]int{
"oYN_usk0AeGc_C6VEZfmFQP5VHMQ": 1, // 周小扬
"oYN_ust9hXKEvEv0X6Mq6nlAWs_E": 1, // me
"oYN_usqnpGVQ4xxlao_yybsbYJh4": 1, // 朱丹
}
)
func SmartMessageTemplateSend(userOpenID, templateID, downloadURL, miniPageURL string, data interface{}) (err error) {
var miniProgram map[string]interface{}
if miniPageURL != "" {
miniProgram = map[string]interface{}{
"appid": api.WeixinMiniAPI.GetAppID(),
"pagepath": miniPageURL,
}
}
globals.SugarLogger.Debugf("SmartMessageTemplateSend openID:%s, templateID:%s, downloadURL:%s, miniProgram:%s", userOpenID, templateID, downloadURL, utils.Format4Output(miniProgram, true))
if globals.ReallySendWeixinMsg || debugOpenIDMap[userOpenID] == 1 {
if err = api.WeixinAPI.CBMessageTemplateSend(userOpenID, templateID, downloadURL, miniProgram, data); err != nil {
globals.SugarLogger.Debugf("SmartMessageTemplateSend openID:%s, templateID:%s, downloadURL:%s, miniProgram:%s, failed with error:%v", userOpenID, templateID, downloadURL, utils.Format4Output(miniProgram, true), err)
}
}
return err
}
func SendMsgToUser(userID string, templateID string, data interface{}) (err error) {
globals.SugarLogger.Debugf("SendMsgToUser userID:%d, templateID:%s", userID, templateID)
authBinds, err := dao.GetUserBindAuthInfo(dao.GetDB(), userID, model.AuthBindTypeAuth, []string{"weixinsns"}, "", "", "wx2bb99eb5d2c9b82c")
if err != nil {
return err
}
successCount := 0
if len(authBinds) == 0 {
return fmt.Errorf("此用户未找到微信认证方式userID: %v", userID)
}
globals.SugarLogger.Debugf("SendMsgToUser userID:%d, openID:%s, templateID:%s", userID, authBinds[0].AuthID, templateID)
if err2 := SmartMessageTemplateSend(authBinds[0].AuthID, templateID, "", "", data); err2 == nil {
successCount++
} else {
err = err2
}
if successCount > 0 {
err = nil // 只要成功一个都当成成功
}
if err != nil {
globals.SugarLogger.Debugf("SendMsgToUser all failed userID:%d, templateID:%s, error:%v", userID, templateID, err)
}
return err
}

View File

@@ -0,0 +1,28 @@
package weixinmsg
import (
"testing"
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
"git.rosy.net.cn/jx-callback/globals/api2"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/globals/testinit"
)
func init() {
testinit.Init()
api2.Init()
}
func TestGetWeixinOpenIDsFromStoreID(t *testing.T) {
openIDs := GetWeixinOpenIDsFromStoreID(100118)
t.Log(utils.Format4Output(openIDs, false))
}
func TestSendStoreMessage(t *testing.T) {
_, err := SendStoreMessage(jxcontext.AdminCtx, "title", "content", []int{1}, false, true)
if err != nil {
t.Fatal(err)
}
}

261
business/model/act.go Normal file
View File

@@ -0,0 +1,261 @@
package model
import (
"time"
"git.rosy.net.cn/baseapi/utils"
)
const (
ActTypeAll = -1
ActSkuFake = 0 // 假活动,只用于存储活动结算信息
ActSkuDirectDown = 3 // 直降
ActSkuSecKill = 4 // 秒杀
ActSkuDiscount = 5 // 折扣
ActDiscountTypePrice = 1 //折扣类型是最低价
ActDiscountTypePercentage = 2 //折扣类型是最低折扣
TrendTypeUp = 1 //涨价趋势
TrendTypeDown = 2 //降价趋势
TrendTypeNothing = 0 //不变
ActOrderBegin = 10
ActOrderMoneyOff = 11
ActOrderMoneyOffCoupon = 12
ActOrderReduceFreight = 13
ActOrderReduceFreightCoupon = 14
)
const (
ActStatusNA = 0 // 未知
ActStatusCreated = 1 // 需同步
ActStatusCanceled = 2 // 需同步
ActStatusEnded = 3 // 不需要同步,根据活动时间自动刷新的
ActCreateTypeAPI = 1
ActCreateTypeCallback = 2
ActCreateTypeSpider = 3
OverlapRuleNormal = 0 // 不允许重叠(重叠会报错)
OverlapRuleReplace = 1 // 相同活动类型,或秒杀替换直降
)
var (
ActTypeName = map[int]string{
ActSkuFake: "结算",
ActSkuDirectDown: "直降",
ActSkuSecKill: "秒杀",
ActSkuDiscount: "折扣",
}
ActStatusName = map[int]string{
ActStatusNA: "未知",
ActStatusCreated: "正常",
ActStatusCanceled: "取消",
ActStatusEnded: "结束",
}
ActCreateTypeName = map[int]string{
ActCreateTypeAPI: "API",
ActCreateTypeCallback: "回调",
ActCreateTypeSpider: "网页",
}
)
type Act struct {
ModelIDCULD
Name string `orm:"size(64)" json:"name"`
Advertising string `orm:"size(255)" json:"advertising"`
Type int `json:"type"`
Status int `json:"status"`
LimitUser int `json:"limitUser"` // 是否按用户限制
LimitDaily int `json:"limitDaily"` // 每日限购单数
LimitCount int `json:"limitCount"` // 每单限购数量
Source string `orm:"size(255)" json:"source"`
CreateType int `json:"createType"`
IsSpecial int8 `json:"isSpecial"` // 是否是特殊绑定活动
OverlapRule int `json:"overlapRule"`
PricePercentage int `json:"pricePercentage"` // 单品级活动才有效
BeginAt time.Time `orm:"type(datetime);index" json:"beginAt"`
EndAt time.Time `orm:"type(datetime);index" json:"endAt"`
VendorMask int `json:"-"`
Remark string `orm:"size(255)" json:"remark"`
DiscountType int `json:"discountType"` //折扣类型1为最低价2为最低折扣
DiscountValue1 int `json:"DiscountValue1"` //第一档折扣
DiscountValue2 int `json:"DiscountValue2"` //第二档折扣
}
// test
func (*Act) TableUnique() [][]string {
return [][]string{
[]string{"Name", "Type", "DeletedAt"},
}
}
type ActMap struct {
ModelIDCULD
ActID int `orm:"column(act_id)" json:"actID"`
VendorID int `orm:"column(vendor_id)" json:"vendorID"`
VendorOrgCode string `orm:"size(32)" json:"vendorOrgCode"` // 同一平台下不同的商户代码,如果只有一个,可以为空
VendorActID string `orm:"column(vendor_act_id);size(48)" json:"vendorActID"`
SyncStatus int8 `orm:"default(2)" json:"syncStatus"`
Remark string `orm:"size(1024)" json:"remark"`
}
func (*ActMap) TableUnique() [][]string {
return [][]string{
[]string{"ActID", "VendorID", "DeletedAt"},
}
}
func (*ActMap) TableIndex() [][]string {
return [][]string{
[]string{"VendorActID", "VendorID", "DeletedAt"}, // 饿百美团活动的VendorActID统一为空不能设置为唯一索引
}
}
// 不建表
type Act2 struct {
MapID int `orm:"column(map_id)"`
Act
VendorID int `orm:"column(vendor_id)" json:"vendorID"`
VendorOrgCode string `orm:"size(32)" json:"vendorOrgCode"` // 同一平台下不同的商户代码,如果只有一个,可以为空
VendorActID string `orm:"column(vendor_act_id);size(48)" json:"vendorActID"`
SyncStatus int8 `orm:"default(2)" json:"syncStatus"`
}
func (a *Act2) GetRealActName() string {
if IsSyncStatusNeedCreate(a.SyncStatus) {
return a.Name
}
return a.Name + "_" + utils.Int64ToStr(time.Now().Unix())
}
type ActOrderRule struct {
ModelIDCULD
ActID int `orm:"column(act_id)" json:"actID"`
SalePrice int64 `orm:"" json:"salePrice"` // 满的价格
DeductPrice int64 `orm:"" json:"deductPrice"` // 减的价格
}
type ActStoreSku struct {
ModelIDCULD
ActID int `orm:"column(act_id)" json:"actID"`
OriginalPrice int64 `orm:"" json:"originalPrice"` // 单品级活动用,创建活动时商品的原始京西价
// 以下字段API中有效
StoreID int `orm:"column(store_id)" json:"storeID"`
SkuID int `orm:"column(sku_id)" json:"skuID"`
PricePercentage int `orm:"" json:"pricePercentage"` // 单品级活动用SKU级的价格比例非0覆盖Act中的PricePercentage
ActPrice int64 `orm:"" json:"actPrice"` // 单品级活动用SKU级指定的价格非0覆盖CustomPricePercentage与Act中的PricePercentage
EarningPrice int64 `json:"earningPrice"` // 活动商品设置,结算给门店老板的钱
Stock int `orm:"" json:"stock"` // 活动库存
}
func (*ActStoreSku) TableUnique() [][]string {
return [][]string{
[]string{"ActID", "StoreID", "SkuID", "DeletedAt"},
}
}
type ActStoreSkuMap struct {
ModelIDCULD
BindID int `orm:"column(bind_id)" json:"bindID"`
ActID int `orm:"column(act_id)" json:"actID"`
StoreID int `orm:"column(store_id)" json:"storeID"`
SkuID int `orm:"column(sku_id)" json:"skuID"`
VendorID int `orm:"column(vendor_id)" json:"vendorID"`
VendorActID string `orm:"column(vendor_act_id);size(48)" json:"vendorActID"`
SyncStatus int8 `orm:"default(2)" json:"syncStatus"`
VendorPrice int64 `json:"vendorPrice"` // 创建活动时的平台价格
ActualActPrice int64 `json:"actualActPrice"` // 单品级活动用,创建活动时商品的活动价格
EarningPrice int64 `json:"earningPrice"` // 活动商品设置,结算给门店老板的钱
TrendType int `json:"trendType"` //折扣活动使用涨跌趋势1为涨2为跌0为不动
TrendPrice int `json:"trendPrice"` //涨跌具体多少
}
func (*ActStoreSkuMap) TableUnique() [][]string {
return [][]string{
[]string{"ActID", "BindID", "VendorID"},
}
}
func (*ActStoreSkuMap) TableIndex() [][]string {
return [][]string{
[]string{"ActID", "StoreID", "SkuID", "VendorID", "DeletedAt"},
}
}
// 不建表
type ActStoreSku2 struct {
MapID int `orm:"column(map_id)"`
Type int `json:"type"`
DiscountType int `json:"discountType"`
DiscountValue1 int `json:"discountValue1"`
DiscountValue2 int `json:"discountValue2"`
ActStoreSku
VendorID int `orm:"column(vendor_id)" json:"vendorID"`
VendorActID string `orm:"column(vendor_act_id);size(48)" json:"vendorActID"`
SyncStatus int8 `orm:"default(2)" json:"syncStatus"`
VendorPrice int64 `json:"vendorPrice"` // 创建活动时的平台价格
ActualActPrice int64 `json:"actualActPrice"` // 单品级活动用,创建活动时商品的活动价格
VendorStoreID string `orm:"column(vendor_store_id)" json:"vendorStoreID"`
StoreName string `json:"storeName"`
VendorSkuID string `orm:"column(vendor_sku_id)" json:"vendorSkuID"`
SkuName string `json:"skuName"`
Prefix string `json:"-"`
ExPrefix string
ExPrefixBegin *time.Time
ExPrefixEnd *time.Time
SkuNameName string `orm:"column(sku_name_name)" json:"-"`
Unit string `orm:"size(8)" json:"-"`
SpecQuality float32 `json:"-"`
SpecUnit string `json:"-"`
Comment string `json:"-"`
TrendType int `json:"trendType"` //折扣活动使用涨跌趋势1为涨2为跌0为不动
TrendPrice int `json:"trendPrice"` //涨跌具体多少
}
type StoreSkuAct struct {
ModelIDCUL
StoreID int `orm:"column(store_id)"`
SkuID int `orm:"column(sku_id);index"`
VendorID int `orm:"column(vendor_id)" json:"vendorID"`
ActPercentage int `json:"actPercentage"` // 直降活动百分比
SyncStatus int8 `orm:"default(2)" json:"syncStatus"`
// ActID int `orm:"column(act_id);index" json:"actID"`
VendorActID string `orm:"column(vendor_act_id);size(48);index" json:"vendorActID"`
HintActID int `orm:"column(hint_act_id);size(48);index" json:"hintActID"`
VendorActPrice int64 `json:"vendorActPrice"` // 保存数据用,实际的活动价
Remark string `orm:"column(remark);size(1024)" json:"remark"`
// EarningActID int `orm:"column(earning_act_id);index" json:"earningActID"`
// EarningPrice int64 `json:"earningPrice"`
}
func (*StoreSkuAct) TableUnique() [][]string {
return [][]string{
[]string{"StoreID", "SkuID", "VendorID"},
}
}

View File

@@ -2,6 +2,7 @@ package model
import (
"math"
"time"
)
const (
@@ -34,6 +35,23 @@ type PagedInfo struct {
Data interface{} `json:"data"`
}
type OrderFinancialExt struct {
OrderFinancial
VendorStoreID string `orm:"column(vendor_store_id);size(48)" json:"vendorStoreID"` //
OrderFinishedAt time.Time `orm:"type(datetime)" json:"orderFinishedAt"` // 订单妥投/完成时间
StoreID int `orm:"column(store_id)" json:"storeID"` // 外部系统里记录的 jxstoreid
JxStoreID int `orm:"column(jx_store_id)" json:"jxStoreID"` // 根据VendorStoreID在本地系统里查询出来的 jxstoreid
StoreName string `orm:"size(64)" json:"storeName"` //
Status int `json:"status"` // 参见OrderStatus*相关的常量定义
Skus []*OrderSkuFinancial `orm:"-" json:"skus"` // 正向订单购买商品列表
Discounts []*OrderDiscountFinancial `orm:"-" json:"discounts"` // 正向订单享受优惠列表
}
type OrderFinancialSkuExt struct {
OrderSkuFinancial
Image string `json:"image"`
}
type ProductInfo struct {
OriginalName string `json:"originalName"`
OriginalSpec string `json:"originalSpec"`

View File

@@ -12,23 +12,21 @@ const (
VendorIDPurchaseBegin = 0
VendorIDJD = 0
VendorIDMTWM = 1
VendorIDELM = 2
VendorIDPDD = 2 //拼多多
VendorIDEBAI = 3
VendorIDGD = 10
VendorIDYB = 4 //银豹
VendorIDTT = 14
VendorIDTB = 16 //淘宝
VendorIDJDShop = 5 //京东商城
VendorIDWSC = 11 // 微盟微商城
VendorIDPurchaseEnd = 11
VendorIDJX = 9 // 这是一个假的京西VendorID
VendorGoMei = 12 // 国美
VendorIDTT = 14 // 抖音平台小程序
VendorIDPurchaseEnd = 10
VendorIDOther = 999 //其他平台
VendorIDWXPay = 51 // 微信支付
VendorIDDeliveryBegin = 101
VendorIDDada = 101 // 达达配送
VendorIDMTPS = 102 // 美团配送
VendorIDFengNiao = 103 // 蜂鸟配送
VendorIDDada = 101
VendorIDMTPS = 102
VendorIDFengNiao = 103
VendorIDJDWL = 401 //京东物流
VendorIDDeliveryEnd = 500
@@ -37,7 +35,6 @@ const (
VendorIDXiaoWM = 202 // 外卖管家打印机
VendorIDYiLianYun = 203 // 易联云
VendorIDZhongWu = 204 // 中午云打印
VendorIDJxprint = 205 // 京西打印
VendorIDPrinterEnd = 300
VendorIDOthersBegin = 301
@@ -52,22 +49,6 @@ const (
VendorIDAutonavi = 321 // 高德导航
VendorIDQiNiuCloud = 323 // 七牛云
VendorIDShowAPI = 325 // 万维易源
// 美团配送门店配送方式
MTWMStorePSWay1 = "1003" //美团跑腿(众包)
MTWMStorePSWay2 = "1001" //专送(加盟)
MTWMStorePSWay3 = "1002" //专送(自建)
MTWMStorePSWay4 = "1004" //城市代理
MTWMStorePSWay5 = "2002" //快送
MTWMStorePSWay6 = "2010" //全城送
MTWMStorePSWay7 = "0000" //商家自配
MTWMStorePSWay8 = "3001" //混合送(专送+快送)
MTWMStorePSWay9 = "30011002" //混合自建
MTWMStorePSWay10 = "30011001" //混合加盟
MTWMStorePSWay11 = "30012002" //混合快送
MTWMStorePSWay12 = "0002" //趣生活美食配送
MTWMStorePSWay13 = "0016" //达达快递
MTWMStorePSWay14 = "0033" //E_代送
)
type VendorInfo struct {
@@ -85,26 +66,22 @@ var (
VendorNames = map[int]string{
VendorIDJD: "Jd",
VendorIDMTWM: "Mtwm",
VendorIDELM: "Elm",
VendorIDPDD: "Pdd",
VendorIDEBAI: "Ebai",
VendorIDWSC: "Wsc",
VendorIDYB: "Yb",
VendorIDTB: "Tb",
VendorIDJX: "Jx",
VendorIDJDShop: "Jds",
VendorIDDada: "Dada",
VendorIDMTPS: "Mtps",
VendorIDFengNiao: "Fn",
VendorIDDada: "Dada",
VendorIDMTPS: "Mtps",
VendorIDFeiE: "Feie",
VendorIDXiaoWM: "XiaoWM",
VendorIDYiLianYun: "Yilianyun",
VendorIDZhongWu: "ZhongWu",
VendorIDJxprint: "Jx",
VendorIDQiNiuCloud: "Qiniu",
VendorIDJDWL: "Jdwl",
VendorGoMei: "GoMei",
}
VendorTypeName = map[int]string{
@@ -117,23 +94,21 @@ var (
VendorChineseNames = map[int]string{
VendorIDJD: "京东到家",
VendorIDMTWM: "美团外卖",
VendorIDELM: "饿了么",
VendorIDPDD: "拼多多",
VendorIDEBAI: "饿百新零售",
VendorIDYB: "银豹",
VendorIDTB: "淘宝",
VendorIDJDShop: "京东商城",
VendorIDWSC: "微盟微商城",
VendorIDJX: "京西商城",
VendorIDOther: "其他平台",
VendorIDDada: "达达众包",
VendorIDMTPS: "美团配送",
VendorIDJDWL: "京东物流",
VendorIDFengNiao: "蜂鸟配送",
VendorIDDada: "达达众包",
VendorIDMTPS: "美团配送",
VendorIDJDWL: "京东物流",
VendorIDFeiE: "飞鹅",
VendorIDXiaoWM: "外卖管家",
VendorIDYiLianYun: "易联云",
VendorIDZhongWu: "中午云",
VendorIDJxprint: "京西云",
VendorIDWXMP: "微信公众号",
VendorIDWXQRCode: "微信扫码",
@@ -145,7 +120,21 @@ var (
VendorIDAutonavi: "高德导航",
VendorIDQiNiuCloud: "七牛云",
VendorIDShowAPI: "万维易源",
VendorGoMei: "国美",
}
VendorImg = map[int]string{
VendorIDJD: "http://image.jxc4.com/image/b1bd587d98e82ad6405132b8da67a1db.tem.png",
VendorIDMTWM: "http://image.jxc4.com/image/fb09e10a9c059aa6c133ff3e05c1dbbc.tem.png",
VendorIDEBAI: "http://image.jxc4.com/image/28e654c72a2bd92c5d09fdab475f6288.tem.png",
VendorIDJDShop: "http://image.jxc4.com/image/7c43ebbcbdbc0ef31fe028f680c0a7e3.tem.png",
VendorIDOther: "http://image.jxc4.com/image/558382ba95573b9537fbb209cadbd031.tem.png",
}
VendorColors = map[int]string{
VendorIDJD: "#3CC518",
VendorIDMTWM: "#FFB14A",
VendorIDEBAI: "#E43428",
VendorIDJDShop: "#51A7FC",
}
VendorInfoMap = map[int]*VendorInfo{

View File

@@ -1,229 +0,0 @@
package model
//
//// VendorIDJD, VendorIDMTWM与VendorIDELM的定义和老系统是兼容的
//const (
// VendorTypeUnknown = 0 // 未知
// VendorTypePurchase = 1 // 购物平台
// VendorTypeDelivery = 2 // 快递平台
// VendorTypePrinter = 3 // 网络打印机
// VendorTypeOthers = 9 // 其它
//
// VendorIDUnknown = -1
// VendorIDPurchaseBegin = 0
// VendorIDJD = 0
// VendorIDMTWM = 1
// VendorIDPDD = 2 //拼多多
// VendorIDEBAI = 3
// VendorIDTB = 4 //淘宝
// VendorIDJDShop = 5 //京东商城
// VendorIDJX = 9 // 这是一个假的京西VendorID
// VendorIDPurchaseEnd = 10
// VendorIDOther = 999 //其他平台
//
// VendorIDWXPay = 51 // 微信支付
//
// VendorIDDeliveryBegin = 101
// VendorIDDada = 101
// VendorIDMTPS = 102
// VendorIDFengNiao = 103
// VendorIDJDWL = 401 //京东物流
// VendorIDDeliveryEnd = 500
//
// VendorIDPrinterBegin = 201
// VendorIDFeiE = 201 // 飞鹅打印机
// VendorIDXiaoWM = 202 // 外卖管家打印机
// VendorIDYiLianYun = 203 // 易联云
// VendorIDZhongWu = 204 // 中午云打印
// VendorIDPrinterEnd = 300
//
// VendorIDOthersBegin = 301
//
// VendorIDWXMP = 301 // 微信公众号
// VendorIDWXQRCode = 302 // 微信扫码
// VendorIDWXMini = 303 // 微信小程序
//
// VendorIDDDH5MicroApp = 311 // 钉钉H5微应用
// VendorIDDDMobileQRCode = 312 // 钉钉移动接入应用(登录)
//
// VendorIDAutonavi = 321 // 高德导航
// VendorIDQiNiuCloud = 323 // 七牛云
// VendorIDShowAPI = 325 // 万维易源
//)
//
//type VendorInfo struct {
// Name string `json:"name"`
//
// OrgCodeName string `json:"orgCodeName"`
// Value1Name string `json:"value1Name,omitempty"`
// Value2Name string `json:"value2Name,omitempty"`
// Value3Name string `json:"value3Name,omitempty"`
// Value4Name string `json:"value4Name,omitempty"`
// Value5Name string `json:"value5Name,omitempty"`
//}
//
//var (
// VendorNames = map[int]string{
// VendorIDJD: "Jd",
// VendorIDMTWM: "Mtwm",
// VendorIDPDD: "Pdd",
// VendorIDEBAI: "Ebai",
// VendorIDTB: "Tb",
// VendorIDJX: "Jx",
// VendorIDJDShop: "Jds",
//
// VendorIDDada: "Dada",
// VendorIDMTPS: "Mtps",
//
// VendorIDFeiE: "Feie",
// VendorIDXiaoWM: "XiaoWM",
// VendorIDYiLianYun: "Yilianyun",
// VendorIDZhongWu: "ZhongWu",
//
// VendorIDQiNiuCloud: "Qiniu",
// VendorIDJDWL: "Jdwl",
// }
//
// VendorTypeName = map[int]string{
// VendorTypeUnknown: "未知",
// VendorTypePurchase: "购物平台",
// VendorTypeDelivery: "快递平台",
// VendorTypeOthers: "其它",
// }
//
// VendorChineseNames = map[int]string{
// VendorIDJD: "京东到家",
// VendorIDMTWM: "美团外卖",
// VendorIDPDD: "拼多多",
// VendorIDEBAI: "饿百新零售",
// VendorIDTB: "淘宝",
// VendorIDJDShop: "京东商城",
// VendorIDJX: "京西商城",
// VendorIDOther: "其他平台",
//
// VendorIDDada: "达达众包",
// VendorIDMTPS: "美团配送",
// VendorIDJDWL: "京东物流",
//
// VendorIDFeiE: "飞鹅",
// VendorIDXiaoWM: "外卖管家",
// VendorIDYiLianYun: "易联云",
// VendorIDZhongWu: "中午云",
//
// VendorIDWXMP: "微信公众号",
// VendorIDWXQRCode: "微信扫码",
// VendorIDWXMini: "微信小程序",
//
// VendorIDDDH5MicroApp: "钉钉H5微应用",
// VendorIDDDMobileQRCode: "钉钉移动接入应用(登录)",
//
// VendorIDAutonavi: "高德导航",
// VendorIDQiNiuCloud: "七牛云",
// VendorIDShowAPI: "万维易源",
// }
//
// VendorImg = map[int]string{
// VendorIDJD: "http://image.jxc4.com/image/b1bd587d98e82ad6405132b8da67a1db.tem.png",
// VendorIDMTWM: "http://image.jxc4.com/image/fb09e10a9c059aa6c133ff3e05c1dbbc.tem.png",
// VendorIDEBAI: "http://image.jxc4.com/image/28e654c72a2bd92c5d09fdab475f6288.tem.png",
// VendorIDJDShop: "http://image.jxc4.com/image/7c43ebbcbdbc0ef31fe028f680c0a7e3.tem.png",
// VendorIDOther: "http://image.jxc4.com/image/558382ba95573b9537fbb209cadbd031.tem.png",
// }
//
// VendorColors = map[int]string{
// VendorIDJD: "#3CC518",
// VendorIDMTWM: "#FFB14A",
// VendorIDEBAI: "#E43428",
// VendorIDJDShop: "#51A7FC",
// }
//
// VendorInfoMap = map[int]*VendorInfo{
// VendorIDJD: &VendorInfo{
// Name: "京东到家",
// OrgCodeName: "商户代码",
// Value1Name: "AppKey",
// Value2Name: "AppSecret",
// Value3Name: "Token",
// Value4Name: "管理后台Cookie",
// },
// VendorIDMTWM: &VendorInfo{
// Name: "美团外卖",
// OrgCodeName: "AppID",
// Value1Name: "Secret",
// Value2Name: "回调URL",
// },
// VendorIDEBAI: &VendorInfo{
// Name: "饿百联盟",
// OrgCodeName: "商户代码",
// Value1Name: "Source",
// Value2Name: "Secret",
// Value3Name: "管理后台Cookie",
// },
//
// // VendorIDDada: &VendorInfo{
// // Name: "达达快递",
// // OrgCodeName: "商户ID",
// // Value1Name: "app_key",
// // Value2Name: "app_secret",
// // },
// // VendorIDMTPS: &VendorInfo{
// // Name: "美团配送",
// // OrgCodeName: "自编码",
// // Value1Name: "Appkey",
// // Value2Name: "Secret",
// // },
//
// // VendorIDFeiE: &VendorInfo{
// // Name: "飞鹅",
// // OrgCodeName: "User",
// // Value1Name: "Key",
// // },
// // VendorIDXiaoWM: &VendorInfo{
// // Name: "外卖管家",
// // OrgCodeName: "AppID",
// // Value1Name: "AppKey",
// // },
// // VendorIDYiLianYun: &VendorInfo{
// // Name: "易联云",
// // OrgCodeName: "ClientID",
// // Value1Name: "ClientSecret",
// // },
// }
//)
//
//func GetVendorMask(vendorIDs ...int) (vendorMask int) {
// for _, vendorID := range vendorIDs {
// vendorMask |= 1 << uint(vendorID)
// }
// return vendorMask
//}
//
//func GetVendorType(vendorID int) (vendorType int) {
// if vendorID >= VendorIDPurchaseBegin && VendorIDPurchaseBegin <= VendorIDPurchaseEnd {
// return VendorTypePurchase
// } else if vendorID >= VendorIDPurchaseBegin && VendorIDPurchaseBegin <= VendorIDPurchaseEnd {
// return VendorTypeDelivery
// } else if vendorID >= VendorIDOthersBegin {
// return VendorTypeOthers
// }
// return VendorTypeUnknown
//}
//
//type AppKeyConfig struct {
// ModelIDCULD
// VendorID int `json:"vendorID"`
// VendorOrgCode string `orm:"size(32)" json:"vendorOrgCode"` // 同一平台下不同的商户代码,如果只有一个,可以为空
//
// Name string `orm:"size(32)" json:"name"`
// Value1 string `orm:"size(1024)" json:"value1"`
// Value2 string `orm:"size(1024)" json:"value2"`
// Value3 string `orm:"size(1024)" json:"value3"`
// Value4 string `orm:"size(1024)" json:"value4"`
// Value5 string `orm:"size(1024)" json:"value5"`
//}
//
//func (a *AppKeyConfig) TableUnique() [][]string {
// return [][]string{
// []string{"VendorID", "VendorOrgCode", "DeletedAt"},
// }
//}

View File

@@ -1,12 +0,0 @@
package model
type Apps struct {
ModelIDCULD
UserID string `orm:"column(user_id)" json:"user_id"` //属于哪个账号的
Mobile string `json:"mobile"` //手机号
Name string `json:"name"` //应用名称
Type int `json:"type"` //应用类型
AppKey string `json:"app_key"` //Key
Status int `json:"status"` //状态
}

137
business/model/bill.go Normal file
View File

@@ -0,0 +1,137 @@
package model
const (
BillTypeDeposit = 10 //发布任务
BillTypeJob = 11 //做任务实得
BillTypeJobCancelOverdue = 12 //任务过期或取消
BillTypeJobAuditUnPassWithCancelOverdue = 13 //任务不通过时,任务已取消或过期
BillTypeSpJob = 14 //特殊任务扣除
BillTypeDivide = 15 //群员做任务分成
BillTypeJobDivide = 16 //做任务实得(被扣除分成后)
BillTypeDropShipping = 17 //一件代发订单扣除
BillTypeDropShippingDeposit = 18 //一件代发保证金
BillTypeUnionShare = 19 //联盟任务分成
BillTypeMember = 20 //开通会员
BillTypePayByAccountBalance = 25 //余额支付
BillTypePayByMixPay1 = 26 //混合支付中的 余额部分状态码
BillTypePayByMixPay2 = 27 //混合支付中的 微信部分状态码
BillMixPayRefund1 = 28 //混合支付 余额部分退款
BillTypeQuitGroup = 30 //退群
BillTypeJdWaybillOverWeight = 40 //京东物流超重扣款
BillTypeCash = 8 //提现
BillTypeInvest = 6 //充值
)
var (
BillTypeNames = map[int]string{
BillTypeDeposit: "发布任务",
BillTypeJob: "做任务实得",
BillTypeJobCancelOverdue: "任务过期或取消",
BillTypeJobAuditUnPassWithCancelOverdue: "任务不通过时,任务已取消或过期",
BillTypeSpJob: "特殊任务扣除",
BillTypeDivide: "群员做任务分成",
BillTypeJobDivide: "做任务实得(被扣除分成后)",
BillTypeDropShipping: "一件代发订单收入/扣除",
BillTypeDropShippingDeposit: "一件代发保证金",
BillTypeMember: "开通会员",
BillTypeQuitGroup: "退群",
BillTypeJdWaybillOverWeight: "京东物流超重扣款",
BillTypeCash: "提现",
BillTypeInvest: "充值",
}
)
//混合支付详情表
type MixPay struct {
ModelIDCUL
OrderID string `orm:"column(order_id)" json:"order_id"` //账单ID 对应order表
BalancePrice int `orm:"column(balance_price)" json:"balance_price"` //余额支付部分
TotalPrice int `orm:"column(total_price)" json:"total_price"` //订单总额
WxPrice int `orm:"column(wx_price)" json:"wx_price"` //微信支付部分
Status int `orm:"column(status)" json:"status"` //订单状态 -1:退款/1:正常
}
func (v *MixPay) TableIndex() [][]string {
return [][]string{
[]string{"OrderID"},
[]string{"CreatedAt"},
}
}
//账单收入表
type BillIncome struct {
ModelIDCUL
BillID int64 `orm:"column(bill_id)" json:"billID"` //账单ID
JobID int `orm:"column(job_id)" json:"jobID"` //任务ID
Type int `json:"type"` //收入类型
IncomePrice int `json:"incomePrice"` //收入金额
}
func (v *BillIncome) TableIndex() [][]string {
return [][]string{
[]string{"BillID"},
[]string{"CreatedAt"},
}
}
//账单支出表
type BillExpend struct {
ModelIDCUL
BillID int64 `orm:"column(bill_id)" json:"billID"` //账单ID
JobID int `orm:"column(job_id)" json:"jobID"` //任务ID
Type int `json:"type"` //支出类型
ExpendPrice int `json:"expendPrice"` //支出金额
}
func (v *BillExpend) TableIndex() [][]string {
return [][]string{
[]string{"BillID"},
[]string{"CreatedAt"},
}
}
//用户账单表
type UserBill struct {
ModelIDCULD
BillID int64 `orm:"column(bill_id)" json:"billID"` //账单ID
UserID string `orm:"column(user_id)" json:"userID"` //用户ID
AccountBalance int `orm:"column(account_balance)" json:"accountBalance"` //账户余额
}
func (v *UserBill) TableUnique() [][]string {
return [][]string{
[]string{"UserID"},
}
}
func (v *UserBill) TableIndex() [][]string {
return [][]string{
[]string{"BillID"},
[]string{"CreatedAt"},
[]string{"AccountBalance"},
}
}
type UnionOrderSettle struct {
ModelIDCUL
BillID int64 `orm:"column(bill_id)" json:"billID"` //账单ID
VendorID int `orm:"column(vendor_id)" json:"vendorID"` //平台ID
Issue int `json:"issue"` //期数
EarningPrice int `json:"earningPrice"` //结算金额
OrderCount int `json:"orderCount"` //当期有效推广订单数量
Comment string `json:"comment"` //备注
}
func (v *UnionOrderSettle) TableUnique() [][]string {
return [][]string{
[]string{"BillID", "VendorID", "Issue"},
}
}

View File

@@ -0,0 +1,12 @@
package model
type CasbinRule struct {
ID int `orm:"column(id)" json:"id"`
PType string
V0 string `orm:"index"`
V1 string `orm:"index"`
V2 string
V3 string
V4 string
V5 string
}

View File

@@ -1,9 +1,12 @@
package model
import (
"fmt"
"git.rosy.net.cn/baseapi/platformapi/ebaiapi"
"git.rosy.net.cn/baseapi/platformapi/jdapi"
"git.rosy.net.cn/baseapi/platformapi/mtwmapi"
"git.rosy.net.cn/jx-callback/globals"
)
var (
@@ -22,14 +25,12 @@ var (
},
}
//ShopChineseNames = map[int]string{
// VendorIDJD: globals.StoreName,
// VendorIDMTWM: globals.StoreNameMtwm,
// VendorIDELM: globals.StoreNameEbai,
// VendorIDEBAI: globals.StoreNameEbai,
// VendorIDJX: fmt.Sprintf("%s商城", globals.StoreName),
// VendorIDWSC: "微盟微商城",
//}
ShopChineseNames = map[int]string{
VendorIDJD: globals.StoreName,
VendorIDMTWM: globals.StoreNameMtwm,
VendorIDEBAI: globals.StoreNameEbai,
VendorIDJX: fmt.Sprintf("%s商城", globals.StoreName),
}
OrderStatusName = map[int]string{
OrderStatusMsg: "通知消息",
@@ -74,7 +75,6 @@ var (
WaybillStatusPending: "压单",
WaybillStatusAcceptCanceled: "取消接受",
WaybillStatusAccepted: "已接单",
WaybillStatusCourierAssigned: "已分配骑手",
WaybillStatusCourierArrived: "已到店",
WaybillStatusApplyFailedGetGoods: "取货失败待审核",
WaybillStatusAgreeFailedGetGoods: "取货失败",
@@ -83,6 +83,7 @@ var (
WaybillStatusDelivered: "送达",
WaybillStatusCanceled: "取消",
WaybillStatusFailed: "失败",
WaybillStatusCourierAssigned: "已分配骑手",
}
OrderTypeName = map[int]string{
OrderTypeOrder: "订单",
@@ -90,6 +91,15 @@ var (
OrderTypeAfsOrder: "售后单",
}
UnionOrderStatusName = map[int]string{
UnionOrderStatusNew: "新订单",
UnionOrderStatusPay: "用户已支付",
UnionOrderStatusTakeOver: "用户已确认收货",
UnionOrderStatusAuditOver: "已审核",
UnionOrderStatusFinish: "已完成(已结算)",
UnionOrderStatusFail: "已退款(结算失败)",
}
ComplaintReasons = map[int]string{
ComplaintReasons1: "骑手态度恶劣",
ComplaintReasons2: "骑手接单后未取货",
@@ -114,13 +124,6 @@ var (
// OperateCopyStoreSkus: "复制门店商品",
}
//ThingTypeName = map[int]string{
// ThingTypeCategory: "分类",
// ThingTypeSku: "门店商品",
// ThingTypeSkuName: "商品库",
// ThingTypeStore: "门店",
//}
ApiFunctionName = map[string]string{
"UpdateStoresSkus": "门店商品管理",
"UpdateStoresSkusSale": "门店商品可售状态修改",
@@ -146,7 +149,6 @@ var (
MultiStoresVendorMap = map[int]int{
VendorIDJD: 1,
VendorIDMTWM: 0,
VendorIDELM: 0,
VendorIDEBAI: 0,
}
@@ -180,11 +182,6 @@ var (
"打印机ID",
"打印机密钥",
},
VendorIDJxprint: []string{
VendorChineseNames[VendorIDJxprint],
"打印机编号",
"不填",
},
}
AfsReasonTypeName = map[int]string{
AfsReasonTypeGoodsQuality: "商品质量",
@@ -208,27 +205,14 @@ var (
0: "休息",
1: "营业",
}
UnionOrderStatusName = map[int]string{
UnionOrderStatusNew: "新订单",
UnionOrderStatusPay: "用户已支付",
UnionOrderStatusTakeOver: "用户已确认收货",
UnionOrderStatusAuditOver: "已审核",
UnionOrderStatusFinish: "已完成(已结算)",
UnionOrderStatusFail: "已退款(结算失败)",
JobLimitCountType = map[int]string{
JobLimitCountTypePO: "每人一次",
JobLimitCountTypePDO: "每人一天一次",
JobLimitCountTypePWO: "每人一周一次",
JobLimitCountTypeNoLimit: "不限次",
}
)
//联盟订单状态
const (
UnionOrderStatusNew = 10 //已领券?还未支付
UnionOrderStatusPay = 15 //已支付
UnionOrderStatusTakeOver = 20 //确认收货,已收到货
UnionOrderStatusAuditOver = 25 //审核成功,待结算
UnionOrderStatusFinish = 110 //已结算
UnionOrderStatusFail = 115 //审核失败,结算失败
)
const (
OrderTypeOrder = 1
OrderTypeWaybill = 2
@@ -283,33 +267,38 @@ const (
OrderStatusEndBegin = 100 // 以下的状态就是结束状态
OrderStatusFinished = 110 // 订单已完成
OrderStatusConfirm = 112 //一件代发订单确认收货
OrderStatusCanceled = 115 // 订单已取消
OrderStatusEndEnd = 120
OrderStatusRejection = 132 // 客户拒收
OrderStatusCustomerService = 131 // 客服退款
AfsOrderStatusWait4Approve = 155 // 待审核售后单
AfsOrderStatusNew = 160 // 已审核或不需要审核售后单
AfsOrderStatusWait4ReceiveGoods = 165 // 退款退货的,需要商家确认收到货
AfsOrderStatusReceivedGoods = 167 // 已确认收到货
AfsOrderStatusFinished = 180 // 售后单成功完成
AfsOrderStatusFailed = 190 // 售后单失败
)
const (
ApplyOrderCancel = 140 // 申请取消
ApplyOrderRefund = 130 // 申请退款
OrderStatusRejection = 132 // 客户拒收
OrderStatusCustomerService = 131 // 客服退款
ApplyOrderCancel = 140 // 申请取消
ApplyOrderRefundGoods = 150 // 申请退款
UserInStoreConsultingService = 160 // 进店咨询
BusinessCancelOrder = 170 // 商家取消打印
CancelOrderSuccess = 170 // 取消成功打印
OrderRefundMoneySuccess = 180 // 退款成功打印
)
//联盟订单状态
const (
LockStatusUnlocked = 0
LockStatusLocked = 1
UnionOrderStatusNew = 10 //已领券?还未支付
UnionOrderStatusPay = 15 //已支付
UnionOrderStatusTakeOver = 20 //确认收货,已收到货
UnionOrderStatusAuditOver = 25 //审核成功,待结算
UnionOrderStatusFinish = 110 //已结算
UnionOrderStatusFail = 115 //审核失败,结算失败
)
//投诉原因
@@ -341,31 +330,27 @@ const (
WaybillStatusRefuseFailedGetGoods = -70
WaybillStatusUnknown = 0
WaybillStatusNew = 5 // 新建订单
WaybillStatusPending = 7 //
WaybillStatusAcceptCanceled = 8 // 取消运单
WaybillStatusAccepted = 10 // 分配骑手,正在接单
WaybillStatusCourierAssigned = 12 //已分配骑手
WaybillStatusCourierArrived = 15 // 此状态是可选的,明确写出来是因为还是较重要的状态,但业务逻辑不应依赖此状态
WaybillStatusNew = 5
WaybillStatusPending = 7
WaybillStatusAcceptCanceled = 8
WaybillStatusAccepted = 10
WaybillStatusCourierArrived = 15 // 此状态是可选的,明确写出来是因为还是较重要的状态,但业务逻辑不应依赖此状态
WaybillStatusApplyFailedGetGoods = 17 // 取货失败待审核
WaybillStatusAgreeFailedGetGoods = 18 // 取货失败
WaybillStatusDelivering = 20 // 配送中
WaybillStatusDeliverFailed = 22 // 配送中失败
WaybillStatusDeliverReminder = 30 // 催单
WaybillStatusDelivering = 20
WaybillStatusDeliverFailed = 22
WaybillStatusEndBegin = 100 // 以下的状态就是结束状态
WaybillStatusDelivered = 105 // todo 这个应该改为110与订单对应
WaybillStatusCanceled = 115
WaybillStatusFailed = 120 // 这个状态存在的意义是区分于WaybillStatusCanceled比如达达平台在这种状态下再次创建运单的方式不一样
WaybillStatusEndEnd = 120
)
const (
BusinessTypeImmediate = 1
BusinessTypeDingshida = 2
WaybillStatusCourierAssigned = 12 //已分配骑手
WaybillStatusDeliverReminder = 30 // 催单
)
var (
@@ -375,52 +360,6 @@ var (
}
)
const (
JdPlatformFeeRate = 10
MtPlatformFeeRate = 10
)
const (
OrderDeliveryFlagMaskScheduleDisabled = 1 // 禁止三方配送调度
OrderDeliveryFlagMaskPurcahseDisabled = 2 // 购物平台已不配送(一般为门店配送类型本身为自配送,或已经转自配送)
OrderDeliveryFlagMaskAutoPickup = 4 // 是否是自动拣货的
OrderDeliveryFlagMaskDada = 16 // 创建达达运单中
OrderDeliveryFlagMaskMtps = 32 // 创建美团配送运单中
)
const (
WaybillDeliveryFlagMaskActiveCancel = 1 // 主动取消
)
const (
OrderFlagMaskPrinted = 1 // 已经打印
OrderFlagMaskUserApplyCancel = 6
OrderFlagAgreeUserApplyCancel = 2
OrderFlagRefuseUserApplyCancel = 6
OrderFlagMaskFailedGetGoods = 24
OrderFlagAgreeFailedGetGoods = 8
OrderFlagRefuseFailedGetGoods = 24
OrderFlagMaskFailedDeliver = 32
OrderFlagMaskCallPMCourier = 64 // 取货失败后召唤平台配送
OrderFlagMaskSetDelivered = 128 // 设置送达
OrderFlagMaskFake = 256 // 假订单,即刷单用的
OrderFlagMaskTempJX = 512 // 临时京西订单
)
const (
AfsOrderFlagMaskUserRefund = 3 // 门店处理售后单申请
AfsOrderFlagAgreeUserRefund = 1 // 门店同意售后单申请
AfsOrderFlagRefuseUserRefund = 3 // 门店拒绝售后单申请
AfsOrderFlagMaskReturnGoods = 4 // 门店确认收到退货
)
const (
AfsAppealTypeRefund = 1 // 仅退款
AfsAppealTypeReturnAndRefund = 2 // 退货退款
@@ -441,12 +380,6 @@ const (
AfsReasonNotOthers = 0 // 其它
)
const (
AfsTypeUnknown = 0 // 未知
AfsTypePartRefund = 1 // 部分退款
AfsTypeFullRefund = 2 // 全额退款
)
const (
DefaultEarningPricePercentage = 70 // 门店缺省结算百分比
@@ -456,39 +389,11 @@ const (
)
const (
YES = 1 //通用
NO = 0
DISABLED = -1
B2BTag = "B2B"
B2BNumberId = 10
YES = 1 //通用
NO = 0
DISABLED = -1
)
const (
WeChatQrCode = "weChat"
TiktokQrCode = "tiktok"
)
const (
DefaultName = "石锋"
DefaultPhone = "18048531223"
DefaultIdCard = "610126198012230014"
)
func IsPurchaseVendorExist(vendorID int) bool {
_, ok := VendorNames[vendorID]
return ok && vendorID >= VendorIDPurchaseBegin && vendorID <= VendorIDPurchaseEnd
}
func IsDeliveryVendorExist(vendorID int) bool {
_, ok := VendorNames[vendorID]
return ok && vendorID >= VendorIDDeliveryBegin && vendorID <= VendorIDDeliveryEnd
}
func IsPrinterVendorExist(vendorID int) bool {
_, ok := VendorNames[vendorID]
return ok && vendorID >= VendorIDPrinterBegin && vendorID <= VendorIDPrinterEnd
}
func IsOrderLockStatus(status int) bool {
return status == OrderStatusLocked || status == OrderStatusApplyCancel
}
@@ -513,15 +418,6 @@ func IsVendorRemote(vendorID int) bool {
return vendorID >= VendorIDJD && vendorID <= VendorIDEBAI
}
func WaybillVendorID2Mask(vendorID int) (mask int8) {
if vendorID == VendorIDDada {
mask = OrderDeliveryFlagMaskDada
} else if vendorID == VendorIDMTPS {
mask = OrderDeliveryFlagMaskMtps
}
return mask
}
func IsAfsOrderFinalStatus(status int) bool {
return status >= AfsOrderStatusFinished && status <= AfsOrderStatusFailed
}
@@ -529,405 +425,3 @@ func IsAfsOrderFinalStatus(status int) bool {
func IsWaybillFinalStatus(status int) bool {
return status >= WaybillStatusEndBegin && status <= WaybillStatusEndEnd
}
const (
JXC4AppId = "wx4b5930c13f8b1170" // 京西菜市appId
JXC4BusinessAppId = "wx08a5c2a8581414ff" // 京西商家appId
JXC4TiktokAppId = "tta6a1d01c399f264201" // 抖音appID
)
//package model
//
//import (
// "git.rosy.net.cn/baseapi/platformapi/ebaiapi"
// "git.rosy.net.cn/baseapi/platformapi/jdapi"
// "git.rosy.net.cn/baseapi/platformapi/mtwmapi"
//)
//
//var (
// PurchaseVendorInfo = map[int]map[string]interface{}{
// VendorIDJD: map[string]interface{}{
// "chineseName": VendorChineseNames[VendorIDJD],
// "userApplyCancelWaitMinute": jdapi.UserApplyCancelWaitMinute,
// },
// VendorIDMTWM: map[string]interface{}{
// "chineseName": VendorChineseNames[VendorIDMTWM],
// "userApplyCancelWaitMinute": mtwmapi.UserApplyCancelWaitMinute,
// },
// VendorIDEBAI: map[string]interface{}{
// "chineseName": VendorChineseNames[VendorIDEBAI],
// "userApplyCancelWaitMinute": ebaiapi.UserApplyCancelWaitMinute,
// },
// }
//
// OrderStatusName = map[int]string{
// OrderStatusMsg: "通知消息",
// OrderStatusWaybillTipChanged: "小费变动",
// OrderStatusRefuseFailedGetGoods: "取货失败审核驳回",
// OrderStatusAdjust: "订单调整完成",
// OrderStatusApplyUrgeOrder: "催单",
//
// OrderStatusUnlocked: "解锁",
// OrderStatusLocked: "锁定",
// // OrderStatusApplyRefund: "申请退款",
// OrderStatusUndoApplyCancel: "取消申请取消",
// OrderStatusVendorRejectCancel: "拒绝取消",
// OrderStatusVendorAgreeCancel: "同意取消",
// OrderStatusApplyCancel: "申请取消",
//
// OrderStatusUnknown: "一般事件",
//
// OrderStatusWait4Pay: "待付款",
// OrderStatusNew: "新订单",
// OrderStatusWaitAccepted: "待接单",
// OrderStatusAccepted: "待拣货",
// OrderStatusFinishedPickup: "待配送",
// OrderStatusApplyFailedGetGoods: "取货失败待审核",
// OrderStatusAgreeFailedGetGoods: "取货失败",
// OrderStatusDelivering: "配送中",
// OrderStatusDeliverFailed: "投递失败",
// OrderStatusFinished: "完成",
// OrderStatusCanceled: "取消",
//
// AfsOrderStatusWait4Approve: "待审核",
// AfsOrderStatusNew: "已审核",
// AfsOrderStatusWait4ReceiveGoods: "退货待确认",
// AfsOrderStatusReceivedGoods: "退货已收到",
// AfsOrderStatusFinished: "售后成功",
// AfsOrderStatusFailed: "售后失败",
// }
// WaybillStatusName = map[int]string{
// WaybillStatusUnknown: "一般事件",
//
// WaybillStatusNew: "新运单",
// WaybillStatusPending: "压单",
// WaybillStatusAcceptCanceled: "取消接受",
// WaybillStatusAccepted: "已接单",
// WaybillStatusCourierArrived: "已到店",
// WaybillStatusApplyFailedGetGoods: "取货失败待审核",
// WaybillStatusAgreeFailedGetGoods: "取货失败",
// WaybillStatusDelivering: "配送中",
// WaybillStatusDeliverFailed: "投递失败",
// WaybillStatusDelivered: "送达",
// WaybillStatusCanceled: "取消",
// WaybillStatusFailed: "失败",
// }
// OrderTypeName = map[int]string{
// OrderTypeOrder: "订单",
// OrderTypeWaybill: "运单",
// OrderTypeAfsOrder: "售后单",
// }
//
// UnionOrderStatusName = map[int]string{
// UnionOrderStatusNew: "新订单",
// UnionOrderStatusPay: "用户已支付",
// UnionOrderStatusTakeOver: "用户已确认收货",
// UnionOrderStatusAuditOver: "已审核",
// UnionOrderStatusFinish: "已完成(已结算)",
// UnionOrderStatusFail: "已退款(结算失败)",
// }
//
// ComplaintReasons = map[int]string{
// ComplaintReasons1: "骑手态度恶劣",
// ComplaintReasons2: "骑手接单后未取货",
// ComplaintReasons3: "骑手取货太慢",
// ComplaintReasons4: "骑手送货太慢",
// ComplaintReasons5: "货品未送达",
// ComplaintReasons6: "货品有损坏",
// ComplaintReasons7: "骑手违规收取顾客其他费用",
// ComplaintReasons69: "骑手恶意取消订单",
// ComplaintReasons71: "骑手提前点击取货/送达",
// }
//
// SupplementTypeName = map[int]string{
// BadAppraiseSupplement: "差评退款",
// Coupon: "优惠券",
// }
//
// OperateTypeName = map[int]string{
// OperateAdd: "新增",
// OperateUpdate: "修改",
// OperateDelete: "删除",
// // OperateCopyStoreSkus: "复制门店商品",
// }
//
// ApiFunctionName = map[string]string{
// "UpdateStoresSkus": "门店商品管理",
// "UpdateStoresSkusSale": "门店商品可售状态修改",
// "CopyStoreSkus": "京西门店商品复制到京西",
// "UpdateStore": "门店管理-更新门店信息",
// "CreateStore": "门店管理-创建门店",
// "DeleteStore": "门店管理-删除门店",
// "DeleteStoreVendorMap": "门店解绑",
// "AddStoreVendorMap": "门店绑定",
// "UpdateStoreVendorMap": "门店修改平台绑定信息",
// "DeleteStoreCourierMap": "门店解绑三方配送平台",
// "AddStoreCourierMap": "门店绑定三方配送平台",
// "UpdateStoreCourierMap": "门店修改三方配送平台绑定信息",
// "Login": "登录",
// "RegisterUser": "注册",
// "AutoPayForPopluarMan": "每日订单打款",
// "SyncStoresQualify": "上传门店营业资质",
// "CancelOrder": "取消订单",
// "UpdateSku": "修改sku",
// "UpdateSkuName": "修改skuName",
// }
//
// MultiStoresVendorMap = map[int]int{
// VendorIDJD: 1,
// VendorIDMTWM: 0,
// VendorIDEBAI: 0,
// }
//
// ZXCityCodeMap = map[int]string{
// 310100: "上海市",
// 110100: "北京市",
// 120100: "天津市",
// 440300: "深圳市",
// 500100: "重庆市",
// 441900: "东莞",
// }
//
// PrinterVendorInfo = map[int][]string{
// VendorIDFeiE: []string{
// VendorChineseNames[VendorIDFeiE],
// "序列号",
// "KEY",
// },
// VendorIDXiaoWM: []string{
// VendorChineseNames[VendorIDXiaoWM],
// "打印机编号",
// "不填",
// },
// VendorIDYiLianYun: []string{
// VendorChineseNames[VendorIDYiLianYun],
// "终端号",
// "密钥",
// },
// VendorIDZhongWu: []string{
// VendorChineseNames[VendorIDZhongWu],
// "打印机ID",
// "打印机密钥",
// },
// }
// AfsReasonTypeName = map[int]string{
// AfsReasonTypeGoodsQuality: "商品质量",
// AfsReasonTypeWrongGoods: "错误的商品",
// AfsReasonTypeMissingGoods: "缺少部分商品",
// AfsReasonTypeNoGoods: "全部商品未收到",
// AfsReasonTypeDamagedGoods: "商品有损伤",
// AfsReasonTypeGoodsQuantity: "缺斤少两",
// AfsReasonTypeGoodsAbsent: "商家通知我缺货",
// AfsReasonTypeGoodsNoSame: "商品与描述不符",
// AfsReasonWrongPurchase: "误购",
// AfsReasonNotReceivedIntime: "未在时效内送达",
// AfsReasonNotOthers: "其它",
// }
// AfsAppealTypeName = map[int]string{
// AfsAppealTypeRefund: "仅退款",
// AfsAppealTypeReturnAndRefund: "退款", // 这个其实是退货退款,强制显示成退款
// AfsAppealTypeNewGoods: "退款.", // 这个其实是重发商品,强制显示成退款
// }
// VendorStatus = map[int]string{
// 0: "休息",
// 1: "营业",
// }
//)
//
//const (
// OrderTypeOrder = 1
// OrderTypeWaybill = 2
// OrderTypeAfsOrder = 3
//)
//
//// https://blog.csdn.net/a13570320979/article/details/51366355
//// 美团配送:
//// 坐标类型0火星坐标高德腾讯地图均采用火星坐标 1百度坐标 默认值为0
//// 京东:
//// 收货人地址定位类型buyerCoordType值为空或为1时定位类型为gps如为其他值时定位类型为非gps类型。)
//// 饿了么:
//// 只支持高德坐标
//// 达达:
//// 只支持高德坐标
//// 如下定义与美团配送兼容
//const (
// CoordinateTypeMars = 0 // 火星坐标高德坐标GCJ02坐标系
// CoordinateTypeBaiDu = 1 // 百度坐标bd-09在GCJ02坐标系上再次偏移加密的坐标
// CoordinateTypeMapbar = 2
// CoordinateTypeGPS = 84 // 真实坐标WGS84原始坐标系
//)
//
//const (
// OrderStatusMsg = -100
//
// OrderStatusWaybillTipChanged = -80 // 订单小费变化
//
// OrderStatusRefuseFailedGetGoods = -70 // 取货失败审核驳回
// OrderStatusAdjust = -65 // 原值-35 订单调整完成
// OrderStatusApplyUrgeOrder = -55 // 原值-15
//
// OrderStatusUnlocked = -25
// OrderStatusLocked = -20
// OrderStatusUndoApplyCancel = -10
// OrderStatusVendorRejectCancel = -7
// OrderStatusVendorAgreeCancel = -6
// OrderStatusApplyCancel = -5
//
// OrderStatusUnknown = 0
// OrderStatusWait4Pay = 2 // 原值-60 下单待支付
// OrderStatusWaitAccepted = 3 // 待接单,目前饿百用
// OrderStatusNew = 5 // 新订单,实际是已经支付
// OrderStatusAccepted = 10 // 已经接单,也即待出库,待拣货
// OrderStatusFinishedPickup = 15 // 拣货完成
//
// OrderStatusApplyFailedGetGoods = 17 // 取货失败待审核
// OrderStatusAgreeFailedGetGoods = 18 // 取货失败
//
// OrderStatusDelivering = 20 // 开始配送,配送员已取货,从这里开始就是运单消息了
// OrderStatusDeliverFailed = 22 // 投递失败
//
// OrderStatusEndBegin = 100 // 以下的状态就是结束状态
// OrderStatusFinished = 110 // 订单已完成
// OrderStatusConfirm = 112 //一件代发订单确认收货
// OrderStatusCanceled = 115 // 订单已取消
// OrderStatusEndEnd = 120
//
// AfsOrderStatusWait4Approve = 155 // 待审核售后单
// AfsOrderStatusNew = 160 // 已审核或不需要审核售后单
// AfsOrderStatusWait4ReceiveGoods = 165 // 退款退货的,需要商家确认收到货
// AfsOrderStatusReceivedGoods = 167 // 已确认收到货
// AfsOrderStatusFinished = 180 // 售后单成功完成
// AfsOrderStatusFailed = 190 // 售后单失败
//)
//
////联盟订单状态
//const (
// UnionOrderStatusNew = 10 //已领券?还未支付
// UnionOrderStatusPay = 15 //已支付
// UnionOrderStatusTakeOver = 20 //确认收货,已收到货
// UnionOrderStatusAuditOver = 25 //审核成功,待结算
//
// UnionOrderStatusFinish = 110 //已结算
// UnionOrderStatusFail = 115 //审核失败,结算失败
//)
//
////投诉原因
//const (
// ComplaintReasons1 = 1 //"骑手态度恶劣",
// ComplaintReasons2 = 2 //"骑手接单后未取货"
// ComplaintReasons3 = 3 //"骑手取货太慢",
// ComplaintReasons4 = 4 //"骑手送货太慢",
// ComplaintReasons5 = 5 //"货品未送达",
// ComplaintReasons6 = 6 //"货品有损坏",
// ComplaintReasons7 = 7 //"骑手违规收取顾客其他费用",
// ComplaintReasons69 = 69 //"骑手恶意取消订单",
// ComplaintReasons71 = 71 //"骑手提前点击取货/送达",
//)
//
//const (
// BadAppraiseSupplement = 1 //差评退款
// Coupon = 2 //优惠券
//)
//
//const (
// OperateAdd = 2 //新增操作
// OperateUpdate = 1 //修改操作
// OperateDelete = 4 //删除操作
// OperateCopyStoreSkus = 3 //复制门店商品
//)
//
//const (
// WaybillStatusRefuseFailedGetGoods = -70
// WaybillStatusUnknown = 0
//
// WaybillStatusNew = 5
// WaybillStatusPending = 7
// WaybillStatusAcceptCanceled = 8
// WaybillStatusAccepted = 10
// WaybillStatusCourierArrived = 15 // 此状态是可选的,明确写出来是因为还是较重要的状态,但业务逻辑不应依赖此状态
//
// WaybillStatusApplyFailedGetGoods = 17 // 取货失败待审核
// WaybillStatusAgreeFailedGetGoods = 18 // 取货失败
//
// WaybillStatusDelivering = 20
// WaybillStatusDeliverFailed = 22
//
// WaybillStatusEndBegin = 100 // 以下的状态就是结束状态
// WaybillStatusDelivered = 105 // todo 这个应该改为110与订单对应
// WaybillStatusCanceled = 115
// WaybillStatusFailed = 120 // 这个状态存在的意义是区分于WaybillStatusCanceled比如达达平台在这种状态下再次创建运单的方式不一样
// WaybillStatusEndEnd = 120
//)
//
//var (
// ElmSkuPromotion = map[int]int{
// 11: 1,
// 200: 1,
// }
//)
//
//const (
// AfsAppealTypeRefund = 1 // 仅退款
// AfsAppealTypeReturnAndRefund = 2 // 退货退款
// AfsAppealTypeNewGoods = 3 // 重发新商品(即京东到家的直赔)
//)
//
//const (
// AfsReasonTypeGoodsQuality = 1 // 商品质量
// AfsReasonTypeWrongGoods = 2 // 错误的商品
// AfsReasonTypeMissingGoods = 3 // 缺少部分商品
// AfsReasonTypeNoGoods = 4 // 全部商品未收到
// AfsReasonTypeDamagedGoods = 5 // 商品有损伤
// AfsReasonTypeGoodsQuantity = 6 // 缺斤少两
// AfsReasonTypeGoodsAbsent = 7 // 商家通知缺货
// AfsReasonTypeGoodsNoSame = 8 // 商品与描述不符
// AfsReasonWrongPurchase = 9 // 误购
// AfsReasonNotReceivedIntime = 10 // 未在时效内送达
// AfsReasonNotOthers = 0 // 其它
//)
//
//const (
// DefaultEarningPricePercentage = 70 // 门店缺省结算百分比
//
// MinVendorPricePercentage = 10
// DefVendorPricePercentage = 100 // 平台缺省调价比例
// MaxVendorPricePercentage = 400
//)
//
//const (
// YES = 1 //通用
// NO = 0
// DISABLED = -1
//)
//
//func IsOrderLockStatus(status int) bool {
// return status == OrderStatusLocked || status == OrderStatusApplyCancel
//}
//
//func IsOrderUnlockStatus(status int) bool {
// return status == OrderStatusUnlocked || status == OrderStatusUndoApplyCancel || status == OrderStatusVendorAgreeCancel || status == OrderStatusVendorRejectCancel
//}
//
//func IsOrderMainStatus(status int) bool {
// return status > OrderStatusUnknown
//}
//
//func IsOrderFinalStatus(status int) bool {
// return status >= OrderStatusEndBegin && status <= OrderStatusEndEnd
//}
//
//func IsOrderImportantStatus(status int) bool {
// return IsOrderMainStatus(status) || IsOrderLockStatus(status) || IsOrderUnlockStatus(status)
//}
//
//func IsVendorRemote(vendorID int) bool {
// return vendorID >= VendorIDJD && vendorID <= VendorIDEBAI
//}
//
//func IsAfsOrderFinalStatus(status int) bool {
// return status >= AfsOrderStatusFinished && status <= AfsOrderStatusFailed
//}
//
//func IsWaybillFinalStatus(status int) bool {
// return status >= WaybillStatusEndBegin && status <= WaybillStatusEndEnd
//}

609
business/model/dao/act.go Normal file
View File

@@ -0,0 +1,609 @@
package dao
import (
"fmt"
"time"
"git.rosy.net.cn/jx-callback/globals"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/model"
)
type ActMapPureInfo struct {
VendorID int `orm:"column(vendor_id)" json:"vendorID"`
VendorOrgCode string `orm:"size(32)" json:"vendorOrgCode"` // 同一平台下不同的商户代码,如果只有一个,可以为空
VendorActID string `orm:"column(vendor_act_id);size(48)" json:"vendorActID"`
SyncStatus int `orm:"default(2)" json:"syncStatus"`
Remark string `orm:"column(map_remark)" json:"remark"`
}
type ActVendorInfo struct {
model.Act
VendorList []*ActMapPureInfo `json:"vendorList"`
}
type tActAndMap struct {
model.Act
MapID int `orm:"column(map_id)" json:"-"` // 内部使用,不暴露
ActMapPureInfo
}
type PagedActListInfo struct {
TotalCount int `json:"totalCount"`
Data []*ActVendorInfo `json:"data"`
}
func GetActVendorInfo(db *DaoDB, actID int, vendorIDs []int) (actMap map[int]*model.Act2, err error) {
leftOrEmpty := ""
if len(vendorIDs) == 1 && vendorIDs[0] == -1 {
leftOrEmpty = "LEFT"
}
sql := fmt.Sprintf(`
SELECT t1.*,
t2.id map_id, t2.vendor_id, t2.vendor_org_code, t2.vendor_act_id, t2.sync_status
FROM act t1
%s JOIN act_map t2 ON t2.act_id = t1.id AND t2.deleted_at = ?`, leftOrEmpty)
sqlParams := []interface{}{
utils.DefaultTimeValue,
}
if len(vendorIDs) > 0 {
sql += " AND t2.vendor_id IN (" + GenQuestionMarks(len(vendorIDs)) + ")"
sqlParams = append(sqlParams, vendorIDs)
}
sql += `
WHERE t1.deleted_at = ? AND t1.id = ?`
sqlParams = append(sqlParams, utils.DefaultTimeValue, actID)
var actList []*model.Act2
if err = GetRows(db, &actList, sql, sqlParams...); err == nil {
actMap = make(map[int]*model.Act2)
for _, v := range actList {
if leftOrEmpty != "" {
v.VendorID = -1
}
actMap[v.VendorID] = v
}
}
return actMap, err
}
func GetActStoreSkuVendorList(db *DaoDB, actID int, vendorIDs, storeIDs, skuIDs []int, keyword string, offset, pageSize int) (totalCount int, actStoreSkuList []*model.ActStoreSku2, err error) {
// globals.SugarLogger.Debugf("GetActStoreSkuVendorList actID:%d", actID)
// offset = jxutils.FormalizePageOffset(offset)
// pageSize = jxutils.FormalizePageSize(pageSize)
// leftOrEmpty := ""
// if len(vendorIDs) == 1 && (vendorIDs[0] == -1 || vendorIDs[0] == model.VendorIDJX) {
// leftOrEmpty = "LEFT"
// }
// sql := fmt.Sprintf(`
// SELECT SQL_CALC_FOUND_ROWS
// t1.*,
// t2.id map_id, t2.vendor_id, t2.vendor_act_id, t2.sync_status, t2.actual_act_price, t2.vendor_price, t2.trend_type, t2.trend_price,
// t3.vendor_store_id,
// CASE t2.vendor_id
// WHEN 0 THEN
// t4m.vendor_thing_id
// WHEN 1 THEN
// t5.mtwm_id
// WHEN 3 THEN
// t5.ebai_id
// ELSE
// ''
// END vendor_sku_id,
// t4.comment, t4.spec_quality, t4.spec_unit,
// t6.name store_name,
// t7.name sku_name_name, t7.unit, t7.prefix, t7.ex_prefix, t7.ex_prefix_begin, t7.ex_prefix_end
// FROM act_store_sku t1
// %s JOIN act_store_sku_map t2 ON t2.act_id = ? AND t2.bind_id = t1.id AND t2.deleted_at = ?`, leftOrEmpty)
// sqlParams := []interface{}{
// actID,
// utils.DefaultTimeValue,
// }
// if len(vendorIDs) > 0 {
// sql += " AND t2.vendor_id IN (" + GenQuestionMarks(len(vendorIDs)) + ")"
// sqlParams = append(sqlParams, vendorIDs)
// }
// sql += `
// LEFT JOIN store_map t3 ON t3.store_id = t1.store_id AND t3.vendor_id = t2.vendor_id AND t3.deleted_at = ?
// JOIN sku t4 ON t4.id = t1.sku_id
// LEFT JOIN thing_map t4m ON t4m.vendor_id = ? AND t4m.thing_id = t4.id AND t4m.thing_type = ? AND t4m.vendor_id = t2.vendor_id AND t4m.vendor_org_code = t3.vendor_org_code AND t4m.deleted_at = ?
// LEFT JOIN store_sku_bind t5 ON t5.sku_id = t1.sku_id AND t5.store_id = t1.store_id AND t5.deleted_at = ?
// LEFT JOIN store t6 ON t6.id = t1.store_id
// JOIN sku_name t7 ON t7.id = t4.name_id
// WHERE t1.act_id = ?
// `
// sqlParams = append(sqlParams,
// utils.DefaultTimeValue,
// model.VendorIDJD, model.ThingTypeSku, utils.DefaultTimeValue,
// utils.DefaultTimeValue,
// actID,
// )
// if keyword != "" {
// keywordLike := "%" + keyword + "%"
// sql += " AND (t7.name LIKE ? OR t6.name LIKE ?"
// sqlParams = append(sqlParams, keywordLike, keywordLike)
// if intKeyword := int(utils.Str2Int64WithDefault(keyword, 0)); intKeyword > 0 {
// sql += " OR t1.sku_id = ? OR t1.store_id = ?"
// sqlParams = append(sqlParams, intKeyword, intKeyword)
// }
// sql += ")"
// }
// if leftOrEmpty != "" {
// sql += " AND t1.deleted_at = ?"
// sqlParams = append(sqlParams, utils.DefaultTimeValue)
// }
// if len(storeIDs) > 0 {
// sql += " AND t1.store_id IN (" + GenQuestionMarks(len(storeIDs)) + ")"
// sqlParams = append(sqlParams, storeIDs)
// }
// if len(skuIDs) > 0 {
// sql += " AND t1.sku_id IN (" + GenQuestionMarks(len(skuIDs)) + ")"
// sqlParams = append(sqlParams, skuIDs)
// }
// sql += " LIMIT ? OFFSET ?;"
// sqlParams = append(sqlParams, pageSize, offset)
// // globals.SugarLogger.Debug(sql)
// // globals.SugarLogger.Debug(utils.Format4Output(sqlParams, false))
// // globals.SugarLogger.Debug(utils.Format4Output(actStoreSkuList, false))
// Begin(db)
// defer Commit(db)
// if err = GetRows(db, &actStoreSkuList, sql, sqlParams...); err == nil {
// totalCount = GetLastTotalRowCount(db)
// }
return totalCount, actStoreSkuList, err
}
func GetActStoreSkuVendorInfo(db *DaoDB, actID int, vendorIDs, storeIDs, skuIDs []int) (actStoreSkuMap map[int][]*model.ActStoreSku2, err error) {
leftOrEmpty := ""
if len(vendorIDs) == 1 && vendorIDs[0] == -1 {
leftOrEmpty = "LEFT"
}
_, actStoreSkuList, err := GetActStoreSkuVendorList(db, actID, vendorIDs, storeIDs, skuIDs, "", 0, -1)
if err == nil {
actStoreSkuMap = make(map[int][]*model.ActStoreSku2)
for _, v := range actStoreSkuList {
if leftOrEmpty != "" {
v.VendorID = -1
}
actStoreSkuMap[v.VendorID] = append(actStoreSkuMap[v.VendorID], v)
}
}
return actStoreSkuMap, err
}
func QueryActs(db *DaoDB, actID int, offset, pageSize int, syncStatus int, keyword string, vendorID int, statusList, actTypeList, createTypeList []int,
storeID int, skuIDs []int, cityCode int, beginAt, endAt, createdAtFrom, createdAtTo time.Time) (pagedInfo *PagedActListInfo, err error) {
if actID == 0 && utils.IsTimeZero(createdAtFrom) && utils.IsTimeZero(beginAt) {
return nil, fmt.Errorf("actID,createdAtFrom和beginAt中至少要指定一个条件")
}
offset = jxutils.FormalizePageOffset(offset)
pageSize = jxutils.FormalizePageSize(pageSize)
isGetAll := offset == 0 && pageSize == model.UnlimitedPageSize
sql := `
SELECT SQL_CALC_FOUND_ROWS
DISTINCT t1.id
FROM act t1`
sqlParams := []interface{}{}
if isGetAll {
sql = `
SELECT
t1.*,
t2.id map_id, t2.vendor_id, t2.vendor_act_id, t2.sync_status, t2.remark map_remark
FROM act t1`
}
sql += " LEFT JOIN act_map t2 ON t2.act_id = t1.id AND t2.deleted_at = ?"
sqlParams = append(sqlParams, utils.DefaultTimeValue)
if syncStatus >= 0 {
sql += " AND (t2.sync_status = ? OR t2.sync_status & ? <> 0)"
sqlParams = append(sqlParams, syncStatus, syncStatus)
}
sql += `
WHERE t1.deleted_at = ?`
if syncStatus >= 0 {
sql += " AND t2.id IS NOT NULL"
}
sqlParams = append(sqlParams, utils.DefaultTimeValue)
keywordInt := int64(0)
if keyword != "" {
keywordLike := "%" + keyword + "%"
sql += " AND ( t1.name LIKE ? OR t1.advertising LIKE ? OR t1.remark LIKE ? OR t2.vendor_act_id LIKE ?"
sqlParams = append(sqlParams, keywordLike, keywordLike, keywordLike, keywordLike)
keywordInt = utils.Str2Int64WithDefault(keyword, 0)
if keywordInt > 0 {
sql += `
OR t1.id = ?`
sqlParams = append(sqlParams, keywordInt)
}
sql += ")"
}
if storeID > 0 || len(skuIDs) > 0 || cityCode > 0 {
sql += ` AND (SELECT COUNT(*)
FROM act_store_sku t2`
if cityCode > 0 {
sql += " JOIN store t3 ON t3.id = t2.store_id AND t3.city_code = ?"
sqlParams = append(sqlParams, cityCode)
}
sql += `
WHERE t2.act_id = t1.id AND t2.deleted_at = ?`
sqlParams = append(sqlParams, utils.DefaultTimeValue)
if storeID > 0 {
sql += " AND t2.store_id = ?"
sqlParams = append(sqlParams, storeID)
}
if len(skuIDs) > 0 {
sql += " AND t2.sku_id IN (" + GenQuestionMarks(len(skuIDs)) + ")"
sqlParams = append(sqlParams, skuIDs)
}
sql += ") > 0"
}
if actID > 0 {
sql += " AND t1.id = ?"
sqlParams = append(sqlParams, actID)
}
if vendorID >= 0 {
sql += " AND t1.vendor_mask & ? <> 0"
sqlParams = append(sqlParams, model.GetVendorMask(vendorID))
}
if len(statusList) > 0 {
sql += " AND t1.status IN (" + GenQuestionMarks(len(statusList)) + ")"
sqlParams = append(sqlParams, statusList)
}
if len(actTypeList) > 0 {
sql += " AND t1.type IN (" + GenQuestionMarks(len(actTypeList)) + ")"
sqlParams = append(sqlParams, actTypeList)
}
if len(createTypeList) > 0 {
sql += " AND t1.create_type IN (" + GenQuestionMarks(len(createTypeList)) + ")"
sqlParams = append(sqlParams, createTypeList)
}
if !utils.IsTimeZero(beginAt) {
sql += " AND t1.begin_at <= ?"
sqlParams = append(sqlParams, beginAt)
}
if !utils.IsTimeZero(endAt) {
sql += " AND t1.end_at >= ?"
sqlParams = append(sqlParams, endAt)
}
if !utils.IsTimeZero(createdAtFrom) {
sql += " AND t1.created_at >= ?"
sqlParams = append(sqlParams, createdAtFrom)
}
if !utils.IsTimeZero(createdAtTo) {
sql += " AND t1.created_at <= ?"
sqlParams = append(sqlParams, createdAtTo)
}
pagedInfo = &PagedActListInfo{}
if isGetAll {
sql += `
ORDER BY t1.id DESC, t2.vendor_id`
} else {
sql += `
ORDER BY 1 DESC
LIMIT ? OFFSET ?
`
sqlParams = append(sqlParams, pageSize, offset)
var idList []int
txDB, _ := Begin(db)
defer func() {
if r := recover(); r != nil {
Rollback(db, txDB)
panic(r)
}
}()
// globals.SugarLogger.Debug(sql)
if err = GetRowsTx(txDB, &idList, sql, sqlParams...); err != nil || len(idList) == 0 {
Rollback(db, txDB)
return pagedInfo, err
}
pagedInfo.TotalCount = GetLastTotalRowCountTx(txDB)
Commit(db, txDB)
sql = `
SELECT
t1.*,
t2.id map_id, t2.vendor_id, t2.vendor_org_code, t2.vendor_act_id, t2.sync_status, t2.remark map_remark
FROM act t1
LEFT JOIN act_map t2 ON t2.act_id = t1.id AND t2.deleted_at = ?
WHERE t1.id IN (` + GenQuestionMarks(len(idList)) + `)`
if syncStatus >= 0 {
sql += " AND t2.id IS NOT NULL"
}
sql += `
ORDER BY t1.id DESC, t2.vendor_id`
sqlParams = []interface{}{
utils.DefaultTimeValue,
idList,
}
}
var actList []*tActAndMap
// globals.SugarLogger.Debug(sql)
if err = GetRows(db, &actList, sql, sqlParams...); err != nil {
return nil, err
}
actMap := make(map[int]*ActVendorInfo)
for _, v := range actList {
tmpAct := actMap[v.ID]
if tmpAct == nil {
tmpAct = &ActVendorInfo{
Act: v.Act,
}
actMap[v.ID] = tmpAct
pagedInfo.Data = append(pagedInfo.Data, tmpAct)
}
if v.MapID > 0 {
tmpAct.VendorList = append(tmpAct.VendorList, &v.ActMapPureInfo)
}
}
if isGetAll {
pagedInfo.TotalCount = len(pagedInfo.Data)
}
return pagedInfo, err
}
func GetExistVendorActIDs(db *DaoDB, vendorID int) (vendorActIDs []string, err error) {
// todo 不应该是全表扫描
sql := `
SELECT
DISTINCT t1.vendor_act_id
FROM act_store_sku_map t1
WHERE t1.deleted_at = ? AND t1.vendor_id = ?`
sqlParams := []interface{}{
utils.DefaultTimeValue,
vendorID,
}
err = GetRows(db, &vendorActIDs, sql, sqlParams...)
return vendorActIDs, err
}
func GetEffectiveActStoreSkuInfo(db *DaoDB, actID int, vendorIDs []int, actType int, storeIDs, skuIDs []int, beginAt, endAt time.Time) (actStoreSkuList []*model.ActStoreSku2, err error) {
if utils.IsTimeZero(beginAt) {
return nil, fmt.Errorf("GeActStoreSkuInfo必须指定活动开始时间")
}
if utils.IsTimeZero(endAt) {
endAt = beginAt
}
sql := `
SELECT
t1.type, t1.discount_type, t1.discount_value1, t1.discount_value2,
t2.*,
t3.actual_act_price, t3.sync_status, t3.vendor_price, t3.vendor_id, t3.trend_type, t3.trend_price
FROM act t1
JOIN act_store_sku t2 ON t2.act_id = t1.id AND t2.deleted_at = ?
JOIN act_store_sku_map t3 ON t3.bind_id = t2.id AND t3.act_id = t1.id AND (t3.sync_status & ? = 0 OR t1.type = ?)
JOIN act_map t4 ON t4.act_id = t1.id AND t4.vendor_id = t3.vendor_id AND t4.deleted_at = ? AND (t4.sync_status & ? = 0 OR t1.type = ?)
WHERE t1.deleted_at = ? AND t1.status = ? AND NOT (t1.begin_at > ? OR t1.end_at < ?) AND t1.create_type = ?`
sqlParams := []interface{}{
utils.DefaultTimeValue,
model.SyncFlagNewMask,
model.ActSkuFake,
utils.DefaultTimeValue, model.SyncFlagNewMask, model.ActSkuFake,
utils.DefaultTimeValue, model.ActStatusCreated, endAt, beginAt, model.ActCreateTypeAPI,
}
if len(vendorIDs) > 0 {
sql += " AND (t1.vendor_mask & ?) <> 0 AND t3.vendor_id IN (" + GenQuestionMarks(len(vendorIDs)) + ")"
sqlParams = append(sqlParams, model.GetVendorMask(vendorIDs...), vendorIDs)
}
if actID > 0 {
sql += " AND t1.id = ?"
sqlParams = append(sqlParams, actID)
}
if actType != model.ActTypeAll {
sql += " AND t1.type = ?"
sqlParams = append(sqlParams, actType)
}
if len(storeIDs) > 0 {
sql += " AND t2.store_id IN (" + GenQuestionMarks(len(storeIDs)) + ")"
sqlParams = append(sqlParams, storeIDs)
}
if len(skuIDs) > 0 {
sql += " AND t2.sku_id IN (" + GenQuestionMarks(len(skuIDs)) + ")"
sqlParams = append(sqlParams, skuIDs)
}
if globals.IsStoreSkuAct {
sql += " AND t1.is_special = 0"
}
err = GetRows(db, &actStoreSkuList, sql, sqlParams...)
return actStoreSkuList, err
}
func GetEffectiveActStoreSkuInfo2(db *DaoDB, actID int, vendorIDs []int, actTypes []int, storeIDs, skuIDs []int, beginAt, endAt time.Time) (actStoreSkuList []*model.ActStoreSku2, err error) {
if utils.IsTimeZero(beginAt) {
return nil, fmt.Errorf("GeActStoreSkuInfo必须指定活动开始时间")
}
if utils.IsTimeZero(endAt) {
endAt = beginAt
}
sql := `
SELECT
t1.type,
t2.*,
t3.actual_act_price, t3.sync_status, t3.vendor_price, t3.vendor_id
FROM act t1
JOIN act_store_sku t2 ON t2.act_id = t1.id AND t2.deleted_at = ?
JOIN act_store_sku_map t3 ON t3.bind_id = t2.id AND t3.act_id = t1.id AND (t3.sync_status & ? = 0 OR t1.type = ?)
JOIN act_map t4 ON t4.act_id = t1.id AND t4.vendor_id = t3.vendor_id AND t4.deleted_at = ? AND (t4.sync_status & ? = 0 OR t1.type = ?)
WHERE t1.deleted_at = ? AND t1.status = ? AND NOT (t1.begin_at > ? OR t1.end_at < ?) AND t1.create_type = ?`
sqlParams := []interface{}{
utils.DefaultTimeValue,
model.SyncFlagNewMask,
model.ActSkuFake,
utils.DefaultTimeValue, model.SyncFlagNewMask, model.ActSkuFake,
utils.DefaultTimeValue, model.ActStatusCreated, endAt, beginAt, model.ActCreateTypeAPI,
}
if len(vendorIDs) > 0 {
sql += " AND (t1.vendor_mask & ?) <> 0 AND t3.vendor_id IN (" + GenQuestionMarks(len(vendorIDs)) + ")"
sqlParams = append(sqlParams, model.GetVendorMask(vendorIDs...), vendorIDs)
}
if actID > 0 {
sql += " AND t1.id = ?"
sqlParams = append(sqlParams, actID)
}
if len(actTypes) > 0 {
sql += " AND t1.type IN (" + GenQuestionMarks(len(actTypes)) + ")"
sqlParams = append(sqlParams, actTypes)
}
if len(storeIDs) > 0 {
sql += " AND t2.store_id IN (" + GenQuestionMarks(len(storeIDs)) + ")"
sqlParams = append(sqlParams, storeIDs)
}
if len(skuIDs) > 0 {
sql += " AND t2.sku_id IN (" + GenQuestionMarks(len(skuIDs)) + ")"
sqlParams = append(sqlParams, skuIDs)
}
if globals.IsStoreSkuAct {
sql += " AND t1.is_special = 0"
}
// globals.SugarLogger.Debug(sql)
// globals.SugarLogger.Debug(utils.Format4Output(sqlParams, false))
err = GetRows(db, &actStoreSkuList, sql, sqlParams...)
return actStoreSkuList, err
}
func UpdateActStatusByTime(db *DaoDB, refTime time.Time) (num int64, err error) {
sql := `
UPDATE act t1
SET t1.status = ?
WHERE t1.deleted_at = ? AND t1.status < ? AND t1.end_at < ?;`
sqlParams := []interface{}{
model.ActStatusEnded,
utils.DefaultTimeValue,
model.ActStatusCanceled,
utils.Time2Date(refTime),
}
num, err = ExecuteSQL(db, sql, sqlParams...)
return num, err
}
// func ActStoreSkuMap2StoreSkuAct(actStoreSkuMap *model.ActStoreSkuMap, isCanceled bool) (storeSkuAct *model.StoreSkuAct) {
// storeSkuAct = &model.StoreSkuAct{
// StoreID: actStoreSkuMap.StoreID,
// SkuID: actStoreSkuMap.SkuID,
// VendorID: actStoreSkuMap.VendorID,
// }
// storeSkuAct.CreatedAt = actStoreSkuMap.CreatedAt
// storeSkuAct.UpdatedAt = actStoreSkuMap.UpdatedAt
// storeSkuAct.LastOperator = actStoreSkuMap.LastOperator
// if actStoreSkuMap.ActualActPrice > 0 {
// if isCanceled || !utils.IsTimeZero(actStoreSkuMap.DeletedAt) {
// storeSkuAct.ActID = 0
// } else {
// storeSkuAct.ActID = actStoreSkuMap.ActID
// storeSkuAct.VendorActID = actStoreSkuMap.VendorActID
// storeSkuAct.SyncStatus = actStoreSkuMap.SyncStatus
// storeSkuAct.VendorPrice = actStoreSkuMap.VendorPrice
// storeSkuAct.ActualActPrice = actStoreSkuMap.ActualActPrice
// }
// }
// if actStoreSkuMap.EarningPrice > 0 {
// if isCanceled || !utils.IsTimeZero(actStoreSkuMap.DeletedAt) {
// storeSkuAct.EarningActID = 0
// } else {
// storeSkuAct.EarningActID = actStoreSkuMap.ActID
// storeSkuAct.EarningPrice = actStoreSkuMap.EarningPrice
// }
// }
// return storeSkuAct
// }
func BatchUpdateActEntity(db *DaoDB, isCanceled bool, items []*KVUpdateItem) (num int64, err error) {
return BatchUpdateEntityByKV(db, items)
// if globals.IsStoreSkuAct {
// Begin(db)
// defer func() {
// if r := recover(); r != nil || err != nil {
// Rollback(db)
// if r != nil {
// panic(r)
// }
// }
// }()
// for _, v := range items {
// if actStoreSku, ok := v.Item.(*model.ActStoreSkuMap); ok {
// for k1, v1 := range v.KVs {
// refutil.SetObjFieldByName(actStoreSku, k1, v1)
// }
// if err = CreateOrUpdateActStoreSku(db, ActStoreSkuMap2StoreSkuAct(actStoreSku, isCanceled)); err != nil {
// return 0, err
// }
// }
// }
// }
// if _, err = BatchUpdateEntityByKV(db, items); err != nil {
// return 0, err
// }
// if globals.IsStoreSkuAct {
// Commit(db)
// }
// return num, err
}
func CreateOrUpdateActStoreSku(db *DaoDB, storeSkuAct *model.StoreSkuAct) (err error) {
storeSkuActCopy := *storeSkuAct
if err2 := GetEntity(db, &storeSkuActCopy, model.FieldStoreID, model.FieldSkuID, model.FieldVendorID); err2 == nil {
storeSkuAct.ID = storeSkuActCopy.ID
_, err = UpdateEntity(db, storeSkuAct)
} else if IsNoRowsError(err2) {
err = CreateEntity(db, storeSkuAct)
} else {
err = err2
}
return err
}
func GetStoresSkusAct(db *DaoDB, hintActID int, mustDirty bool, storeIDs, skuIDs, vendorIDs []int, mustHaveVendorActID bool, minActPercentage, maxActPercentage int) (storeSkuActList []*model.StoreSkuAct, err error) {
sql := `
SELECT *
FROM store_sku_act t1
WHERE 1 = 1
`
sqlParams := []interface{}{}
if hintActID > 0 {
sql += " AND t1.hint_act_id = ?"
sqlParams = append(sqlParams, hintActID)
}
if mustDirty {
sql += " AND (t1.sync_status <> 0 OR (t1.act_percentage = 0 AND t1.vendor_act_id <> '') OR (t1.act_percentage <> 0 AND t1.vendor_act_id = ''))"
}
if len(storeIDs) > 0 {
sql += " AND t1.store_id IN (" + GenQuestionMarks(len(storeIDs)) + ")"
sqlParams = append(sqlParams, storeIDs)
}
if len(skuIDs) > 0 {
sql += " AND t1.sku_id IN (" + GenQuestionMarks(len(skuIDs)) + ")"
sqlParams = append(sqlParams, skuIDs)
}
if len(vendorIDs) > 0 {
sql += " AND t1.vendor_id IN (" + GenQuestionMarks(len(vendorIDs)) + ")"
sqlParams = append(sqlParams, vendorIDs)
}
if mustHaveVendorActID {
sql += " AND t1.vendor_act_id <> ''"
}
if minActPercentage > 0 {
sql += " AND t1.act_percentage >= ?"
sqlParams = append(sqlParams, minActPercentage)
}
if maxActPercentage > 0 {
sql += " AND t1.act_percentage <= ?"
sqlParams = append(sqlParams, maxActPercentage)
}
err = GetRows(db, &storeSkuActList, sql, sqlParams...)
return storeSkuActList, err
}

View File

@@ -0,0 +1,54 @@
package dao
import (
"testing"
"time"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/model"
)
func TestGetEffectiveActStoreSkuInfo(t *testing.T) {
type testData struct {
ResultCount int
ActID int
VendorIDs []int
StoreIDs []int
SkuIDs []int
FromTime time.Time
ToTime time.Time
}
for _, v := range []*testData{
&testData{
StoreIDs: []int{100190},
SkuIDs: []int{23847},
ResultCount: 1,
FromTime: utils.Str2Time("2019-08-06 12:34:56"),
ToTime: utils.Str2Time("2019-08-06 12:34:56"),
},
} {
result, err := GetEffectiveActStoreSkuInfo(GetDB(), v.ActID, v.VendorIDs, model.ActTypeAll, v.StoreIDs, v.SkuIDs, v.FromTime, v.ToTime)
if err != nil {
t.Fatal(err)
}
if len(result) != v.ResultCount {
t.Log(utils.Format4Output(result, false))
t.Errorf("cond:%s, len(result):%d, v.ResultCount:%d", utils.Format4Output(v, false), len(result), v.ResultCount)
}
}
}
func TestUpdateActStatusByTime(t *testing.T) {
_, err := UpdateActStatusByTime(GetDB(), time.Now().Add(-48*time.Hour))
if err != nil {
t.Fatal(err)
}
}
func TestGetActStoreSkuVendorList(t *testing.T) {
_, _, err := GetActStoreSkuVendorList(GetDB(), 18440, nil, nil, nil, "", 0, 0)
if err != nil {
t.Fatal(err)
}
}

View File

@@ -0,0 +1,182 @@
package dao
import (
"git.rosy.net.cn/jx-callback/globals"
"time"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/model"
)
func GetUserBill(db *DaoDB, userID, billID string) (userBill *model.UserBill, err error) {
sql := `
SELECT * FROM user_bill WHERE deleted_at = ?
`
sqlParams := []interface{}{utils.DefaultTimeValue}
if userID != "" {
sql += ` AND user_id = ?`
sqlParams = append(sqlParams, userID)
}
if billID != "" {
sql += ` AND bill_id = ?`
sqlParams = append(sqlParams, billID)
}
err = GetRow(db, &userBill, sql, sqlParams)
return userBill, err
}
// 添加用户支出记录
func AddUserExpend() {
}
func GetBillExpend(db *DaoDB, userID string, billType int, fromTime, toTime time.Time) (billExpends []*model.BillExpend, err error) {
sql := `
SELECT b.*
FROM user_bill a
LEFT JOIN bill_expend b ON b.bill_id = a.bill_id
WHERE a.deleted_at = ?
`
sqlParams := []interface{}{utils.DefaultTimeValue}
if userID != "" {
sql += ` AND a.user_id = ?`
sqlParams = append(sqlParams, userID)
}
if billType != 0 {
sql += ` AND b.type = ?`
sqlParams = append(sqlParams, billType)
}
if fromTime != utils.ZeroTimeValue {
sql += ` AND b.created_at >= ?`
sqlParams = append(sqlParams, fromTime)
}
if toTime != utils.ZeroTimeValue {
sql += ` AND b.created_at <= ?`
sqlParams = append(sqlParams, toTime)
}
err = GetRows(db, &billExpends, sql, sqlParams)
return billExpends, err
}
func GetBillIncome(db *DaoDB, jobID int, billID int64) (billIncomes []*model.BillIncome, err error) {
sql := `
SELECT b.*
FROM user_bill a
LEFT JOIN bill_income b ON b.bill_id = a.bill_id
WHERE a.deleted_at = ?
`
sqlParams := []interface{}{utils.DefaultTimeValue}
if jobID != 0 {
sql += ` AND b.job_id = ?`
sqlParams = append(sqlParams, jobID)
}
if billID != 0 {
sql += ` AND b.bill_id = ?`
sqlParams = append(sqlParams, billID)
}
err = GetRows(db, &billIncomes, sql, sqlParams)
return billIncomes, err
}
type UserBillDetail struct {
CreatedAt time.Time `json:"created_at"`
LastOperator string `json:"lastOperator"`
BillType int `json:"billType"`
Price int `json:"price"`
Type string `json:"type"`
}
func GetUserBillDetail(db *DaoDB, userID string, fromTime, toTime time.Time, pageSize, offset int) (pagedInfo *model.PagedInfo, err error) {
var userBillDetails []*UserBillDetail
sql := `
SELECT SQL_CALC_FOUND_ROWS k.* FROM (
SELECT a.created_at, a.last_operator, a.type bill_type, a.income_price price, 'income' type
FROM bill_income a
JOIN user_bill b ON a.bill_id = b.bill_id AND b.user_id = ?
`
sqlParams := []interface{}{userID}
if fromTime != utils.ZeroTimeValue {
sql += ` AND a.created_at >= ?`
sqlParams = append(sqlParams, fromTime)
}
if toTime != utils.ZeroTimeValue {
sql += ` AND a.created_at <= ?`
sqlParams = append(sqlParams, toTime)
}
sql += `
UNION ALL
SELECT a.created_at, a.last_operator, a.type bill_type, a.expend_price price, 'expend' type
FROM bill_expend a
JOIN user_bill b ON a.bill_id = b.bill_id AND b.user_id = ?
`
sqlParams = append(sqlParams, userID)
if fromTime != utils.ZeroTimeValue {
sql += ` AND a.created_at >= ?`
sqlParams = append(sqlParams, fromTime)
}
if toTime != utils.ZeroTimeValue {
sql += ` AND a.created_at <= ?`
sqlParams = append(sqlParams, toTime)
}
sql += `
)k
ORDER BY k.created_at LIMIT ? OFFSET ?
`
pageSize = jxutils.FormalizePageSize(pageSize)
sqlParams = append(sqlParams, pageSize, offset)
txDB, _ := Begin(db)
defer Commit(db, txDB)
if err = GetRowsTx(txDB, &userBillDetails, sql, sqlParams...); err == nil {
pagedInfo = &model.PagedInfo{
TotalCount: GetLastTotalRowCountTx(txDB),
Data: userBillDetails,
}
}
return pagedInfo, err
}
// UpdateUserBill 修改用户余额
func UpdateUserBill(userId string, money int) error {
_, err := ExecuteSQL(GetDB(), `UPDATE user_bill SET account_balance = ? WHERE user_id = ? `, []interface{}{money, userId}...)
return err
}
type MixPayDetail struct {
ID int `json:"id"`
CreatedAt time.Time `json:"created_at"`
UpdateAt time.Time `json:"update_at"`
LastOperator string `json:"lastOperator"`
OrderID string `json:"order_id"`
BalancePrice int `json:"balance_price"`
TotalPrice int `json:"total_price"`
WxPrice int `json:"wx_price"`
Status int `json:"status"`
}
//获取混合支付 余额部分信息
func GetMixPayDetail(orderID string) (details *model.MixPay, err error) {
//var info []*MixPayDetail
info := make([]*model.MixPay, 0)
var sqlParams []interface{}
sql := ""
if orderID != "" {
sql += "SELECT * FROM mix_pay WHERE order_id = ?"
sqlParams = append(sqlParams, orderID)
}
err = GetRows(GetDB(), &info, sql, sqlParams...)
if err != nil {
globals.SugarLogger.Debug("er===========", err)
return nil, err
}
return info[0], err
//if err == nil {
// details = &MixPayDetail{
// OrderID: info[0].OrderID,
// BalancePrice: info[0].BalancePrice,
// TotalPrice: info[0].TotalPrice,
// WxPrice: info[0].WxPrice,
// Status: info[0].Status,
// }
//}
}

View File

@@ -0,0 +1,586 @@
package dao
import (
"encoding/json"
"fmt"
"math"
"strings"
"time"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/model"
)
const (
sortTypeDistance = 1 //距离
sortTypeTime = 2 //发布时间
sortTypeAvgPrice = 4 //奖励高低
)
func GetJobCategories(db *DaoDB, name string) (jobCategories []*model.JobCategory, err error) {
sql := `
SELECT * FROM job_category WHERE deleted_at = ?
`
sqlParams := []interface{}{utils.DefaultTimeValue}
if name != "" {
sql += ` AND name LIKE ?`
sqlParams = append(sqlParams, "%"+name+"%")
}
err = GetRows(db, &jobCategories, sql, sqlParams)
return jobCategories, err
}
type GetJobsResult struct {
model.JobExt
CategoryName string `json:"categoryName"` //分类名
IndexImg string `json:"indexImg"` //任务封面
Distance float64 `json:"distance"` //距用户距离
}
func GetJobSteps(db *DaoDB, jobID int) (jobSteps []*model.JobStep, err error) {
sql := `
SELECT *
FROM job_step
WHERE job_id = ?
AND deleted_at = ?
`
sqlParams := []interface{}{jobID, utils.DefaultTimeValue}
err = GetRows(db, &jobSteps, sql, sqlParams)
return jobSteps, err
}
func GetJobImgs(db *DaoDB, jobID int) (jobImgs []*model.JobImg, err error) {
sql := `
SELECT *
FROM job_img
WHERE job_id = ?
`
sqlParams := []interface{}{jobID}
err = GetRows(db, &jobImgs, sql, sqlParams)
return jobImgs, err
}
func GetJobs(db *DaoDB, userIDs []string, categoryIDs, statuss, vendorIDs, types, cityCodes []int, includeStep bool, fromTime, toTime time.Time, lng, lat float64, cityCode, span int, keyword string, sortType, pageSize, offset int) (pagedInfo *model.PagedInfo, err error) {
var (
jobs []*GetJobsResult
sqlParams = []interface{}{lng, lat, utils.DefaultTimeValue, utils.DefaultTimeValue}
)
sql := `
SELECT SQL_CALC_FOUND_ROWS a.*, b.name, getDistance(?, ?, CAST(a.lng AS DECIMAL(15,6))/1000000, CAST(a.lat AS DECIMAL(15,6))/1000000) distance
FROM job a
JOIN job_category b ON b.id = a.job_category_id AND b.deleted_at = ?
WHERE a.deleted_at = ?
`
if cityCode > 0 {
sql += " AND (a.job_city_code = ? OR a.job_city_code = ?)"
sqlParams = append(sqlParams, cityCode, model.JobCountrywideCode)
}
if len(userIDs) > 0 {
sql += ` AND a.user_id IN (` + GenQuestionMarks(len(userIDs)) + `)`
sqlParams = append(sqlParams, userIDs)
}
if len(categoryIDs) > 0 {
sql += ` AND a.job_category_id IN (` + GenQuestionMarks(len(categoryIDs)) + `)`
sqlParams = append(sqlParams, categoryIDs)
}
if len(statuss) > 0 {
sql += ` AND a.status IN (` + GenQuestionMarks(len(statuss)) + `)`
sqlParams = append(sqlParams, statuss)
}
if len(vendorIDs) > 0 {
sql += ` AND a.vendor_id IN (` + GenQuestionMarks(len(vendorIDs)) + `)`
sqlParams = append(sqlParams, vendorIDs)
}
if len(types) > 0 {
sql += ` AND a.type IN (` + GenQuestionMarks(len(types)) + `)`
sqlParams = append(sqlParams, types)
}
if len(cityCodes) > 0 {
sql += ` AND a.job_city_code IN (` + GenQuestionMarks(len(cityCodes)) + `)`
sqlParams = append(sqlParams, cityCodes)
}
if fromTime != utils.ZeroTimeValue {
sql += ` AND a.created_at >= ?`
sqlParams = append(sqlParams, fromTime)
}
if toTime != utils.ZeroTimeValue {
sql += ` AND a.created_at <= ?`
sqlParams = append(sqlParams, toTime)
}
if span != 0 {
if span == model.JobSpanTop {
sql += ` AND a.job_span_top = 1`
} else {
sql += ` AND a.job_span_recmd = 1`
}
}
if keyword != "" {
sql += ` AND (a.title LIKE ? OR a.content LIKE ? OR a.address LIKE ? OR b.name LIKE ?)`
sqlParams = append(sqlParams, "%"+keyword+"%", "%"+keyword+"%", "%"+keyword+"%", "%"+keyword+"%")
}
if sortType != 0 {
if sortType == sortTypeDistance {
sql += ` ORDER BY job_span_top DESC, top_seq, distance`
} else if sortType == -sortTypeDistance {
sql += ` ORDER BY job_span_top DESC, top_seq, distance DESC`
} else if sortType == sortTypeAvgPrice {
sql += ` ORDER BY job_span_top DESC, top_seq, a.avg_price`
} else if sortType == -sortTypeAvgPrice {
sql += ` ORDER BY job_span_top DESC, top_seq, a.avg_price DESC`
} else if sortType == sortTypeTime {
sql += ` ORDER BY job_span_top DESC, top_seq, a.created_at`
} else if sortType == -sortTypeTime {
sql += ` ORDER BY status DESC, job_span_top DESC, top_seq, a.created_at DESC`
}
}
sql += " LIMIT ? OFFSET ?"
pageSize = jxutils.FormalizePageSize(pageSize)
sqlParams = append(sqlParams, pageSize, offset)
txDB, _ := Begin(db)
defer Commit(db, txDB)
if err = GetRowsTx(txDB, &jobs, sql, sqlParams...); err == nil {
pagedInfo = &model.PagedInfo{
TotalCount: GetLastTotalRowCountTx(txDB),
// Data: jobs,
}
for _, v := range jobs {
if includeStep {
if jobSteps, err := GetJobSteps(db, v.ID); err == nil && len(jobSteps) > 0 {
v.JobSteps = jobSteps
}
}
if jobImgs, err := GetJobImgs(db, v.ID); err == nil && len(jobImgs) > 0 {
v.JobImgs = jobImgs
v.IndexImg = jobImgs[0].Img
}
}
pagedInfo.Data = jobs
}
return pagedInfo, err
}
func GetJob(db *DaoDB, userIDs []string, categoryIDs, statuss, types []int, fromTime, toTime time.Time, includeStep bool) (job *model.Job, err error) {
jobs, err := GetJobsNoPage(db, userIDs, nil, categoryIDs, statuss, types, fromTime, toTime, 0, includeStep)
if err != nil {
return job, err
}
if len(jobs) == 0 {
return job, fmt.Errorf("未查询到对应的京东快递任务!")
}
if data, err := json.Marshal(jobs[0]); err == nil {
json.Unmarshal(data, &job)
}
return job, err
}
func GetJobWithTitle(db *DaoDB, title string) (job *model.Job, err error) {
sql := `
SELECT * FROM job WHERE title = ? AND deleted_at = ? AND status = ?
`
sqlParams := []interface{}{title, utils.DefaultTimeValue, model.JobStatusDoing}
err = GetRow(db, &job, sql, sqlParams)
return job, err
}
func GetJobsNoPage(db *DaoDB, userIDs []string, vendorIDs, categoryIDs, statuss, types []int, fromTime, toTime time.Time, span int, includeStep bool) (jobs []*GetJobsResult, err error) {
sql := `
SELECT a.*, b.name
FROM job a
JOIN job_category b ON b.id = a.job_category_id AND b.deleted_at = ?
WHERE 1 = 1
`
sqlParams := []interface{}{utils.DefaultTimeValue}
if len(userIDs) > 0 {
sql += ` AND a.user_id IN (` + GenQuestionMarks(len(userIDs)) + `)`
sqlParams = append(sqlParams, userIDs)
}
if len(vendorIDs) > 0 {
sql += ` AND a.vendor_id IN (` + GenQuestionMarks(len(vendorIDs)) + `)`
sqlParams = append(sqlParams, vendorIDs)
}
if len(categoryIDs) > 0 {
sql += ` AND a.job_category_id IN (` + GenQuestionMarks(len(categoryIDs)) + `)`
sqlParams = append(sqlParams, categoryIDs)
}
if len(statuss) > 0 {
sql += ` AND a.status IN (` + GenQuestionMarks(len(statuss)) + `)`
sqlParams = append(sqlParams, statuss)
}
if len(types) > 0 {
sql += ` AND a.type IN (` + GenQuestionMarks(len(types)) + `)`
sqlParams = append(sqlParams, types)
}
if fromTime != utils.ZeroTimeValue {
sql += ` AND a.created_at >= ?`
sqlParams = append(sqlParams, fromTime)
}
if toTime != utils.ZeroTimeValue {
sql += ` AND a.created_at <= ?`
sqlParams = append(sqlParams, toTime)
}
if span != 0 {
if span == model.JobSpanTop {
sql += ` AND a.job_span_top = 1`
} else {
sql += ` AND a.job_span_recmd = 1`
}
}
err = GetRows(db, &jobs, sql, sqlParams...)
for _, v := range jobs {
if includeStep {
if jobSteps, err := GetJobSteps(db, v.ID); err == nil && len(jobSteps) > 0 {
v.JobSteps = jobSteps
}
}
if jobImgs, err := GetJobImgs(db, v.ID); err == nil && len(jobImgs) > 0 {
v.JobImgs = jobImgs
}
}
return jobs, err
}
func GetJobDetail(db *DaoDB, jobID int) (job *GetJobsResult, err error) {
sql := `
SELECT a.*, b.name
FROM job a
JOIN job_category b ON b.id = a.job_category_id AND b.deleted_at = ?
WHERE 1 = 1
`
sqlParams := []interface{}{utils.DefaultTimeValue}
if jobID != 0 {
sql += ` AND a.id = ?`
sqlParams = append(sqlParams, jobID)
}
err = GetRow(db, &job, sql, sqlParams...)
if job != nil {
if jobSteps, err := GetJobSteps(db, job.ID); err == nil && len(jobSteps) > 0 {
job.JobSteps = jobSteps
}
if jobImgs, err := GetJobImgs(db, job.ID); err == nil && len(jobImgs) > 0 {
job.JobImgs = jobImgs
}
} else {
return job, fmt.Errorf("未查到到该任务!")
}
return job, err
}
func GetJobOrdersNoPage(db *DaoDB, jobID int, jobOrderID int64, userID string, statusCompareStr string, fromTime, toTime time.Time, statuss []int) (jobOrders []*model.JobOrder, err error) {
sql := `
SELECT a.*
FROM job_order a
WHERE 1 = 1
`
sqlParams := []interface{}{}
if jobID != 0 {
sql += ` AND a.job_id = ?`
sqlParams = append(sqlParams, jobID)
}
if jobOrderID != 0 {
sql += ` AND a.job_order_id = ?`
sqlParams = append(sqlParams, jobOrderID)
}
if userID != "" {
sql += ` AND a.user_id = ?`
sqlParams = append(sqlParams, userID)
}
if statusCompareStr != "" {
sql += ` AND a.status ` + statusCompareStr
}
if fromTime != utils.ZeroTimeValue {
sql += ` AND a.created_at >= ?`
sqlParams = append(sqlParams, fromTime)
}
if toTime != utils.ZeroTimeValue {
sql += ` AND a.created_at <= ?`
sqlParams = append(sqlParams, toTime)
}
if len(statuss) > 0 {
sql += ` AND a.status IN (` + GenQuestionMarks(len(statuss)) + `)`
sqlParams = append(sqlParams, statuss)
}
err = GetRows(db, &jobOrders, sql, sqlParams)
return jobOrders, err
}
type GetJobOrdersResult struct {
model.JobOrder
JobLimitAt int `json:"jobLimitAt"` //任务限时完成小时数
AuditLimitAt int `json:"auditLimitAt"` //限时审核小时数
JobOrderFinishAt time.Time `json:"jobOrderFinishAt"`
JobOrderAuditFinishAt time.Time `json:"jobOrderAuditFinishAt"`
JobIndexImg string `json:"jobIndexImg"`
VendorID int `orm:"column(vendor_id)" json:"vendorID"` //推广平台
AvgPrice int `json:"avgPrice"` //单个任务金额
Title string `orm:"size(255)" json:"title"` //任务标题
JobContent string `orm:"size(500)" json:"jobContent"`
JobCategoryID int `orm:"column(job_category_id)" json:"jobCategoryID"`
StoreURL string `orm:"column(store_url)" json:"storeURL"`
}
func GetJobOrders(db *DaoDB, jobID int, jobOrderID int64, userID, jobUserID string, statusCompareStr string, fromTime, toTime time.Time, statuss []int, pageSize, offset int) (pagedInfo *model.PagedInfo, err error) {
var jobOrders []*GetJobOrdersResult
sql := `
SELECT SQL_CALC_FOUND_ROWS a.*, b.job_limit_at, b.vendor_id, b.avg_price, b.title, b.content job_content, b.audit_limit_at, b.job_category_id, b.store_url
FROM job_order a
JOIN job b ON a.job_id = b.id
WHERE 1 = 1
`
sqlParams := []interface{}{}
if jobID != 0 {
sql += ` AND a.job_id = ?`
sqlParams = append(sqlParams, jobID)
}
if jobOrderID != 0 {
sql += ` AND a.job_order_id = ?`
sqlParams = append(sqlParams, jobOrderID)
}
if userID != "" {
sql += ` AND a.user_id = ?`
sqlParams = append(sqlParams, userID)
}
if jobUserID != "" {
sql += ` AND b.user_id = ?`
sqlParams = append(sqlParams, jobUserID)
}
if statusCompareStr != "" {
sql += ` AND a.status ` + statusCompareStr
}
if fromTime != utils.ZeroTimeValue {
sql += ` AND a.created_at >= ?`
sqlParams = append(sqlParams, fromTime)
}
if toTime != utils.ZeroTimeValue {
sql += ` AND a.created_at <= ?`
sqlParams = append(sqlParams, toTime)
}
if len(statuss) > 0 {
sql += ` AND a.status IN (` + GenQuestionMarks(len(statuss)) + `)`
sqlParams = append(sqlParams, statuss)
}
sql += " LIMIT ? OFFSET ?"
pageSize = jxutils.FormalizePageSize(pageSize)
sqlParams = append(sqlParams, pageSize, offset)
txDB, _ := Begin(db)
defer Commit(db, txDB)
if err = GetRowsTx(txDB, &jobOrders, sql, sqlParams...); err == nil {
pagedInfo = &model.PagedInfo{
TotalCount: GetLastTotalRowCountTx(txDB),
// Data: jobOrders,
}
for _, v := range jobOrders {
if jobImgs, err := GetJobImgs(db, v.JobID); err == nil && len(jobImgs) > 0 {
v.JobIndexImg = jobImgs[0].Img
}
v.JobOrderFinishAt = v.JobOrder.CreatedAt.Add(time.Duration(v.JobLimitAt) * time.Hour)
v.JobOrderAuditFinishAt = v.JobOrder.SubmitAuditAt.Add(time.Duration(v.AuditLimitAt) * time.Hour)
}
pagedInfo.Data = jobOrders
}
return pagedInfo, err
}
func GetMtMember(db *DaoDB) (mtMember *model.MtMember, err error) {
sql := `
SELECT *
FROM mt_member
WHERE deleted_at = ?
LIMIT 1
`
sqlParams := []interface{}{utils.DefaultTimeValue}
err = GetRow(db, &mtMember, sql, sqlParams)
return mtMember, err
}
func GetJobTimers(db *DaoDB, status int) (jobTimers []*model.JobTimer, err error) {
sql := `
SELECT *
FROM job_timer
WHERE 1 = 1
`
sqlParams := []interface{}{}
if status != -1 {
sql += ` AND status = ?`
sqlParams = append(sqlParams, status)
}
err = GetRows(db, &jobTimers, sql, sqlParams)
return jobTimers, err
}
func GetMtMembers(db *DaoDB) (num int, err error) {
var mtMembers []*model.MtMember
sql := `
SELECT * FROM mt_member WHERE deleted_at = ?
`
sqlParams := []interface{}{utils.DefaultTimeValue}
err = GetRows(db, &mtMembers, sql, sqlParams)
num = len(mtMembers)
return num, err
}
func GetUserSearch(db *DaoDB, userID, keyword string) (userSearchs []*model.UserSearch, err error) {
sql := `
SELECT *
FROM user_search
WHERE 1 = 1
`
sqlParams := []interface{}{}
if userID != "" {
sql += " AND user_id = ?"
sqlParams = append(sqlParams, userID)
}
if keyword != "" {
sql += " AND keyword = ?"
sqlParams = append(sqlParams, keyword)
}
err = GetRows(db, &userSearchs, sql, sqlParams)
return userSearchs, err
}
func GetStationList(db *DaoDB) (stations []*model.StationInfo, err error) {
sql := `
SELECT *
FROM station_info
`
sqlParams := []interface{}{}
err = GetRows(db, &stations, sql, sqlParams)
return stations, err
}
func GetStationInfoList(db *DaoDB, stationName string, cityCode int, lat, lng float64, oilCode string, sortType, offset, pageSize int) (pagedInfo *model.PagedInfo, err error) {
var (
stations []*model.StationInfo
distanceFlag bool
sqlParams = []interface{}{}
)
if lng != 0 && lat != 0 {
distanceFlag = true
}
sql := `
SELECT SQL_CALC_FOUND_ROWS *
`
if distanceFlag {
sql += `, getDistance(?, ?, longitude, latitude) distance`
sqlParams = append(sqlParams, lng, lat)
}
sql += `
FROM station_info
WHERE 1 = 1
`
if stationName != "" {
sql += " AND station_name LIKE ?"
sqlParams = append(sqlParams, "%"+stationName+"%")
}
if cityCode != 0 {
sql += " AND city_id = ?"
sqlParams = append(sqlParams, cityCode)
}
if oilCode != "" {
sql += " AND POSITION(? IN prices) > 0"
sqlParams = append(sqlParams, oilCode)
}
if sortType != 0 {
if sortType == 1 {
sql += " ORDER BY distance"
} else if sortType == -1 {
sql += " ORDER BY distance DESC"
} else if sortType == 2 {
sql += " ORDER BY star_num"
} else if sortType == -2 {
sql += " ORDER BY star_num DESC"
}
}
sql += " LIMIT ? OFFSET ?"
pageSize = jxutils.FormalizePageSize(pageSize)
sqlParams = append(sqlParams, pageSize, offset)
txDB, _ := Begin(db)
defer Commit(db, txDB)
if err = GetRowsTx(txDB, &stations, sql, sqlParams...); err == nil {
pagedInfo = &model.PagedInfo{
TotalCount: GetLastTotalRowCountTx(txDB),
// Data: stations,
}
for _, v := range stations {
var oilInfo []*model.OilInfo
json.Unmarshal([]byte(strings.ReplaceAll(v.Prices, "\\", "")), &oilInfo)
v.OilInfo = oilInfo
}
if math.Abs(utils.Int2Float64(sortType)) == 3 {
if oilCode != "" {
for i := 0; i < len(stations); i++ {
for j := 0; j < len(stations)-i-1; j++ {
var (
index int
index2 int
)
for k, v := range stations[j].OilInfo {
if v.OilCode == oilCode {
index = k
}
}
for k, v := range stations[j+1].OilInfo {
if v.OilCode == oilCode {
index2 = k
}
}
if sortType == 3 {
if utils.Str2Float64(stations[j].OilInfo[index].DiscountPrice) > utils.Str2Float64(stations[j+1].OilInfo[index2].DiscountPrice) {
temp := stations[j]
stations[j] = stations[j+1]
stations[j+1] = temp
}
} else if sortType == -3 {
if utils.Str2Float64(stations[j].OilInfo[index].DiscountPrice) < utils.Str2Float64(stations[j+1].OilInfo[index2].DiscountPrice) {
temp := stations[j]
stations[j] = stations[j+1]
stations[j+1] = temp
}
}
}
}
}
}
pagedInfo.Data = stations
}
return pagedInfo, err
}
func GetMaxJobTopSeq(db *DaoDB) (maxSeq int, err error) {
Seq := &struct {
TopSeq int
}{}
sql := `
SELECT MAX(top_seq) top_seq FROM job WHERE deleted_at = ? AND status = ? AND job_span_top = ?
`
sqlParams := []interface{}{utils.DefaultTimeValue, model.JobStatusDoing, 1}
if err = GetRow(db, &Seq, sql, sqlParams); err == nil {
return Seq.TopSeq, err
}
return maxSeq, err
}
func GetMaxJobRecmdSeq(db *DaoDB) (maxSeq int, err error) {
Seq := &struct {
RecmdSeq int
}{}
sql := `
SELECT MAX(recmd_seq) recmd_seq FROM job WHERE deleted_at = ? AND status = ? AND job_span_recmd = ?
`
sqlParams := []interface{}{utils.DefaultTimeValue, model.JobStatusDoing, 1}
if err = GetRow(db, &Seq, sql, sqlParams); err == nil {
return Seq.RecmdSeq, err
}
return maxSeq, err
}
func GetJobSpans(db *DaoDB) (jobSpans []*model.JobSpan, err error) {
sql := `
SELECT *
FROM job_span
WHERE deleted_at = ?
`
sqlParams := []interface{}{utils.DefaultTimeValue}
err = GetRows(db, &jobSpans, sql, sqlParams)
return jobSpans, err
}

View File

@@ -0,0 +1,15 @@
package dao
import (
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/model"
)
func GetVendorMatterCategory(db *DaoDB, vendorID int) (vendorMatterCat []*model.VendorMatterCategory, err error) {
sql := `
SELECT * FROM vendor_matter_category WHERE deleted_at = ? AND vendor_id = ?
`
sqlParams := []interface{}{utils.DefaultTimeValue, vendorID}
err = GetRows(db, &vendorMatterCat, sql, sqlParams)
return vendorMatterCat, err
}

View File

@@ -0,0 +1,740 @@
package dao
import (
"github.com/astaxie/beego/client/orm"
"time"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/model"
)
func GetDeliveryOrdersNoPage(db *DaoDB, userIDs []string, statuss []int, fromTime, toTime time.Time, isWeights []int) (dOrders []*model.DeliveryOrder, err error) {
sql := `
SELECT a.*
FROM delivery_order a
WHERE 1 = 1
`
sqlParams := []interface{}{}
if len(userIDs) > 0 {
sql += ` AND a.user_id IN (` + GenQuestionMarks(len(userIDs)) + `)`
sqlParams = append(sqlParams, userIDs)
}
if len(statuss) > 0 {
sql += ` AND a.status IN (` + GenQuestionMarks(len(statuss)) + `)`
sqlParams = append(sqlParams, statuss)
}
if len(isWeights) > 0 {
sql += ` AND a.is_weight IN (` + GenQuestionMarks(len(isWeights)) + `)`
sqlParams = append(sqlParams, isWeights)
}
if fromTime != utils.ZeroTimeValue {
sql += ` AND a.created_at >= ?`
sqlParams = append(sqlParams, fromTime)
}
if toTime != utils.ZeroTimeValue {
sql += ` AND a.created_at <= ?`
sqlParams = append(sqlParams, toTime)
}
err = GetRows(db, &dOrders, sql, sqlParams)
return dOrders, err
}
type GetDeliveryOrdersResult struct {
model.DeliveryOrder
DeliverySendInfo *UserDeliveryAddressEx `json:"deliverySendInfo"`
DeliveryReceiveInfo *UserDeliveryAddressEx `json:"deliveryReceiveInfo"`
}
func GetDeliveryOrders(db *DaoDB, userIDs []string, statuss []int, fromTime, toTime time.Time, pageSize, offset int) (pagedInfo *model.PagedInfo, err error) {
var dOrders []*GetDeliveryOrdersResult
sql := `
SELECT SQL_CALC_FOUND_ROWS a.*
FROM delivery_order a
WHERE 1 = 1
`
sqlParams := []interface{}{}
if len(userIDs) > 0 {
sql += ` AND a.user_id IN (` + GenQuestionMarks(len(userIDs)) + `)`
sqlParams = append(sqlParams, userIDs)
}
if len(statuss) > 0 {
sql += ` AND a.status IN (` + GenQuestionMarks(len(statuss)) + `)`
sqlParams = append(sqlParams, statuss)
}
if fromTime != utils.ZeroTimeValue {
sql += ` AND a.created_at >= ?`
sqlParams = append(sqlParams, fromTime)
}
if toTime != utils.ZeroTimeValue {
sql += ` AND a.created_at <= ?`
sqlParams = append(sqlParams, toTime)
}
sql += " ORDER BY a.created_at DESC"
sql += " LIMIT ? OFFSET ?"
pageSize = jxutils.FormalizePageSize(pageSize)
sqlParams = append(sqlParams, pageSize, offset)
txDB, _ := Begin(db)
defer Commit(db, txDB)
if err = GetRowsTx(txDB, &dOrders, sql, sqlParams...); err == nil {
pagedInfo = &model.PagedInfo{
TotalCount: GetLastTotalRowCountTx(txDB),
// Data: dOrders,
}
for _, v := range dOrders {
if addressList1, _, err := QueryUserDeliveryAddress(db, int64(v.DeliverySendID), nil, 0, 0, 0); err == nil && len(addressList1) > 0 {
v.DeliverySendInfo = addressList1[0]
} else {
sendInfo := &UserDeliveryAddressEx{}
sendInfo.ConsigneeName = v.SendName
sendInfo.ConsigneeMobile = v.SendMobile
sendInfo.Address = v.SendAddress
sendInfo.AutoAddress = v.SendAutoAddress
sendInfo.CityCode = v.SendCityCode
sendInfo.DistrictCode = v.SendDistrictCode
sendInfo.DetailAddress = v.SendDetailAddress
sendInfo.Lng = v.SendLng
sendInfo.Lat = v.SendLat
v.DeliverySendInfo = sendInfo
}
if addressList2, _, err := QueryUserDeliveryAddress(db, int64(v.DeliveryReceiveID), nil, 0, 0, 0); err == nil && len(addressList2) > 0 {
v.DeliveryReceiveInfo = addressList2[0]
} else {
receiveInfo := &UserDeliveryAddressEx{}
receiveInfo.ConsigneeName = v.ReceiveName
receiveInfo.ConsigneeMobile = v.ReceiveMobile
receiveInfo.Address = v.ReceiveAddress
receiveInfo.AutoAddress = v.ReceiveAutoAddress
receiveInfo.CityCode = v.ReceiveCityCode
receiveInfo.DistrictCode = v.ReceiveDistrictCode
receiveInfo.DetailAddress = v.ReceiveDetailAddress
receiveInfo.Lng = v.ReceiveLng
receiveInfo.Lat = v.ReceiveLat
v.DeliveryReceiveInfo = receiveInfo
}
}
pagedInfo.Data = dOrders
}
return pagedInfo, err
}
type GetOrdersResult struct {
model.Order
UserName string `json:"userName"`
Mobile string `json:"mobile"`
}
var TableOrder = "order"
func GetOrderByID(db *DaoDB, orderID string) (*model.Order, error) {
sql := `SELECT * FROM` + "`order`" + ` WHERE 1 = 1 `
sqlParams := []interface{}{}
if orderID != "" {
sql += `AND order_id = ?`
sqlParams = append(sqlParams, orderID)
}
orderInfos := &model.Order{}
if err := GetRow(db, orderInfos, sql, sqlParams); err != nil {
return nil, err
}
return orderInfos, nil
}
func GetOrders(db *DaoDB, orderID, userID string, orderType int, cityCodes []int, fromTime, toTime time.Time, keyword string, offset, pageSize int) (pagedInfo *model.PagedInfo, err error) {
var orders []*GetOrdersResult
sql := `
SELECT SQL_CALC_FOUND_ROWS a.*, b.name user_name, b.mobile
FROM ` + "`order`" + ` a
JOIN user b ON b.user_id = a.user_id AND b.deleted_at = ?
WHERE 1 = 1
`
sqlParams := []interface{}{
utils.DefaultTimeValue,
}
if orderID != "" {
sql += ` AND a.order_id = ?`
sqlParams = append(sqlParams, orderID)
}
if userID != "" {
sql += ` AND a.user_id = ?`
sqlParams = append(sqlParams, userID)
}
if orderType != 0 {
sql += ` AND a.type = ?`
sqlParams = append(sqlParams, orderType)
}
if len(cityCodes) > 0 {
sql += ` AND a.city_code IN (` + GenQuestionMarks(len(cityCodes)) + `)`
sqlParams = append(sqlParams, cityCodes)
}
if fromTime != utils.ZeroTimeValue {
sql += ` AND a.created_at >= ?`
sqlParams = append(sqlParams, fromTime)
}
if toTime != utils.ZeroTimeValue {
sql += ` AND a.created_at <= ?`
sqlParams = append(sqlParams, toTime)
}
if keyword != "" {
sql += ` AND (b.mobile LIKE ? OR b.name LIKE ?)`
sqlParams = append(sqlParams, "%"+keyword+"%", "%"+keyword+"%")
}
sql += " LIMIT ? OFFSET ?"
pageSize = jxutils.FormalizePageSize(pageSize)
sqlParams = append(sqlParams, pageSize, offset)
txDB, _ := Begin(db)
defer Commit(db, txDB)
if err = GetRowsTx(txDB, &orders, sql, sqlParams); err == nil {
pagedInfo = &model.PagedInfo{
TotalCount: GetLastTotalRowCountTx(txDB),
Data: orders,
}
}
return pagedInfo, err
}
type GetPayStatisticsResult struct {
TotalPay int `json:"totalPay"` //支付总额
CanCash int `json:"canCash"` //可提现(未提现+申请提现)
AccountBalance int `json:"accountBalance"` //未提现(含保证金)
SubmitCash int `json:"submitCash"` //申请提现
Cashed int `json:"cashed"` //已经体现
CashIncome int `json:"cashIncome"` //提现收益
TotalIncome int `json:"totalIncome"` //收益总额
MemberIncome int `json:"memberIncome"` //会员收益
}
func getFromSql(orderType, status int, alies string, userID string, pop int, cityCodes []int, mobile string, fromTime, toTime time.Time, orderTypes []int) (sql string, sqlParams []interface{}) {
sql += `
(SELECT SUM(IFNULL(b.pay_price,0)) total_pay
FROM user a
JOIN ` + "`order` b " + `ON b.user_id = a.user_id AND b.type = ? AND b.status = ?
`
sqlParams = append(sqlParams, orderType, status)
if len(orderTypes) > 0 {
sql += ` AND b.order_type IN (` + GenQuestionMarks(len(orderTypes)) + `)`
sqlParams = append(sqlParams, orderTypes)
}
if fromTime != utils.ZeroTimeValue {
sql += ` AND b.created_at > ?`
sqlParams = append(sqlParams, fromTime)
}
if toTime != utils.ZeroTimeValue {
sql += ` AND b.created_at < ?`
sqlParams = append(sqlParams, toTime)
}
if mobile != "" {
if pop == 1 {
sql += " JOIN user e ON e.moblie = ? AND a.pop_user = e.user_id"
sqlParams = append(sqlParams, mobile)
}
}
sql += `
WHERE a.status = ? AND a.deleted_at = ?
`
sqlParams = append(sqlParams, model.UserStatusNormal, utils.DefaultTimeValue)
if userID != "" {
if pop == 1 {
sql += " AND a.pop_user = ?"
sqlParams = append(sqlParams, userID)
} else {
sql += " AND a.user_id = ?"
sqlParams = append(sqlParams, userID)
}
}
if mobile != "" {
if pop == 0 {
sql += " AND a.mobile = ?"
sqlParams = append(sqlParams, mobile)
}
}
if len(cityCodes) > 0 {
sql += ` AND a.city_code IN (` + GenQuestionMarks(len(cityCodes)) + `)`
sqlParams = append(sqlParams, cityCodes)
}
sql += `) ` + alies
return sql, sqlParams
}
func GetPayStatistics(db *DaoDB, userID string, pop int, cityCodes []int, mobile string, fromTime, toTime time.Time, orderTypes []int) (getPayStatisticsResult *GetPayStatisticsResult, err error) {
sqlParams := []interface{}{}
sql := `SELECT t1.total_pay, t2.total_pay submit_cash, t3.total_pay cashed, t4.account_balance, t4.account_balance + t2.total_pay can_cash
FROM `
rSQL1, rSQLParams1 := getFromSql(model.OrderTypePay, model.OrderStatusFinished, "t1", userID, pop, cityCodes, mobile, fromTime, toTime, orderTypes)
sql += rSQL1 + ","
sqlParams = append(sqlParams, rSQLParams1...)
rSQL2, rSQLParams2 := getFromSql(model.OrderTypeCash, model.OrderStatusWait4Pay, "t2", userID, pop, cityCodes, mobile, fromTime, toTime, orderTypes)
sql += rSQL2 + ","
sqlParams = append(sqlParams, rSQLParams2...)
rSQL3, rSQLParams3 := getFromSql(model.OrderTypeCash, model.OrderStatusFinished, "t3", userID, pop, cityCodes, mobile, fromTime, toTime, orderTypes)
sql += rSQL3 + ","
sqlParams = append(sqlParams, rSQLParams3...)
sql += `(SELECT SUM(IFNULL(b.account_balance,0)) account_balance
FROM user a
JOIN user_bill b ON a.user_id = b.user_id
`
if mobile != "" {
if pop == 1 {
sql += " JOIN user e ON e.moblie = ? AND a.pop_user = e.user_id"
sqlParams = append(sqlParams, mobile)
}
}
sql += `
WHERE 1 = 1
`
if userID != "" {
if pop == 1 {
sql += " AND a.pop_user = ?"
sqlParams = append(sqlParams, userID)
} else {
sql += " AND a.user_id = ?"
sqlParams = append(sqlParams, userID)
}
}
if mobile != "" {
if pop == 0 {
sql += " AND a.mobile = ?"
sqlParams = append(sqlParams, mobile)
}
}
if len(cityCodes) > 0 {
sql += ` AND a.city_code IN (` + GenQuestionMarks(len(cityCodes)) + `)`
sqlParams = append(sqlParams, cityCodes)
}
sql += `
) t4`
err = GetRow(db, &getPayStatisticsResult, sql, sqlParams)
sqlParams2 := []interface{}{}
getPayStatisticsResult1 := &GetPayStatisticsResult{}
sql2 := `
SELECT SUM(IFNULL(d.expend_price,0)) member_income
FROM user a`
if mobile != "" {
if pop == 1 {
sql2 += " JOIN user e ON e.moblie = ? AND a.pop_user = e.user_id"
sqlParams2 = append(sqlParams2, mobile)
}
}
sql2 += `
LEFT JOIN user_bill c ON c.user_id = a.user_id
LEFT JOIN bill_expend d ON d.bill_id = c.bill_id AND d.type = ?
`
sqlParams2 = append(sqlParams2, model.BillTypeMember)
if fromTime != utils.ZeroTimeValue {
sql2 += ` AND d.created_at > ?`
sqlParams2 = append(sqlParams2, fromTime)
}
if toTime != utils.ZeroTimeValue {
sql2 += ` AND d.created_at < ?`
sqlParams2 = append(sqlParams2, toTime)
}
sql2 += `
WHERE a.status = ? AND a.deleted_at = ?
`
sqlParams2 = append(sqlParams2, model.UserStatusNormal, utils.DefaultTimeValue)
if len(cityCodes) > 0 {
sql2 += ` AND a.city_code IN (` + GenQuestionMarks(len(cityCodes)) + `)`
sqlParams2 = append(sqlParams2, cityCodes)
}
if mobile != "" {
if pop == 0 {
sql2 += " AND a.mobile = ?"
sqlParams2 = append(sqlParams2, mobile)
}
}
if userID != "" {
if pop == 1 {
sql2 += " AND a.pop_user = ?"
sqlParams2 = append(sqlParams2, userID)
} else {
sql2 += " AND a.user_id = ?"
sqlParams2 = append(sqlParams2, userID)
}
}
err = GetRow(db, &getPayStatisticsResult1, sql2, sqlParams2)
getPayStatisticsResult.MemberIncome = getPayStatisticsResult1.MemberIncome
getPayStatisticsResult.CashIncome = getPayStatisticsResult.Cashed / 10
getPayStatisticsResult.TotalIncome = getPayStatisticsResult.MemberIncome + getPayStatisticsResult.CashIncome
return getPayStatisticsResult, err
}
type GetManageStatisticsResult struct {
Date time.Time `json:"date"` //日期
BrowseCount int `json:"browseCount"` //点击次数
AcceptCount int `json:"acceptCount"` //接受任务数
FinishCount int `json:"finishCount"` //完成任务数
CancelCount int `json:"cancelCount"` //取消任务数
TotalCash int `json:"totalCash"` //返现总额
InversionRate float64 `json:"inversionRate"` //转化率
}
func getFromSqlManage(status int, alies string, cityCodes []int, jobTime, endTime time.Time, jobIDs []int) (sql string, sqlParams []interface{}) {
sql += `
(SELECT COUNT(b.id) count
FROM job a
JOIN job_order b ON a.id = b.job_id
WHERE a.deleted_at = ?
`
sqlParams = append(sqlParams, utils.DefaultTimeValue)
if status != 0 {
sql += " AND b.status = ?"
sqlParams = append(sqlParams, status)
}
if jobTime != utils.ZeroTimeValue {
sql += " AND a.created_at > ?"
sqlParams = append(sqlParams, jobTime)
}
if endTime != utils.ZeroTimeValue {
sql += " AND a.created_at < ?"
sqlParams = append(sqlParams, endTime)
}
if len(cityCodes) > 0 {
sql += ` AND a.job_city_code IN (` + GenQuestionMarks(len(cityCodes)) + `)`
sqlParams = append(sqlParams, cityCodes)
}
if len(jobIDs) > 0 {
sql += ` AND a.id IN (` + GenQuestionMarks(len(jobIDs)) + `)`
sqlParams = append(sqlParams, jobIDs)
}
sql += ") " + alies
return sql, sqlParams
}
func getWhereSqlManage(cityCodes []int, jobTime, endTime time.Time, jobIDs []int) (sql string, sqlParams []interface{}) {
if jobTime != utils.ZeroTimeValue {
sql += " AND a.created_at > ?"
sqlParams = append(sqlParams, jobTime)
}
if endTime != utils.ZeroTimeValue {
sql += " AND a.created_at < ?"
sqlParams = append(sqlParams, endTime)
}
if len(cityCodes) > 0 {
sql += ` AND a.job_city_code IN (` + GenQuestionMarks(len(cityCodes)) + `)`
sqlParams = append(sqlParams, cityCodes)
}
if len(jobIDs) > 0 {
sql += ` AND a.id IN (` + GenQuestionMarks(len(jobIDs)) + `)`
sqlParams = append(sqlParams, jobIDs)
}
return sql, sqlParams
}
func GetManageStatistics(db *DaoDB, cityCodes []int, jobTime time.Time, jobIDs []int) (getManageStatisticsResult *GetManageStatisticsResult, err error) {
endTime := jobTime.AddDate(0, 0, 1)
sqlParams := []interface{}{}
sql := `
SELECT t1.count accept_count, t2.count finish_count, t3.count cancel_count, t4.browse_count, t6.total_cash
FROM
`
rSQL1, rSQLparams1 := getFromSqlManage(model.JobOrderStatusAccept, "t1", cityCodes, jobTime, endTime, jobIDs)
sql += rSQL1 + ","
sqlParams = append(sqlParams, rSQLparams1...)
rSQL2, rSQLparams2 := getFromSqlManage(model.JobOrderStatusFinish, "t2", cityCodes, jobTime, endTime, jobIDs)
sql += rSQL2 + ","
sqlParams = append(sqlParams, rSQLparams2...)
rSQL3, rSQLparams3 := getFromSqlManage(model.JobOrderStatusCancel, "t3", cityCodes, jobTime, endTime, jobIDs)
sql += rSQL3 + ","
sqlParams = append(sqlParams, rSQLparams3...)
sql += `
(SELECT SUM(a.browse_count) browse_count
FROM job a
JOIN job_order b ON a.id = b.job_id
WHERE a.deleted_at = ?
`
sqlParams = append(sqlParams, utils.DefaultTimeValue)
rSQL4, rSQLparams4 := getWhereSqlManage(cityCodes, jobTime, endTime, jobIDs)
sql += rSQL4
sqlParams = append(sqlParams, rSQLparams4...)
sql += `
) t4,
`
sql += `
(SELECT t5.count * a.avg_price total_cash FROM job a,
(SELECT COUNT(b.id) count, a.id
FROM job a
JOIN job_order b ON a.id = b.job_id
WHERE a.deleted_at = ? AND b.status = ?
`
sqlParams = append(sqlParams, utils.DefaultTimeValue, model.JobOrderStatusFinish)
rSQL5, rSQLparams5 := getWhereSqlManage(cityCodes, jobTime, endTime, jobIDs)
sql += rSQL5
sqlParams = append(sqlParams, rSQLparams5...)
sql += `
GROUP BY 2) t5
WHERE a.id = t5.id
)t6
`
GetRow(db, &getManageStatisticsResult, sql, sqlParams)
if getManageStatisticsResult == nil {
return &GetManageStatisticsResult{
Date: jobTime,
}, err
} else {
getManageStatisticsResult.Date = jobTime
if getManageStatisticsResult.BrowseCount == 0 {
getManageStatisticsResult.InversionRate = 0
} else {
getManageStatisticsResult.InversionRate = float64(getManageStatisticsResult.FinishCount) / float64(getManageStatisticsResult.BrowseCount)
}
return getManageStatisticsResult, err
}
}
type GetManageStatisticsJobResult struct {
BrowseCount int `json:"browseCount"` //点击次数
AcceptCount int `json:"acceptCount"` //接受任务数
FinishCount int `json:"finishCount"` //完成任务数
CancelCount int `json:"cancelCount"` //取消任务数
TotalCash int `json:"totalCash"` //返现总额
InversionRate float64 `json:"inversionRate"` //转化率
Title string `json:"title"` //任务标题
}
func GetManageStatisticsJob(db *DaoDB, cityCodes []int, fromTime, toTime time.Time, jobIDs []int, offset, pageSize int) (pageInfo *model.PagedInfo, err error) {
var (
sqlParams = []interface{}{}
getManageStatisticsJobResult []*GetManageStatisticsJobResult
)
sql := `
SELECT t1.count acceptCount, t2.count finish_count, t3.count cancel_count, a.browse_count, a.title, a.browse_count / t2.count inversion_rate, t4.total_cash
FROM job a
LEFT JOIN (SELECT job_id, COUNT(*) count FROM job_order WHERE status = ? GROUP BY 1) t1 ON t1.job_id = a.id
LEFT JOIN (SELECT job_id, COUNT(*) count FROM job_order WHERE status = ? GROUP BY 1) t2 ON t2.job_id = a.id
LEFT JOIN (SELECT job_id, COUNT(*) count FROM job_order WHERE status = ? GROUP BY 1) t3 ON t3.job_id = a.id
`
sql += `
LEFT JOIN (SELECT COUNT(b.id) * a.avg_price total_cash, a.id
FROM job a
JOIN job_order b ON a.id = b.job_id AND b.status = ?
GROUP BY 2) t4 ON t4.id = a.id
`
sqlParams = append(sqlParams, model.JobOrderStatusAccept, model.JobOrderStatusFinish, model.JobOrderStatusCancel, model.JobOrderStatusFinish)
sql += " WHERE a.deleted_at = ?"
sqlParams = append(sqlParams, utils.DefaultTimeValue)
rSQL, rSQLparams := getWhereSqlManage(cityCodes, fromTime, toTime, jobIDs)
sql += rSQL
sqlParams = append(sqlParams, rSQLparams...)
sql += " LIMIT ? OFFSET ?"
pageSize = jxutils.FormalizePageSize(pageSize)
sqlParams = append(sqlParams, pageSize, offset)
txDB, _ := Begin(db)
defer Commit(db, txDB)
err = GetRowsTx(txDB, &getManageStatisticsJobResult, sql, sqlParams)
if err == nil {
pageInfo = &model.PagedInfo{
Data: getManageStatisticsJobResult,
TotalCount: GetLastTotalRowCountTx(txDB),
}
}
return pageInfo, err
}
func GetUnionOrders(db *DaoDB, vendorIDs, statuss []int, beginTime, endTime time.Time, isEarning int) (orders []*model.UnionOrder, err error) {
sql := `
SELECT *
FROM union_order
WHERE 1 = 1
`
sqlParams := []interface{}{}
if len(vendorIDs) > 0 {
sql += ` AND vendor_id IN (` + GenQuestionMarks(len(vendorIDs)) + `)`
sqlParams = append(sqlParams, vendorIDs)
}
if len(statuss) > 0 {
sql += ` AND status IN (` + GenQuestionMarks(len(statuss)) + `)`
sqlParams = append(sqlParams, statuss)
}
if !utils.IsTimeZero(beginTime) {
sql += ` AND order_settle_at > ?`
sqlParams = append(sqlParams, beginTime)
}
if !utils.IsTimeZero(endTime) {
sql += ` AND order_settle_at < ?`
sqlParams = append(sqlParams, endTime)
}
if isEarning != -1 {
sql += ` AND is_earning = ?`
sqlParams = append(sqlParams, isEarning)
}
err = GetRows(db, &orders, sql, sqlParams)
return orders, err
}
func GetUnionOrdersByIDs(db *DaoDB, vendorOrderIDs []string, vendorID int) (orders []*model.UnionOrder, err error) {
if len(vendorOrderIDs) == 0 {
return nil, err
}
sql := `
SELECT *
FROM union_order
WHERE 1 = 1
`
sqlParams := []interface{}{}
if len(vendorOrderIDs) > 0 {
sql += ` AND vendor_order_id IN (` + GenQuestionMarks(len(vendorOrderIDs)) + `)`
sqlParams = append(sqlParams, vendorOrderIDs)
}
if vendorID != 0 {
sql += ` AND vendor_id = ?`
sqlParams = append(sqlParams, vendorID)
}
err = GetRows(db, &orders, sql, sqlParams)
return orders, err
}
func GetMyUnionOrders(db *DaoDB, userID string, statuss []int, vendorID, offset, pageSize int) (page *model.PagedInfo, err error) {
var orders []*model.UnionOrder
sql := `
SELECT SQL_CALC_FOUND_ROWS a.*
FROM union_order a
WHERE 1 = 1
`
sqlParams := []interface{}{}
if vendorID != -1 {
sql += ` AND a.vendor_id = ?`
sqlParams = append(sqlParams, vendorID)
}
if len(statuss) > 0 {
sql += ` AND a.status IN (` + GenQuestionMarks(len(statuss)) + `)`
sqlParams = append(sqlParams, statuss)
}
if userID != "" {
sql += ` AND a.user_id = ?`
sqlParams = append(sqlParams, userID)
}
sql += " ORDER BY a.created_at DESC"
sql += " LIMIT ? OFFSET ?"
pageSize = jxutils.FormalizePageSize(pageSize)
sqlParams = append(sqlParams, pageSize, offset)
txDB, _ := Begin(db)
defer Commit(db, txDB)
if err = GetRowsTx(txDB, &orders, sql, sqlParams...); err == nil {
page = &model.PagedInfo{
TotalCount: GetLastTotalRowCountTx(txDB),
Data: orders,
}
}
return page, err
}
type GetUnionOrdersPageResult struct {
model.UnionOrder
Name string `json:"name"`
Moble string `json:"moble"`
}
func GetUnionOrdersPage(db *DaoDB, vendorIDs, statuss []int, beginTime, endTime time.Time, keyword string, offset, pageSize int) (page *model.PagedInfo, err error) {
var orders []*GetUnionOrdersPageResult
sql := `
SELECT SQL_CALC_FOUND_ROWS a.*, b.name, b.mobile
FROM union_order a
LEFT JOIN user b ON a.user_id = b.user_id
WHERE 1 = 1
`
sqlParams := []interface{}{}
if len(vendorIDs) > 0 {
sql += ` AND a.vendor_id IN (` + GenQuestionMarks(len(vendorIDs)) + `)`
sqlParams = append(sqlParams, vendorIDs)
}
if len(statuss) > 0 {
sql += ` AND a.status IN (` + GenQuestionMarks(len(statuss)) + `)`
sqlParams = append(sqlParams, statuss)
}
if !utils.IsTimeZero(beginTime) {
sql += ` AND a.order_settle_at > ?`
sqlParams = append(sqlParams, beginTime)
}
if !utils.IsTimeZero(endTime) {
sql += ` AND a.order_settle_at < ?`
sqlParams = append(sqlParams, endTime)
}
if keyword != "" {
keywordLike := "%" + keyword + "%"
sql += ` AND (b.name LIKE ? OR b.mobile LIKE ? OR a.vendor_order_id LIKE ? OR a.goods_name LIKE ? OR a.comment LIKE ?)`
sqlParams = append(sqlParams, keywordLike, keywordLike, keywordLike, keywordLike, keywordLike)
}
sql += " LIMIT ? OFFSET ?"
pageSize = jxutils.FormalizePageSize(pageSize)
sqlParams = append(sqlParams, pageSize, offset)
txDB, _ := Begin(db)
defer Commit(db, txDB)
if err = GetRowsTx(txDB, &orders, sql, sqlParams...); err == nil {
page = &model.PagedInfo{
TotalCount: GetLastTotalRowCountTx(txDB),
Data: orders,
}
}
return page, err
}
//更新user_vendor_order 支付状态
func SetUserVendorOrderStatus(tx orm.TxOrmer, localWayBillID string, status int) (msg string, err error) {
if _, err := ExecuteSQL(GetDB(), "UPDATE `user_vendor_order` SET order_status = ? WHERE local_way_bill = ? ", []interface{}{status, localWayBillID}...); err != nil {
return "", err
}
return "更新UserVendorOrder状态成功", err
}
// QueryRechargeRecommend 电话充值记录查询
func QueryRechargeRecommend(userId []string, mobile, orderId string, page, pageSize int, start, end time.Time, rechargeStatus int) ([]*model.RechargeUserModelData, int, error) {
result := make([]*model.RechargeUserModelData, 0, 0)
sql := `SELECT SQL_CALC_FOUND_ROWS o.*,u.name FROM ` + "`order`" + ` o`
sqlParams := make([]interface{}, 0, 0)
sql += ` JOIN user u ON o.user_id = u.user_id WHERE 1=1 `
if orderId != "" {
sql += ` AND o.order_id = ? `
sqlParams = append(sqlParams, orderId)
if err := GetRows(GetDB(), &result, sql, sqlParams...); err != nil {
return nil, 0, err
}
return result, 1, nil
}
if userId != nil && len(userId) > 0 {
sql += ` AND o.user_id IN (` + GenQuestionMarks(len(userId)) + `)`
sqlParams = append(sqlParams, userId)
}
if !utils.IsTimeZero(start) {
sql += ` AND o.created_at > ? `
sqlParams = append(sqlParams, start)
}
if !utils.IsTimeZero(end) {
sql += ` AND o.created_at < ? `
sqlParams = append(sqlParams, end)
}
if mobile != "" {
sql += ` AND o.mobile = ? `
sqlParams = append(sqlParams, mobile)
}
if rechargeStatus != 0 {
sql += ` AND o.recharge_status = ? `
sqlParams = append(sqlParams, rechargeStatus)
}
sql += " ORDER BY o.created_at DESC LIMIT ? OFFSET ?"
sqlParams = append(sqlParams, jxutils.FormalizePageSize(pageSize), (page-1)*pageSize)
db := GetDB()
tx, _ := Begin(db)
defer func() {
if r := recover(); r != nil {
Rollback(db, tx)
}
}()
if err := GetRowsTx(tx, &result, sql, sqlParams...); err != nil {
Rollback(db, tx)
return nil, 0, err
}
count := GetLastTotalRowCountTx(tx)
return result, count, nil
}

View File

@@ -0,0 +1,162 @@
package dao
import (
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/globals"
"time"
)
func GetPrintMsgNoPage(db *DaoDB, printNo string, orderNo int64) (prints []*model.PrintMsg, err error) {
sql := `
SELECT *
FROM print_msg
WHERE 1 = 1
`
sqlParams := []interface{}{}
if printNo != "" {
sql += ` AND print_no = ?`
sqlParams = append(sqlParams, printNo)
}
if orderNo != 0 {
sql += ` AND order_no = ?`
sqlParams = append(sqlParams, orderNo)
}
sql += " ORDER BY created_at DESC LIMIT 1"
err = GetRows(db, &prints, sql, sqlParams)
return prints, err
}
func GetPrintMsgs(db *DaoDB, printNo string, statuss []int, beginAt, endAt time.Time, offset, pageSize int) (prints []*model.PrintMsg, err error) {
sql := `
SELECT a.*
FROM print_msg a
WHERE 1 = 1 AND a.deleted_at = ?
`
sqlParams := []interface{}{utils.DefaultTimeValue}
if printNo != "" {
sql += " AND a.print_no = ?"
sqlParams = append(sqlParams, printNo)
}
if len(statuss) > 0 {
sql += " AND a.status IN(" + GenQuestionMarks(len(statuss)) + ")"
sqlParams = append(sqlParams, statuss)
}
if !utils.IsTimeZero(beginAt) {
sql += " AND a.created_at > ?"
sqlParams = append(sqlParams, beginAt)
}
if !utils.IsTimeZero(endAt) {
sql += " AND a.created_at < ?"
sqlParams = append(sqlParams, endAt)
}
sql += " ORDER BY a.created_at LIMIT ? OFFSET ?"
sqlParams = append(sqlParams, pageSize, offset)
err = GetRows(db, &prints, sql, sqlParams)
return prints, err
}
func GetPrintMsg2(db *DaoDB, printNo, msgID string, status, statusNeq int) (printMsgs []*model.PrintMsg, err error) {
sql := `
SELECT *
FROM print_msg
WHERE 1 = 1 AND deleted_at = ?
`
sqlParams := []interface{}{
utils.DefaultTimeValue,
}
if status != model.PrintMsgAll {
sql += " AND status = ?"
sqlParams = append(sqlParams, status)
}
if statusNeq != model.PrintMsgAll {
sql += " AND status <> ?"
sqlParams = append(sqlParams, statusNeq)
}
if printNo != "" {
sql += " AND print_no = ?"
sqlParams = append(sqlParams, printNo)
}
if msgID != "" {
sql += " AND msg_id = ?"
sqlParams = append(sqlParams, msgID)
}
err = GetRows(db, &printMsgs, sql, sqlParams)
return printMsgs, err
}
func GetPrintMsgsFail(db *DaoDB, beginAt, endAt time.Time) (prints []*model.PrintMsg, err error) {
sql := `
SELECT *
FROM print_msg
WHERE 1 = 1 AND deleted_at = ?
AND status <> ?
`
sqlParams := []interface{}{utils.DefaultTimeValue, 1}
if !utils.IsTimeZero(beginAt) {
sql += " AND created_at > ?"
sqlParams = append(sqlParams, beginAt)
}
if !utils.IsTimeZero(endAt) {
sql += " AND created_at < ?"
sqlParams = append(sqlParams, endAt)
}
err = GetRows(db, &prints, sql, sqlParams)
return prints, err
}
func GetPrinter(db *DaoDB, printNo string) (print *model.Printer, err error) {
sql := `
SELECT * FROM printer WHERE print_no = ? AND deleted_at = ?
`
sqlParams := []interface{}{printNo, utils.DefaultTimeValue}
err = GetRow(db, &print, sql, sqlParams)
return print, err
}
// DeletePrintMsg 删除超过一个月时间的打印订单信息
func DeletePrintMsg() {
sql := ` DELETE FROM print_msg WHERE created_at < ?`
num, err := ExecuteSQL(GetDB(), sql, []interface{}{time.Now().AddDate(0, -1, 0)}...)
if err != nil {
globals.SugarLogger.Debugf("定时删除超过一个月的打印信息错误:%v", err)
}
globals.SugarLogger.Debugf("定时删除超过一个月的打印信息:%d 条", num)
return
}
func QueryPrintList(db *DaoDB, printNo, printKey string, status, isOnline int64, page, size int64) (print []*model.Printer, count int, err error) {
sql := `
SELECT SQL_CALC_FOUND_ROWS * FROM printer WHERE 1=1
`
sqlParams := []interface{}{}
if printNo != "" {
sql += ` AND print_no = ?`
sqlParams = append(sqlParams, printNo)
}
if printKey != "" {
sql += ` AND print_key = ?`
sqlParams = append(sqlParams, printKey)
}
if status != model.PrintMsgAll {
sql += ` AND status = ?`
sqlParams = append(sqlParams, status)
}
if isOnline != model.PrintMsgAll {
sql += ` AND is_online = ?`
sqlParams = append(sqlParams, isOnline)
}
sql += ` AND deleted_at = ?`
sqlParams = append(sqlParams, utils.DefaultTimeValue)
sql += ` ORDER BY status desc,is_online desc LIMIT ? OFFSET ? `
sqlParams = append(sqlParams, size, page)
tx, _ := Begin(db)
if err = GetRowsTx(tx, &print, sql, sqlParams...); err != nil {
Rollback(db, tx)
return nil, 0, err
}
count = GetLastTotalRowCountTx(tx)
defer Commit(db, tx)
return print, count, err
}

View File

@@ -3,7 +3,6 @@ package dao
import (
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/model"
"git.rosy.net.cn/jx-callback/globals"
)
// QueryUserPrinter 查询用户打印机
@@ -57,11 +56,10 @@ func GetPrinters(db *DaoDB, appID int, printNo string, status, statusNeq int) (p
}
err = GetRows(db, &printers, sql, sqlParams)
globals.SugarLogger.Debugf("======printers==== %s", utils.Format4Output(printers, false))
return printers, err
}
func GetPrintMsgs(db *DaoDB, printNo, msgID string, status, statusNeq int) (printMsgs []*model.PrintMsg, err error) {
func GetPrintMsgs2(db *DaoDB, printNo, msgID string, status, statusNeq int) (printMsgs []*model.PrintMsg, err error) {
sql := `
SELECT *
FROM print_msg

View File

@@ -0,0 +1,454 @@
package dao
import (
"fmt"
"time"
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/jxutils"
"git.rosy.net.cn/jx-callback/business/model"
)
type UserDeliveryAddressEx struct {
model.UserDeliveryAddress
UserName string `json:"userName"`
CityName string `json:"cityName"`
DistrictName string `json:"districtName"`
ParentCode int `json:"parentCode"`
}
type GetSelfInfoResult struct {
model.User
model.UserBill
WaitCashPrice int `json:"waitCashPrice"`
WaitRealCashPrice int `json:"waitRealCashPrice"`
UserMembers []*model.UserMember `json:"userMembers"`
PopedUserName string `json:"popedUserName"`
UnReadMessageCount int `json:"unReadMessageCount"`
}
func GetUserByID(db *DaoDB, fieldName, fieldValue string) (user *model.User, err error) {
sql := fmt.Sprintf(`
SELECT *
FROM user t1
WHERE t1.deleted_at = ? AND t1.status = ? AND t1.%s = ?
`, fieldName)
sqlParams := []interface{}{
utils.DefaultTimeValue,
model.UserStatusNormal,
fieldValue,
}
// globals.SugarLogger.Debugf("GetUserByID sql:%s, sqlParams:%s", sql, utils.Format4Output(sqlParams, false))
err = GetRow(db, &user, sql, sqlParams...)
return user, err
}
func GetUserByIDWithMembers(db *DaoDB, fieldName, fieldValue string) (getSelfInfoResult *GetSelfInfoResult, err error) {
sql := fmt.Sprintf(`
SELECT t1.*, t2.bill_id, t2.account_balance, t3.name pop_user_name
FROM user t1
JOIN user_bill t2 ON t2.user_id = t1.user_id AND t2.deleted_at = ?
LEFT JOIN user t3 ON t3.user_id = t1.pop_user
WHERE t1.deleted_at = ? AND t1.status = ? AND t1.%s = ?
`, fieldName)
sqlParams := []interface{}{
utils.DefaultTimeValue,
utils.DefaultTimeValue,
model.UserStatusNormal,
fieldValue,
}
// globals.SugarLogger.Debugf("GetUserByID sql:%s, sqlParams:%s", sql, utils.Format4Output(sqlParams, false))
err = GetRow(db, &getSelfInfoResult, sql, sqlParams...)
if messageGroupReads, err := GetMessageGroupRead(db, getSelfInfoResult.User.UserID, 0); err == nil {
var unReadCount int
for _, v := range messageGroupReads {
unReadCount += v.UnReadCount
}
getSelfInfoResult.UnReadMessageCount = unReadCount
}
return getSelfInfoResult, err
}
func GetUsers(db *DaoDB, userType int, keyword, popUser string, userIDs, userID2s, mobiles []string, offset, pageSize int) (userList []*model.User, totalCount int, err error) {
offset = jxutils.FormalizePageOffset(offset)
pageSize = jxutils.FormalizePageSize(pageSize)
if userType == 0 {
userType = 255
}
sqlParams := []interface{}{}
sql := `
SELECT SQL_CALC_FOUND_ROWS
t1.*
FROM user t1
WHERE t1.status = 1 AND t1.deleted_at = ?`
sqlParams = append(sqlParams, utils.DefaultTimeValue)
if len(userIDs) > 0 {
sql += " AND t1.user_id IN (" + GenQuestionMarks(len(userIDs)) + ")"
sqlParams = append(sqlParams, userIDs)
}
if len(userID2s) > 0 {
sql += " AND t1.user_id2 IN (" + GenQuestionMarks(len(userID2s)) + ")"
sqlParams = append(sqlParams, userID2s)
}
if len(mobiles) > 0 {
sql += " AND t1.mobile IN (" + GenQuestionMarks(len(mobiles)) + ")"
sqlParams = append(sqlParams, mobiles)
}
if popUser != "" {
sql += " AND t1.pop_user = ?"
sqlParams = append(sqlParams, popUser)
}
if keyword != "" {
keywordLike := "%" + keyword + "%"
sql += " AND (t1.user_id LIKE ? OR t1.user_id2 LIKE ? OR t1.mobile LIKE ? OR t1.email LIKE ? OR t1.name LIKE ?)"
sqlParams = append(sqlParams, keywordLike, keywordLike, keywordLike, keywordLike, keywordLike)
}
sql += " LIMIT ? OFFSET ?"
sqlParams = append(sqlParams, pageSize, offset)
txDB, _ := Begin(db)
defer Commit(db, txDB)
if err = GetRowsTx(txDB, &userList, sql, sqlParams...); err == nil {
totalCount = GetLastTotalRowCountTx(txDB)
}
return userList, totalCount, err
}
func GetUsers2(db *DaoDB, keyword string, userID string, pop int, mobile string, fromTime, toTime time.Time, timeType int, cityCodes, consumeTypes []int, offset, pageSize int) (pageInfo *model.PagedInfo, err error) {
var (
userList []*model.UserBalance
)
offset = jxutils.FormalizePageOffset(offset)
pageSize = jxutils.FormalizePageSize(pageSize)
sqlParams := []interface{}{}
sql := `
SELECT SQL_CALC_FOUND_ROWS DISTINCT
a.*,ub.account_balance
FROM user a`
for _, v := range consumeTypes {
switch v {
case model.ConsumeTypePublishJob:
sql += " JOIN job b ON b.user_id = a.user_id"
if fromTime != utils.ZeroTimeValue {
if timeType == 2 {
sql += " AND b.created_at > ?"
sqlParams = append(sqlParams, fromTime)
}
}
if toTime != utils.ZeroTimeValue {
if timeType == 2 {
sql += " AND b.created_at < ?"
sqlParams = append(sqlParams, toTime)
}
}
case model.ConsumeTypeMember:
sql += " JOIN user_member c ON c.user_id = a.user_id"
if fromTime != utils.ZeroTimeValue {
if timeType == 2 {
sql += " AND c.created_at > ?"
sqlParams = append(sqlParams, fromTime)
}
}
if toTime != utils.ZeroTimeValue {
if timeType == 2 {
sql += " AND c.created_at < ?"
sqlParams = append(sqlParams, toTime)
}
}
case model.ConsumeTypeDelivery:
sql += " JOIN delivery_order d ON d.user_id = a.user_id"
if fromTime != utils.ZeroTimeValue {
if timeType == 2 {
sql += " AND d.created_at > ?"
sqlParams = append(sqlParams, fromTime)
}
}
if toTime != utils.ZeroTimeValue {
if timeType == 2 {
sql += " AND d.created_at < ?"
sqlParams = append(sqlParams, toTime)
}
}
}
}
sql += ` JOIN user_bill ub ON ub.user_id = a.user_id`
sql += `
WHERE a.status = 1 AND a.deleted_at = ?`
sqlParams = append(sqlParams, utils.DefaultTimeValue)
if userID != "" {
if pop == 1 {
sql += " AND a.pop_user = ?"
sqlParams = append(sqlParams, userID)
} else {
sql += " AND a.user_id = ?"
sqlParams = append(sqlParams, userID)
}
}
if len(cityCodes) > 0 {
sql += " AND a.city_code IN (" + GenQuestionMarks(len(cityCodes)) + ")"
sqlParams = append(sqlParams, cityCodes)
}
if mobile != "" {
sql += " AND a.mobile = ?"
sqlParams = append(sqlParams, mobile)
}
if keyword != "" {
keywordLike := "%" + keyword + "%"
sql += " AND (a.user_id LIKE ? OR a.mobile LIKE ? OR a.email LIKE ? OR a.name LIKE ?)"
sqlParams = append(sqlParams, keywordLike, keywordLike, keywordLike, keywordLike)
}
if fromTime != utils.ZeroTimeValue {
if timeType == 1 {
sql += " AND a.created_at > ?"
sqlParams = append(sqlParams, fromTime)
}
}
if toTime != utils.ZeroTimeValue {
if timeType == 1 {
sql += " AND a.created_at < ?"
sqlParams = append(sqlParams, toTime)
}
}
sql += " LIMIT ? OFFSET ?"
sqlParams = append(sqlParams, pageSize, offset)
txDB, _ := Begin(db)
defer Commit(db, txDB)
if err = GetRowsTx(txDB, &userList, sql, sqlParams...); err == nil {
pageInfo = &model.PagedInfo{
TotalCount: GetLastTotalRowCountTx(txDB),
Data: userList,
}
}
return pageInfo, err
}
func GetUser(db *DaoDB, userID string) (user *model.GetUserResult, err error) {
sqlParams := []interface{}{}
sql := `
SELECT
t1.*, IF(t2.accept_order_count is NULL, 0, t2.accept_order_count) accept_order_count, IF(t3.finished_order_count is NULL, 0, t3.finished_order_count) finished_order_count
FROM user t1
LEFT JOIN (SELECT user_id, COUNT(user_id) accept_order_count FROM job_order WHERE user_id = ? GROUP BY 1)t2 ON t2.user_id = t1.user_id
LEFT JOIN (SELECT user_id, COUNT(user_id) finished_order_count FROM job_order WHERE user_id = ? AND status = ? GROUP BY 1)t3 ON t3.user_id = t1.user_id
WHERE t1.status = ? AND t1.deleted_at = ? AND t1.user_id = ? `
sqlParams = append(sqlParams, userID, userID, model.JobOrderStatusFinish, model.YES, utils.DefaultTimeValue, userID)
err = GetRow(db, &user, sql, sqlParams...)
return user, err
}
func DeleteUsers(db *DaoDB, userIDs []string) (num int64, err error) {
if len(userIDs) > 0 {
sql := `
UPDATE user t1
JOIN auth_bind t2 ON t2.user_id = t1.user_id
SET
t1.deleted_at = ?,
t2.deleted_at = ?
WHERE t1.user_id IN (` + GenQuestionMarks(len(userIDs)) + ");"
now := time.Now()
sqlParams := []interface{}{
now,
now,
userIDs,
}
num, err = ExecuteSQL(db, sql, sqlParams...)
}
return num, err
}
func QueryUserDeliveryAddress(db *DaoDB, addressID int64, userIDs []string, addType int, offset, pageSize int) (addressList []*UserDeliveryAddressEx, totalCount int, err error) {
sql := `
SELECT SQL_CALC_FOUND_ROWS
t1.*,
t2.name user_name,
district.name district_name,
city.name city_name,
cp.code parent_code
FROM user_delivery_address t1
LEFT JOIN user t2 ON t2.user_id = t1.user_id
LEFT JOIN place district ON district.code = t1.district_code
LEFT JOIN place city ON city.code = t1.city_code
LEFT JOIN place cp ON cp.code = city.parent_code
WHERE t1.deleted_at = ?
`
sqlParams := []interface{}{
utils.DefaultTimeValue,
}
if addressID > 0 {
sql += " AND t1.id = ? "
sqlParams = append(sqlParams, addressID)
}
if len(userIDs) > 0 {
sql += " AND t1.user_id IN (" + GenQuestionMarks(len(userIDs)) + ")"
sqlParams = append(sqlParams, userIDs)
}
if addType != 0 {
sql += " AND t1.type = ? "
sqlParams = append(sqlParams, addType)
}
offset = jxutils.FormalizePageOffset(offset)
pageSize = jxutils.FormalizePageSize(pageSize)
sql += `
ORDER BY t1.is_default DESC, t1.consignee_name
LIMIT ? OFFSET ?`
sqlParams = append(sqlParams, pageSize, offset)
txDB, _ := Begin(db)
defer Commit(db, txDB)
if err = GetRowsTx(txDB, &addressList, sql, sqlParams...); err == nil {
totalCount = GetLastTotalRowCountTx(txDB)
}
return addressList, totalCount, err
}
func ClearUserDeliveryAddressDefault(db *DaoDB, userID string, defAddressID int) (err error) {
sql := `
UPDATE user_delivery_address t1
SET t1.is_default = 0
WHERE t1.deleted_at = ? AND t1.user_id = ?
`
sqlParams := []interface{}{
utils.DefaultTimeValue,
userID,
}
if defAddressID > 0 {
sql += " AND t1.id <> ?"
sqlParams = append(sqlParams, defAddressID)
}
_, err = ExecuteSQL(db, sql, sqlParams...)
return err
}
func GetUserOrderSMS(db *DaoDB, mobile, name string) (userOrderSms *model.UserOrderSms, err error) {
sql := `
SELECT *
FROM user_order_sms
WHERE 1=1
`
sqlParams := []interface{}{}
if mobile != "" {
sql += " AND mobile = ?"
sqlParams = append(sqlParams, mobile)
}
if name != "" {
sql += " AND name like ?"
sqlParams = append(sqlParams, "%"+name+"%")
}
err = GetRow(db, &userOrderSms, sql, sqlParams)
return userOrderSms, err
}
func GetUserMember(db *DaoDB, userID string, memberType int) (userMembers []*model.UserMember, err error) {
sql := `
SELECT a.*
FROM user_member a
WHERE a.deleted_at = ?
`
sqlParams := []interface{}{utils.DefaultTimeValue}
if userID != "" {
sql += " AND a.user_id = ?"
sqlParams = append(sqlParams, userID)
}
if memberType != 0 {
sql += " AND a.member_type = ?"
sqlParams = append(sqlParams, memberType)
}
err = GetRows(db, &userMembers, sql, sqlParams)
return userMembers, err
}
type GetUserAllWaitCashPriceResult struct {
UserID string `orm:"column(user_id)" json:"userID"`
Price int `json:"price"`
}
func GetUserAllWaitCashPrice(db *DaoDB, userID string) (price int, err error) {
var result = &GetUserAllWaitCashPriceResult{}
sql := `
SELECT SUM(IF(d.id IS NOT NULL, IF(d.divide_percentage = 0, b.avg_price, b.avg_price*(100-d.divide_percentage)/100),b.avg_price)) price, a.user_id
FROM job_order a
JOIN job b ON a.job_id = b.id
LEFT JOIN message_group_member c ON a.user_id = c.member_user_id
LEFT JOIN message_group d ON d.group_id = c.group_id AND d.type = ?
WHERE a.user_id = ?
AND a.status = ?
`
sqlParams := []interface{}{
model.GroupTypeMulit,
userID,
model.JobOrderStatusWaitAudit,
}
err = GetRow(db, &result, sql, sqlParams)
return result.Price, err
}
func GetUserAllWaitRealCashPrice(db *DaoDB, userID string) (price int, err error) {
var result = &GetUserAllWaitCashPriceResult{}
sql := `
SELECT SUM(pay_price) price FROM ` + "`order`" + ` WHERE user_id = ? AND status = ? AND type = ?
`
sqlParams := []interface{}{
userID,
model.OrderStatusWait4Pay,
model.OrderTypeCash,
}
err = GetRow(db, &result, sql, sqlParams)
return result.Price, err
}
func GetUserUnionBind(db *DaoDB, userID string, vendorID int, unionID string) (userBinds []*model.UserUnionBind, err error) {
sql := `
SELECT * FROM user_union_bind WHERE deleted_at = ?
`
sqlParams := []interface{}{
utils.DefaultTimeValue,
}
if userID != "" {
sql += " AND user_id = ?"
sqlParams = append(sqlParams, userID)
}
if vendorID != -1 {
sql += " AND vendor_id = ?"
sqlParams = append(sqlParams, vendorID)
}
if unionID != "" {
sql += " AND union_id = ?"
sqlParams = append(sqlParams, unionID)
}
err = GetRows(db, &userBinds, sql, sqlParams)
return userBinds, err
}
func GetUserUnionBindImg(db *DaoDB, unionID, actID string) (userBinds *model.UserUnionBindImg, err error) {
sql := `
SELECT * FROM user_union_bind_img WHERE deleted_at = ?
`
sqlParams := []interface{}{
utils.DefaultTimeValue,
}
if unionID != "" {
sql += " AND union_id = ?"
sqlParams = append(sqlParams, unionID)
}
if actID != "" {
sql += " AND act_id = ?"
sqlParams = append(sqlParams, actID)
}
err = GetRow(db, &userBinds, sql, sqlParams)
return userBinds, err
}
func GetUserVendorOrder(db *DaoDB, userID, localWayBill string) (userVendorOrder *model.UserVendorOrder, err error) {
sql := `SELECT * FROM user_vendor_order WHERE deleted_at = ? `
sqlParams := []interface{}{
utils.DefaultTimeValue,
}
if userID != "" {
sql += "AND user_id = ?"
sqlParams = append(sqlParams, userID)
}
if localWayBill != "" {
sql += " AND local_way_bill = ?"
sqlParams = append(sqlParams, localWayBill)
}
err = GetRow(db, &userVendorOrder, sql, sqlParams)
return userVendorOrder, err
}

View File

@@ -0,0 +1,13 @@
package dao
import (
"testing"
)
func TestGetUsers(t *testing.T) {
//userList, _, err := GetUsers(GetDB(), 0, "", nil, nil, []string{"18180948107"}, 0, 0)
//if err != nil {
// t.Fatal(err)
//}
//t.Log(utils.Format4Output(userList, false))
}

View File

@@ -142,6 +142,66 @@ func GetOperateEvents(db *DaoDB, name string, apiFunctions []string, operateType
return operateEventExt, totalCount, err
}
func GetImMessageRecord(db *DaoDB, groupID int, userID, toUserID string, storeID, vendorID int, fromTime, toTime time.Time, offset, pageSize int) (pagedInfo *model.PagedInfo, err error) {
var msg []*model.ImMessageRecord
sql := `
SELECT SQL_CALC_FOUND_ROWS *
FROM im_message_record
WHERE deleted_at = ?
`
sqlParams := []interface{}{
utils.DefaultTimeValue,
}
if groupID != 0 {
sql += " AND group_id = ?"
sqlParams = append(sqlParams, groupID)
if groupID == model.SysGroupID {
sql += " AND to_user_id = ?"
sqlParams = append(sqlParams, toUserID)
}
}
if userID != "" {
sql += " AND user_id = ?"
sqlParams = append(sqlParams, userID)
}
if storeID != 0 {
sql += " AND store_id = ?"
sqlParams = append(sqlParams, storeID)
}
if vendorID >= 0 {
sql += " AND vendor_id = ?"
sqlParams = append(sqlParams, vendorID)
}
if fromTime != utils.ZeroTimeValue {
sql += " AND created_at >= ?"
sqlParams = append(sqlParams, fromTime)
}
if toTime != utils.ZeroTimeValue {
sql += " AND created_at <= ?"
sqlParams = append(sqlParams, toTime)
}
sql += `
ORDER BY created_at DESC
LIMIT ? OFFSET ?
`
sqlParams = append(sqlParams, pageSize, offset)
txDB, _ := Begin(db)
defer Commit(db, txDB)
if err = GetRowsTx(txDB, &msg, sql, sqlParams); err == nil {
pagedInfo = &model.PagedInfo{
TotalCount: GetLastTotalRowCountTx(txDB),
// Data: msg,
}
for _, v := range msg {
if user, err := GetUser(db, v.UserID); err == nil {
v.UserInfo = user
}
}
pagedInfo.Data = msg
}
return pagedInfo, err
}
type GetMessageGroupsResult struct {
model.MessageGroup
Avatar string `json:"avatar"`

View File

@@ -0,0 +1,108 @@
package dao
import (
"git.rosy.net.cn/baseapi/utils"
"git.rosy.net.cn/jx-callback/business/model"
)
func GetMenu(db *DaoDB, name string, level int, userID string) (menus []*model.Menu, err error) {
sqlParams := []interface{}{}
sql := `
SELECT DISTINCT a.*
FROM menu a
`
if userID != "" {
sql += `
JOIN menu d ON d.parent_id = a.id
JOIN user_role b ON b.user_id = ?
JOIN role_menu c ON c.menu_id = d.id AND c.role_id = b.role_id
`
sqlParams = append(sqlParams, userID)
}
sql += " WHERE a.deleted_at = ?"
sqlParams = append(sqlParams, utils.DefaultTimeValue)
if name != "" {
sql += " AND a.name LIKE ?"
sqlParams = append(sqlParams, "%"+name+"%")
}
if level != 0 {
sql += " AND a.level = ?"
sqlParams = append(sqlParams, level)
}
err = GetRows(db, &menus, sql, sqlParams)
return menus, err
}
func GetMenuWithUser(db *DaoDB, name string, level int, userID string) (menus []*model.Menu, err error) {
sql := `
SELECT DISTINCT b.* FROM (
SELECT a.id,a.parent_id
FROM menu a
JOIN user_role b ON b.user_id = ?
JOIN role_menu c ON c.menu_id = a.id AND c.role_id = b.role_id
WHERE a.deleted_at = ?)a
JOIN menu b ON (b.id = a.id OR b.id = a.parent_id)
`
sqlParams := []interface{}{userID, utils.DefaultTimeValue}
err = GetRows(db, &menus, sql, sqlParams)
return menus, err
}
func GetRole(db *DaoDB, name string) (roles []*model.Role, err error) {
sql := `
SELECT *
FROM role
WHERE deleted_at = ?
`
sqlParams := []interface{}{
utils.DefaultTimeValue,
}
if name != "" {
sql += " AND name LIKE ?"
sqlParams = append(sqlParams, "%"+name+"%")
}
err = GetRows(db, &roles, sql, sqlParams)
return roles, err
}
func GetUserRole(db *DaoDB, userIDs []string, roleIDs []int) (userRoles []*model.UserRole, err error) {
sql := `
SELECT *
FROM user_role
WHERE deleted_at = ?
`
sqlParams := []interface{}{
utils.DefaultTimeValue,
}
if len(userIDs) > 0 {
sql += " AND user_id IN (" + GenQuestionMarks(len(userIDs)) + ")"
sqlParams = append(sqlParams, userIDs)
}
if len(roleIDs) > 0 {
sql += " AND role_id IN (" + GenQuestionMarks(len(roleIDs)) + ")"
sqlParams = append(sqlParams, roleIDs)
}
err = GetRows(db, &userRoles, sql, sqlParams)
return userRoles, err
}
func GetRoleMenu(db *DaoDB, roleIDs, menuIDs []int) (roleMenus []*model.RoleMenu, err error) {
sql := `
SELECT *
FROM role_menu
WHERE deleted_at = ?
`
sqlParams := []interface{}{
utils.DefaultTimeValue,
}
if len(roleIDs) > 0 {
sql += " AND role_id IN (" + GenQuestionMarks(len(roleIDs)) + ")"
sqlParams = append(sqlParams, roleIDs)
}
if len(menuIDs) > 0 {
sql += " AND menu_id IN (" + GenQuestionMarks(len(menuIDs)) + ")"
sqlParams = append(sqlParams, menuIDs)
}
err = GetRows(db, &roleMenus, sql, sqlParams)
return roleMenus, err
}

View File

@@ -0,0 +1,15 @@
package dao
import (
"git.rosy.net.cn/jx-callback/business/model"
"time"
)
func NotExistsCreate(printNo string) error {
item := &model.PrintActivation{
CreatedAt: time.Now(),
PrintNo: printNo,
}
return CreateOrUpdate(GetDB(), item)
}

View File

@@ -0,0 +1,28 @@
package dao
import (
"errors"
"git.rosy.net.cn/jx-callback/business/model"
)
// DeductionPrintBalance 扣除打印机账号余额
/*func DeductionPrintBalance(db *DaoDB, printNo string) error {
_, err := ExecuteSQL(db, `UPDATE print_bill SET print_balance = print_balance -1 WHERE print_no = ?`, []interface{}{printNo}...)
return err
}*/
// DeductionPrintBalance 扣除打印机账号余额
func DeductionPrintBalance(db *DaoDB, printNo string) error {
var data *model.PrintBill
if err := GetRow(db, &data, `SELECT * FROM print_bill WHERE print_no = ?`, []interface{}{printNo}...); err != nil {
return err
}
if data == nil {
return errors.New("数据异常")
}
data.PrintBalance -= 1
_, err := UpdateEntity(db, data, "print_balance")
return err
}

View File

@@ -0,0 +1,32 @@
package dao
import (
"git.rosy.net.cn/jx-callback/business/model"
"time"
)
// QueryOrderDeductionRecord 查询订单扣除记录
func QueryOrderDeductionRecord(db *DaoDB, printNo string, orderNo string) (bool, error) {
sql := `SELECT * FROM print_bill_record WHERE print_no = ? AND order_id = ? AND created_at > ? AND created_at < ?`
timeNow := time.Now()
startTime := time.Date(timeNow.Year(), timeNow.Month(), timeNow.Day(), 0, 0, 0, 0, timeNow.Location())
endTime := time.Date(timeNow.Year(), timeNow.Month(), timeNow.Day(), 23, 59, 59, 0, timeNow.Location())
param := []interface{}{printNo, orderNo, startTime, endTime}
var result []*model.PrintBillRecord
if err := GetRows(db, &result, sql, param...); err != nil {
return false, err
}
if len(result) == 0 {
return false, nil
}
return true, nil
}
// AddPrintRecord 添加打印记录
func AddPrintRecord(db *DaoDB, param *model.PrintBillRecord) error {
return CreateEntity(db, param)
}

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