Compare commits
1982 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
637a878808 | ||
|
|
999c3d7ebe | ||
|
|
8a8f545656 | ||
|
|
ce6b120f23 | ||
|
|
3651bf0e1d | ||
|
|
2e261aab4b | ||
|
|
5d76781965 | ||
|
|
bf44d2b733 | ||
|
|
c8e1500892 | ||
|
|
4e1c338bec | ||
|
|
e3fdcd179a | ||
|
|
b4c5df3616 | ||
|
|
505e347939 | ||
|
|
1380b581bc | ||
|
|
f99ef659e0 | ||
|
|
829c546a52 | ||
|
|
f520b3e2e0 | ||
|
|
f74945fab9 | ||
|
|
88f6e70fc8 | ||
|
|
200cefcfb3 | ||
|
|
d5bea30024 | ||
|
|
a9e521eaf2 | ||
|
|
2055c4bb3b | ||
|
|
e0b26ea5b8 | ||
|
|
1f779012a2 | ||
|
|
2df383a788 | ||
|
|
1f40c96cfe | ||
|
|
2b9135903b | ||
|
|
7660eeca92 | ||
|
|
a6bee06006 | ||
|
|
3cb005011c | ||
|
|
93aaf0f58a | ||
|
|
ab090a9fee | ||
|
|
d70f73b541 | ||
|
|
810eefd386 | ||
|
|
3251816066 | ||
|
|
90ff64452a | ||
|
|
544e64dc29 | ||
|
|
8f590d0239 | ||
|
|
6cc389cd0f | ||
|
|
4ae054de73 | ||
|
|
53abbb82d6 | ||
|
|
7eb06a41ae | ||
|
|
1186935d7d | ||
|
|
f3b7e22f23 | ||
|
|
8613ac0861 | ||
|
|
fa87217b90 | ||
|
|
2a0d749ef5 | ||
|
|
2151ea27a9 | ||
|
|
cffad3c660 | ||
|
|
e7e7729715 | ||
|
|
de98b0f88a | ||
|
|
1565ed626b | ||
|
|
df9e1ae124 | ||
|
|
42360e124f | ||
|
|
3bbd241264 | ||
|
|
10b7aa3bc7 | ||
|
|
2e3b7d31ca | ||
|
|
a077b5b8d2 | ||
|
|
c17fe6022f | ||
|
|
27c870ff4d | ||
|
|
28aea06a4c | ||
|
|
5530ab4d01 | ||
|
|
e3fedfdcd2 | ||
|
|
2de089f09a | ||
|
|
eee469ca48 | ||
|
|
0a9699d764 | ||
|
|
6e4d330d35 | ||
|
|
113212b1dd | ||
|
|
680c2030ec | ||
|
|
e0c1a93d66 | ||
|
|
e17e9db240 | ||
|
|
a3b8183585 | ||
|
|
3f5ad2d1ff | ||
|
|
774e7c2579 | ||
|
|
c19efa359e | ||
|
|
1439e701ac | ||
|
|
3ff6d7bd8b | ||
|
|
ca1f95297c | ||
|
|
a83617e477 | ||
|
|
5cd7764c6e | ||
|
|
31ca7605c8 | ||
|
|
d19d4573b9 | ||
|
|
0c52053739 | ||
|
|
ca6df068a6 | ||
|
|
46868e633c | ||
|
|
54a6939d0b | ||
|
|
601e146ba9 | ||
|
|
f95d55a8d2 | ||
|
|
b2b52b336c | ||
|
|
6a04c366bf | ||
|
|
2e904f3719 | ||
|
|
06b225aff3 | ||
|
|
5278ba7739 | ||
|
|
3db704f235 | ||
|
|
1ed5e7e259 | ||
|
|
5ce817e327 | ||
|
|
be829b7399 | ||
|
|
c8b9eb7eff | ||
|
|
a7232b6d3b | ||
|
|
f41547f7b7 | ||
|
|
09806185d8 | ||
|
|
10d7ed2a2c | ||
|
|
27da0e4c57 | ||
|
|
69ad23a7dd | ||
|
|
fdc2736012 | ||
|
|
ff968cbdcf | ||
|
|
20f11b0c4e | ||
|
|
1469168f90 | ||
|
|
3fb979009b | ||
|
|
1c3eadf096 | ||
|
|
a29a10152a | ||
|
|
0f781849b4 | ||
|
|
3c4ffc3599 | ||
|
|
7c2a2bbea1 | ||
|
|
17ff0169b8 | ||
|
|
82eba6b49c | ||
|
|
1c76565c02 | ||
|
|
764f22b32c | ||
|
|
08f8c08c4d | ||
|
|
a067a9ad92 | ||
|
|
ad54650303 | ||
|
|
765517013c | ||
|
|
fec4011989 | ||
|
|
92ec3f3b1f | ||
|
|
57ac67e874 | ||
|
|
0efcc40b09 | ||
|
|
71234f6b48 | ||
|
|
078ca7e9b2 | ||
|
|
44e0edc404 | ||
|
|
f27a3ee5e2 | ||
|
|
2be3fb329e | ||
|
|
944166496e | ||
|
|
5f1bf89743 | ||
|
|
5f3f974d3e | ||
|
|
ff7ae26ce5 | ||
|
|
a376e4b90d | ||
|
|
fc1cc16de6 | ||
|
|
ca27491d14 | ||
|
|
ed419d5a4d | ||
|
|
9e2b93b6cd | ||
|
|
f9913ead46 | ||
|
|
70dfb81139 | ||
|
|
4b9c783b9a | ||
|
|
d626fcf12d | ||
|
|
958ab4686d | ||
|
|
9fee44b6fd | ||
|
|
56b0774eb5 | ||
|
|
f91749c17f | ||
|
|
98a52a7559 | ||
|
|
49334fdb4c | ||
|
|
b081865c17 | ||
|
|
7863aa3f56 | ||
|
|
9a05bc9145 | ||
|
|
6d1c31066e | ||
|
|
59e117ad7c | ||
|
|
9ebe42830f | ||
|
|
be1d4be19e | ||
|
|
c0c154e895 | ||
|
|
a39558cac2 | ||
|
|
84c1e6806c | ||
|
|
65a8cb72cb | ||
|
|
a0c528d299 | ||
|
|
b4bac4ea17 | ||
|
|
b42b66bc8f | ||
|
|
4f934b5bf0 | ||
|
|
be3dbf920d | ||
|
|
49773cf84e | ||
|
|
6f4f89b0fb | ||
|
|
8dca771cca | ||
|
|
348f66c247 | ||
|
|
065a037234 | ||
|
|
82b3bad6a0 | ||
|
|
8ffd05496a | ||
|
|
e15f83f913 | ||
|
|
aedff383c6 | ||
|
|
942f9f93b4 | ||
|
|
d78f392625 | ||
|
|
4b41b34833 | ||
|
|
1bb18dfc46 | ||
|
|
24b4c31037 | ||
|
|
47bac8d2d9 | ||
|
|
4ee80fafea | ||
|
|
8a4c145048 | ||
|
|
9abe9a3a2c | ||
|
|
3167b67693 | ||
|
|
c88f32cea3 | ||
|
|
62b5f16fdb | ||
|
|
895774141e | ||
|
|
7720269bdc | ||
|
|
96129c6e31 | ||
|
|
22e81eb28a | ||
|
|
bb830de073 | ||
|
|
b3bc7a22c4 | ||
|
|
caf21632de | ||
|
|
192c922cbc | ||
|
|
ef8af52e53 | ||
|
|
45ba9ccc7a | ||
|
|
2deef73518 | ||
|
|
8193186dcd | ||
|
|
836947df64 | ||
|
|
00147fe136 | ||
|
|
203affee16 | ||
|
|
6a115c5b9b | ||
|
|
edcd9c6ffb | ||
|
|
599430d88a | ||
|
|
4874f93056 | ||
|
|
f207641021 | ||
|
|
d8664534e4 | ||
|
|
b60ab910d7 | ||
|
|
2ccef476ea | ||
|
|
0c3b2239c1 | ||
|
|
966d98c732 | ||
|
|
55b9e629cd | ||
|
|
914eff9a1f | ||
|
|
43f8d0e623 | ||
|
|
d8a223e360 | ||
|
|
c75d1a66c5 | ||
|
|
2ca0df3f40 | ||
|
|
c92f7c9955 | ||
|
|
9161338c9f | ||
|
|
be84e7c384 | ||
|
|
2ba2117f2a | ||
|
|
21b0927c53 | ||
|
|
c3f43c899f | ||
|
|
d974a2ff1d | ||
|
|
57d94f82ed | ||
|
|
3200ebd799 | ||
|
|
2babd47866 | ||
|
|
a478fee735 | ||
|
|
6c05e98c6e | ||
|
|
283c53b343 | ||
|
|
25e5e0f38d | ||
|
|
cc8b1a6fc0 | ||
|
|
722997a64b | ||
|
|
bab030bf39 | ||
|
|
6fdec929f5 | ||
|
|
dc55a9e747 | ||
|
|
308801a465 | ||
|
|
e7b8c7a510 | ||
|
|
f57cea0164 | ||
|
|
559e5ab7fa | ||
|
|
136acd2b32 | ||
|
|
dd96cf4180 | ||
|
|
718b9991c1 | ||
|
|
c219086e7e | ||
|
|
80e8bbcda8 | ||
|
|
14a1403936 | ||
|
|
947682cf88 | ||
|
|
c0093bf58d | ||
|
|
1b320f1dd5 | ||
|
|
9ba24e16c3 | ||
|
|
4fd10a3fcc | ||
|
|
0bb84957f0 | ||
|
|
f83be684f6 | ||
|
|
eedbe38535 | ||
|
|
e95886f47d | ||
|
|
eaab50c8b2 | ||
|
|
40ab9dc95d | ||
|
|
17d45a0ea1 | ||
|
|
aee9586fd5 | ||
|
|
c94ee61690 | ||
| 86d0619e9e | |||
| 85e5ae4a27 | |||
|
|
df5b862b36 | ||
|
|
3333e9b343 | ||
|
|
265a1b91e6 | ||
|
|
4f5aeb4abb | ||
|
|
1cf28423bb | ||
|
|
831857418b | ||
|
|
8303af4e32 | ||
|
|
9651e0344d | ||
|
|
d2fef3a336 | ||
|
|
27bbaf83d2 | ||
|
|
d276510301 | ||
|
|
ebb09f2cf0 | ||
|
|
eeb48fa769 | ||
|
|
ae0dfd4cf4 | ||
|
|
dc6db2db8e | ||
|
|
027ffa19ca | ||
|
|
949b070f03 | ||
|
|
80c380ce7a | ||
|
|
d4529675f0 | ||
|
|
10569b34f8 | ||
|
|
1600a275be | ||
|
|
817d44a693 | ||
|
|
2e28867bc7 | ||
|
|
48e4753a2a | ||
|
|
5595fd5ad9 | ||
|
|
65a530b33b | ||
|
|
25730745b8 | ||
|
|
8350944f7a | ||
|
|
9dfcd9091b | ||
|
|
b0cf2fbe62 | ||
|
|
2812fa1f08 | ||
|
|
7cc14319ee | ||
|
|
9476a98b69 | ||
|
|
b393bd17b8 | ||
|
|
24fec9b4a7 | ||
|
|
5128d2b100 | ||
|
|
0830cc75e8 | ||
|
|
13da7ceafc | ||
|
|
ca1f6fccbe | ||
|
|
5984d5a475 | ||
|
|
7176f00b9d | ||
|
|
6ddcd52c20 | ||
|
|
5f91a82539 | ||
|
|
bd03bebf66 | ||
|
|
3e7800551a | ||
|
|
84e54bf4d7 | ||
|
|
2451d1ca29 | ||
|
|
bc1e059d32 | ||
|
|
9286e28acc | ||
|
|
fb90a96f65 | ||
|
|
f1761fa154 | ||
|
|
61a994023d | ||
|
|
e8deb61cad | ||
|
|
89b30a3830 | ||
|
|
48b46da333 | ||
|
|
d294481d5a | ||
|
|
f328d74b38 | ||
|
|
3af95bd88f | ||
|
|
8f9e334e0b | ||
|
|
f3848a6a65 | ||
|
|
bb49c91799 | ||
|
|
efeb2ac31d | ||
|
|
e1905cfccc | ||
|
|
c73f22ab60 | ||
|
|
8b6349c187 | ||
|
|
ced6ba0951 | ||
|
|
96adca6623 | ||
|
|
e0e5cbdae5 | ||
|
|
e754065a5d | ||
|
|
b3ced58e91 | ||
|
|
33f0594a6e | ||
|
|
263c155acb | ||
|
|
9da4fd8d2f | ||
|
|
5040922b5d | ||
|
|
fd6ef8aaa3 | ||
|
|
c172e726d4 | ||
|
|
beee8def03 | ||
|
|
df9b60c921 | ||
|
|
f250957e0f | ||
|
|
2867386ea1 | ||
|
|
f9e1bb21af | ||
|
|
090369c02e | ||
|
|
6310f7b494 | ||
|
|
97baf97d97 | ||
|
|
5eff50358a | ||
|
|
f102b2753c | ||
|
|
3dd5cf5910 | ||
|
|
dd9b616371 | ||
|
|
766a35d2f3 | ||
|
|
8cd0816719 | ||
|
|
d7c472372e | ||
|
|
a73dfb6527 | ||
|
|
0494432fa1 | ||
|
|
2176e32aec | ||
|
|
ff0ac93af1 | ||
|
|
a243efcd74 | ||
|
|
74212b0456 | ||
|
|
74c36d2691 | ||
|
|
2d20a2b5c7 | ||
|
|
b78d5c4ca2 | ||
|
|
a3b888c2c5 | ||
|
|
92ef9b145f | ||
|
|
31cb674994 | ||
|
|
618f83ba52 | ||
|
|
6bea930477 | ||
|
|
63f96ca426 | ||
|
|
302ff68ab6 | ||
|
|
c2fe05bd5d | ||
|
|
f03a46a0da | ||
|
|
7e7859c45e | ||
|
|
cbc471ac93 | ||
|
|
c06d648a04 | ||
|
|
c457f143b3 | ||
|
|
0901922618 | ||
|
|
a1a080b68e | ||
|
|
9baac98681 | ||
|
|
ad062f5355 | ||
|
|
3ab6fd6b21 | ||
|
|
6eaf2b37c9 | ||
|
|
37337b9611 | ||
|
|
bfdc340a77 | ||
|
|
bc6ec1e498 | ||
|
|
0d27fb7bd5 | ||
|
|
396d123b4f | ||
|
|
c705214b94 | ||
|
|
adbc9d83b2 | ||
|
|
59085a5b13 | ||
|
|
7dbfd75944 | ||
|
|
6c625c4592 | ||
|
|
2b948d7d35 | ||
|
|
979769669f | ||
|
|
9a9be62928 | ||
|
|
b21b94beca | ||
|
|
78796da29a | ||
|
|
f98f900550 | ||
|
|
5213725aeb | ||
|
|
648f0c8b18 | ||
|
|
65a96e5dfb | ||
|
|
03d3b5a581 | ||
|
|
e9225a2a2f | ||
|
|
e9f9a68c61 | ||
|
|
edd7949cf4 | ||
|
|
577823a804 | ||
|
|
07ae683b22 | ||
|
|
23165bd5d2 | ||
|
|
e11b4f4611 | ||
|
|
4bbf80c7a4 | ||
|
|
990101655e | ||
|
|
a47113288b | ||
|
|
64178e8bdf | ||
|
|
46c422aee5 | ||
|
|
6b327a830a | ||
|
|
6b4e3d4e5e | ||
|
|
b06bccd277 | ||
|
|
334eaef18e | ||
|
|
5e2c0e035e | ||
|
|
9a8abf0a60 | ||
|
|
0a435db932 | ||
|
|
10653b50c5 | ||
|
|
c5e0474fd6 | ||
|
|
5933a585cd | ||
|
|
714d618550 | ||
|
|
24341f5d1c | ||
|
|
16fa4f09ed | ||
|
|
7476e9a721 | ||
|
|
63f3fbadad | ||
|
|
5a75d81980 | ||
|
|
2f184ee50a | ||
|
|
7fccdd507b | ||
|
|
2c765f7547 | ||
|
|
8c2e0ab70f | ||
|
|
9b18e6c175 | ||
|
|
db8da30d67 | ||
|
|
07e21a6dec | ||
|
|
fc56434e55 | ||
|
|
c7ef385ba0 | ||
|
|
cb72da4031 | ||
|
|
6ce9c708dc | ||
|
|
7036c87d09 | ||
|
|
d02fc8f93b | ||
|
|
e7d6da9e1d | ||
|
|
c3dcae9427 | ||
|
|
2d008b822a | ||
|
|
f077bf4283 | ||
|
|
d5848e415c | ||
|
|
9d0d0f5e21 | ||
|
|
de5bff6892 | ||
|
|
43242124c0 | ||
|
|
2f02aef723 | ||
|
|
b5fe22f908 | ||
|
|
660c30602c | ||
|
|
b7e26a3843 | ||
|
|
a7315ffa36 | ||
|
|
c95ff61c20 | ||
|
|
69cead265b | ||
|
|
73cdbb1426 | ||
|
|
f2e9fef592 | ||
|
|
a4c1c1dc75 | ||
|
|
2a73940961 | ||
|
|
6a06a29e54 | ||
|
|
e8eac75f71 | ||
|
|
2d5c6c2090 | ||
|
|
5b8ee36a6e | ||
|
|
423185fbe5 | ||
|
|
d8d8445c3b | ||
|
|
b12901f0b8 | ||
|
|
3a17f3a5bb | ||
|
|
e951df82c6 | ||
|
|
35450fed80 | ||
|
|
51c7ca4581 | ||
|
|
c0f6c0f318 | ||
|
|
610187ad44 | ||
|
|
49a0132967 | ||
|
|
bb6ade2684 | ||
|
|
45a06c52cb | ||
|
|
29a656d505 | ||
|
|
ad87443232 | ||
|
|
6339d6c305 | ||
|
|
b9f8138ce4 | ||
|
|
c86619a391 | ||
|
|
1d335d80de | ||
|
|
1831f4803c | ||
|
|
c2a77313bf | ||
|
|
994fd3c18b | ||
|
|
955b271eb3 | ||
|
|
9214513cff | ||
|
|
2a19d7a4a7 | ||
|
|
e2b3637d9a | ||
|
|
4a3f6b114c | ||
|
|
18c27229e6 | ||
|
|
dac9a6b805 | ||
|
|
d0fb1bfd8d | ||
|
|
10b69be9c8 | ||
|
|
c276ffa0db | ||
|
|
46905fa513 | ||
|
|
44575685e9 | ||
|
|
28365d1a99 | ||
|
|
4ff61f9a39 | ||
|
|
d0b242e2ea | ||
|
|
9f7a64cbbe | ||
|
|
e7cc5c9932 | ||
|
|
38c5f63334 | ||
|
|
d103197d43 | ||
|
|
50fde3330d | ||
|
|
a7dc882512 | ||
|
|
7478be1de8 | ||
|
|
e2a42eac9b | ||
|
|
488e85bbaa | ||
|
|
c9a8bc7415 | ||
|
|
5a2505c4e3 | ||
|
|
e493f6d2f1 | ||
|
|
c7ce59312c | ||
|
|
5ba84e7e10 | ||
|
|
4c521ccbde | ||
|
|
53ef22f8e7 | ||
|
|
89581a69b4 | ||
|
|
57d5af6108 | ||
|
|
bf03d7cf19 | ||
|
|
41a6594f8a | ||
|
|
9fe8a0e29b | ||
|
|
44bedb490d | ||
|
|
b3cd42eead | ||
|
|
f007eceba6 | ||
|
|
f4527f4078 | ||
|
|
17ef6c5170 | ||
|
|
6a409d113b | ||
|
|
1d2c5e7cb3 | ||
|
|
fa903fe325 | ||
|
|
2b3349127d | ||
|
|
12a5356fa6 | ||
|
|
273aa3164f | ||
|
|
006fa482c9 | ||
|
|
cff7df7bb0 | ||
|
|
d43159df8e | ||
|
|
dd77bc44b9 | ||
|
|
9a3c23cb93 | ||
|
|
dceafe02da | ||
|
|
4c8e27b68f | ||
|
|
99513042d1 | ||
|
|
0085e0cb39 | ||
|
|
11f4ae8140 | ||
|
|
54d726f006 | ||
|
|
31ba7bfe14 | ||
|
|
d546e5a880 | ||
|
|
6cc34d2a6d | ||
|
|
09477a093e | ||
|
|
4bfb4666cd | ||
|
|
0012b7ed4f | ||
|
|
ed5deec4f4 | ||
|
|
92dffeba1d | ||
|
|
eba9e2c250 | ||
|
|
4b6a1a7172 | ||
|
|
76c7faa927 | ||
|
|
8c48c93e6d | ||
|
|
7c5aefe607 | ||
|
|
6191973f13 | ||
|
|
81fca6fb44 | ||
|
|
7f894c9cef | ||
|
|
c34535b638 | ||
|
|
6ad5157cdc | ||
|
|
4607c29b79 | ||
|
|
f9a0f52982 | ||
|
|
6c0d4755e2 | ||
|
|
7ddb256847 | ||
|
|
6c68fcabd5 | ||
|
|
2c3bb20bdd | ||
|
|
9e1624a25f | ||
|
|
1d018a2357 | ||
|
|
a8dc2f72df | ||
|
|
7fe320cded | ||
|
|
0eb5642742 | ||
|
|
3611481176 | ||
|
|
1f8ddd9121 | ||
|
|
59e27b0cee | ||
|
|
c1a523f84b | ||
|
|
6bb1f91bcc | ||
|
|
7d31cf9a70 | ||
|
|
4636417016 | ||
|
|
c22137d83b | ||
|
|
9ecc91077b | ||
|
|
c262cdf644 | ||
|
|
4c0f341523 | ||
|
|
670f536586 | ||
|
|
9887bd9a8c | ||
|
|
94bb3a14e7 | ||
|
|
21fc18b006 | ||
|
|
ac2e6f3964 | ||
|
|
780fca768e | ||
|
|
efc987d932 | ||
|
|
b67d3556cf | ||
|
|
846e548d2c | ||
|
|
5bb4e23773 | ||
|
|
a674ddd8d9 | ||
|
|
85e8a8c980 | ||
|
|
289ced8fbb | ||
|
|
6c26e35a23 | ||
|
|
4f1a7167cf | ||
|
|
4b196bf5be | ||
|
|
030bc04fa5 | ||
|
|
7c9d01071c | ||
|
|
b87d00bae4 | ||
|
|
9f208b9a9c | ||
|
|
18b54a0c07 | ||
|
|
91f2f223e4 | ||
|
|
f397526a8d | ||
|
|
c26586433e | ||
|
|
33c7ad037b | ||
|
|
8e589a4dd0 | ||
|
|
c14c7939b1 | ||
|
|
ded8d505fb | ||
|
|
3424bd2c6a | ||
|
|
a967777ce1 | ||
|
|
0d413b02fa | ||
|
|
818b21781d | ||
|
|
706d653c31 | ||
|
|
b5f0c2b724 | ||
|
|
821762be29 | ||
|
|
11f4265954 | ||
|
|
05b904919c | ||
|
|
78dc569b70 | ||
|
|
22f3112a37 | ||
|
|
9b28749d54 | ||
|
|
9a79890e9d | ||
|
|
e821a6a6db | ||
|
|
33cb580c06 | ||
|
|
32fc1b1193 | ||
|
|
c1abd8c810 | ||
|
|
84aacc5287 | ||
|
|
ee7620ff22 | ||
|
|
e96ede8614 | ||
|
|
42a8ac0dc9 | ||
|
|
10298bf1ee | ||
|
|
13339b1cfe | ||
|
|
9db497336d | ||
|
|
0f18f58f5d | ||
|
|
c504026fd9 | ||
|
|
467661c738 | ||
|
|
8d8ad8939e | ||
|
|
528aa3e9b8 | ||
|
|
44eb36a952 | ||
|
|
3e0f3fcaa7 | ||
|
|
e786ad4bdc | ||
|
|
6d871f85a0 | ||
|
|
2886cac6bc | ||
|
|
1ad9113e11 | ||
|
|
3f8d4b0b08 | ||
|
|
6aa5e34c63 | ||
|
|
bce0f97c1c | ||
|
|
0e759d05e5 | ||
|
|
d7a234e4af | ||
|
|
e45f461bfb | ||
|
|
d571f4b0dd | ||
|
|
a43aaad852 | ||
|
|
30129f3fe3 | ||
|
|
d4e2be2e42 | ||
|
|
77547b258f | ||
|
|
0e7e9ec818 | ||
|
|
d6b8097626 | ||
|
|
b4d94c7979 | ||
|
|
9339f35c11 | ||
|
|
4e5246cbda | ||
|
|
301a430666 | ||
|
|
86f18cc35f | ||
|
|
d5fa7c2a36 | ||
|
|
c84b67d67e | ||
|
|
f3d4a9e496 | ||
|
|
1400845af3 | ||
|
|
1eb31e2b92 | ||
|
|
09fd5e8762 | ||
|
|
24be6bcab3 | ||
|
|
aa2a2d4668 | ||
|
|
175b81d0fd | ||
|
|
97cb95647b | ||
|
|
b375c08422 | ||
|
|
398eb6ef78 | ||
|
|
0754010594 | ||
|
|
5dea4eea14 | ||
|
|
88ef2c9190 | ||
|
|
51850b93ed | ||
|
|
2c6337fa21 | ||
|
|
fcfc9e744d | ||
|
|
5ae442993e | ||
|
|
c595835777 | ||
|
|
eeed665278 | ||
|
|
120cbfff11 | ||
|
|
7b8489fa50 | ||
|
|
2843356057 | ||
|
|
7ed142c1a9 | ||
|
|
69e13203e6 | ||
|
|
0b2d728ae3 | ||
|
|
c82ee269cd | ||
|
|
5b3d26c061 | ||
|
|
9889a2ca29 | ||
|
|
73aeaee494 | ||
|
|
d63c7b8fcd | ||
|
|
20909edad8 | ||
|
|
f1914aad10 | ||
|
|
6fed882155 | ||
|
|
05936783de | ||
|
|
60ae59f801 | ||
|
|
e746693d93 | ||
|
|
65e4d2907f | ||
|
|
e3753dacca | ||
|
|
69883c0944 | ||
|
|
09627451a1 | ||
|
|
3a907781ca | ||
|
|
c60d5d6bfd | ||
|
|
2d75a94b24 | ||
|
|
d2e06c0231 | ||
|
|
1331f22052 | ||
|
|
3dc511f26b | ||
|
|
8de2b13d5f | ||
|
|
eeddcf214e | ||
|
|
5a2bb4aacd | ||
|
|
2af4dc7327 | ||
|
|
9b8bc1c240 | ||
|
|
aeee9731cd | ||
|
|
7a6f3b20d7 | ||
|
|
930c3908e1 | ||
|
|
4974568f5a | ||
|
|
9581139b91 | ||
|
|
d7525a0bae | ||
|
|
e11c25444c | ||
|
|
ef3f7ff68b | ||
|
|
9969299821 | ||
|
|
464783d2ff | ||
|
|
f3aaacae0a | ||
|
|
8e44870cbf | ||
|
|
b3e86e8e63 | ||
|
|
55400e0b9e | ||
|
|
9bbcfbe1dc | ||
|
|
d248870393 | ||
|
|
41fc7ba11e | ||
|
|
5c5a34aab7 | ||
|
|
e44a4d854e | ||
|
|
bc2ac8bed1 | ||
|
|
b87b12f548 | ||
|
|
895a17a46b | ||
|
|
5231be8236 | ||
|
|
a441c28bf5 | ||
|
|
90d441d02f | ||
|
|
63b9692adb | ||
|
|
35eddc42a6 | ||
|
|
468ffffe88 | ||
|
|
51db0eee9f | ||
|
|
0aa369db48 | ||
|
|
dae0d38364 | ||
|
|
b524dcc890 | ||
|
|
fbc3c7ec8c | ||
|
|
48a1b0d210 | ||
|
|
5534fe5fb6 | ||
|
|
051539f936 | ||
|
|
f35d9d69ed | ||
|
|
882d8eee59 | ||
|
|
18f9feb2de | ||
|
|
ddd9258a20 | ||
|
|
1d894b763e | ||
|
|
489c6b36d2 | ||
|
|
a4b956c963 | ||
|
|
9861e3edc5 | ||
|
|
e55d4dfd4f | ||
|
|
472508634a | ||
|
|
b38a5a7520 | ||
|
|
6cd3be8dba | ||
|
|
b14c41722f | ||
|
|
9dbb64073a | ||
|
|
e99af06e67 | ||
|
|
a1201f8fc9 | ||
|
|
922b3ab1d2 | ||
|
|
24505a930d | ||
|
|
a7b790f37c | ||
|
|
7bc76205eb | ||
|
|
948cabcf52 | ||
|
|
9f4786de45 | ||
|
|
6668ce23c7 | ||
|
|
14de70f911 | ||
|
|
d1c0a06730 | ||
|
|
ee5f58f6f9 | ||
|
|
143d3dc858 | ||
|
|
e092178d32 | ||
|
|
cceb2db107 | ||
|
|
59d71369a9 | ||
|
|
2d3ccf1878 | ||
|
|
6f27c9b395 | ||
|
|
bc20c5a1a7 | ||
|
|
67a8509ec4 | ||
|
|
a57e665cc7 | ||
|
|
fe68ba1dac | ||
|
|
952c912dbf | ||
|
|
032d106d89 | ||
|
|
bd23a4d42a | ||
|
|
37440aa104 | ||
|
|
b18672e92d | ||
|
|
c8a1d09ba4 | ||
|
|
99cac55563 | ||
|
|
b29bdba37f | ||
|
|
89c4769b69 | ||
|
|
ab54bbba0e | ||
|
|
2fab08a747 | ||
|
|
f7281ee9a9 | ||
|
|
eaff3970a0 | ||
|
|
bc299677ad | ||
|
|
17dfe9e9df | ||
|
|
2bc8c04bc6 | ||
|
|
961245c883 | ||
|
|
dda8b5c209 | ||
|
|
c8678143c1 | ||
|
|
68b6324365 | ||
|
|
5190e42002 | ||
|
|
1d048d11f3 | ||
|
|
18e6a0f6be | ||
|
|
fa0a934737 | ||
|
|
d528a9ec08 | ||
|
|
41a96433d9 | ||
|
|
1a21344d89 | ||
|
|
06c0dece69 | ||
|
|
03a0294e9c | ||
|
|
30f59387e4 | ||
|
|
078bdedfa9 | ||
|
|
83cf5d536b | ||
|
|
688710fb1c | ||
|
|
1dd3d024ac | ||
|
|
6b84c1658e | ||
|
|
c7bc1abe3c | ||
|
|
df4b2ad904 | ||
|
|
e15e3ea14b | ||
|
|
468b238555 | ||
|
|
8060bc5c85 | ||
|
|
a8fac9e339 | ||
|
|
e4e114e9d4 | ||
|
|
c09b5f0d8a | ||
|
|
74b84bd21f | ||
|
|
8c1bbd795a | ||
|
|
2776f7ee0a | ||
|
|
60b9a5f215 | ||
|
|
4dd08d5255 | ||
|
|
5f5acb4063 | ||
|
|
61a271b297 | ||
|
|
6d6fc074ad | ||
|
|
a6b1a43a86 | ||
|
|
b572c36868 | ||
|
|
975c150a57 | ||
|
|
85781aa3dc | ||
|
|
74b033f785 | ||
|
|
5b1584fbe0 | ||
|
|
1738d535cb | ||
|
|
50ef7f89f9 | ||
|
|
6e9d746b40 | ||
|
|
7106636263 | ||
|
|
5ee7e6326c | ||
|
|
807f16107a | ||
|
|
0cb262dace | ||
|
|
88c7ce9f49 | ||
|
|
d192847ae9 | ||
|
|
c4061d4c2d | ||
|
|
f2fcb46f48 | ||
|
|
7c7542ba91 | ||
|
|
74cd4f6727 | ||
|
|
956600b68f | ||
|
|
a31aede139 | ||
|
|
9c9b450dc7 | ||
|
|
3b0af01f75 | ||
|
|
9a2ef79491 | ||
|
|
98d26c4c45 | ||
|
|
a888d04200 | ||
|
|
3148422d6f | ||
|
|
44b67ac9d4 | ||
|
|
86d99338ed | ||
|
|
b270f5e452 | ||
|
|
4f4414d4f3 | ||
|
|
50b1b8b31f | ||
|
|
0304a3aa29 | ||
|
|
35979a2e91 | ||
|
|
f8af185573 | ||
|
|
e2d447a56b | ||
|
|
0a8211dd5b | ||
|
|
e8ac03ce9c | ||
|
|
88195e2216 | ||
|
|
49a307744d | ||
|
|
fee78529dd | ||
|
|
756b904cb2 | ||
|
|
1441394923 | ||
|
|
65f3ac6330 | ||
|
|
e392777487 | ||
|
|
b0e8104334 | ||
|
|
4dfe19a9fb | ||
|
|
7076f09626 | ||
|
|
0a53f6b2b3 | ||
|
|
2ac8dcbdda | ||
|
|
c23948b5fa | ||
|
|
0fe256fc4e | ||
|
|
671d3a676c | ||
|
|
aad0c47ccf | ||
|
|
c1c4af82e6 | ||
|
|
42a60e8d04 | ||
|
|
4fe9db5189 | ||
|
|
71666ba57c | ||
|
|
08c3e7b43c | ||
|
|
3816a38538 | ||
|
|
4fcc832f9d | ||
|
|
bb3324e2c3 | ||
|
|
2ab506d2e4 | ||
|
|
eb731182fd | ||
|
|
ac6882ef5e | ||
|
|
a7b7a2aa3b | ||
|
|
afac53027c | ||
|
|
0ae9289386 | ||
|
|
3e592bcbf2 | ||
|
|
10b4f5cdc6 | ||
|
|
8f1694ee0d | ||
|
|
f55c28b4be | ||
|
|
de5c5f0c7f | ||
|
|
90d742771e | ||
|
|
afb842bdc2 | ||
|
|
bc85b2eb16 | ||
|
|
4906344045 | ||
|
|
6f300bd14f | ||
|
|
17c696597c | ||
|
|
de4b215bd4 | ||
|
|
aa99029c2a | ||
|
|
73c3eea254 | ||
|
|
4799c3c7c3 | ||
|
|
f7cdf1dd00 | ||
|
|
672d78ff0f | ||
|
|
4b562dc015 | ||
|
|
0567c6b063 | ||
|
|
67aada2e62 | ||
|
|
53569d3edc | ||
|
|
490028e6b2 | ||
|
|
75e8ee1422 | ||
|
|
372b4e707a | ||
|
|
eba64edbf3 | ||
|
|
51fe6e674f | ||
|
|
631c0d75ac | ||
|
|
a456e97681 | ||
|
|
a73a14f14f | ||
|
|
7e3037bd0c | ||
|
|
89c29c3b0c | ||
|
|
905f06a045 | ||
|
|
17895d4795 | ||
|
|
48d0738488 | ||
|
|
2fb6adb36f | ||
|
|
0fde5836c3 | ||
|
|
c40aa09330 | ||
|
|
cae95cddb0 | ||
|
|
e1457fd94c | ||
|
|
7e7082aa7e | ||
|
|
983b9f0832 | ||
|
|
408a51c2aa | ||
|
|
19b95ef72e | ||
|
|
4d84ea8764 | ||
|
|
481de6b1b6 | ||
|
|
a9abdb257d | ||
|
|
e776111d28 | ||
|
|
92c12c9a37 | ||
|
|
a2ff32ce31 | ||
|
|
cf236cb103 | ||
|
|
0505f67048 | ||
|
|
dfbfcb576e | ||
|
|
7c5072e086 | ||
|
|
63a6250bfb | ||
|
|
658c49c841 | ||
|
|
c818001bfb | ||
|
|
586b87916b | ||
|
|
d01dc10ade | ||
|
|
ddcf68f6d1 | ||
|
|
46076df528 | ||
|
|
31fa9cbb66 | ||
|
|
a25daae4a1 | ||
|
|
f26debfa1d | ||
|
|
919bd7fa63 | ||
|
|
f55afd8717 | ||
|
|
ac03c5edbf | ||
|
|
eeba4bef5a | ||
|
|
843a6a272c | ||
|
|
378084354d | ||
|
|
65359b76d5 | ||
|
|
22b7cc5f55 | ||
|
|
3df772df44 | ||
|
|
e7d06692fd | ||
|
|
35d4e813c4 | ||
|
|
852baa28da | ||
|
|
41937dde83 | ||
|
|
593716ee26 | ||
|
|
315bad7e0d | ||
|
|
4dc034cde9 | ||
|
|
d886b5191d | ||
|
|
223b9b3acc | ||
|
|
7871f8e82f | ||
|
|
c265e62062 | ||
|
|
3906afd51c | ||
|
|
1d73a484d9 | ||
|
|
702fa49cb5 | ||
|
|
378de2c3b3 | ||
|
|
56668169c6 | ||
|
|
eb5ccea857 | ||
|
|
05e727d091 | ||
|
|
54e03ac047 | ||
|
|
c96ecc37ac | ||
|
|
b829467ab1 | ||
|
|
4b7ac405c3 | ||
|
|
91219ebc03 | ||
|
|
cfad5bc3db | ||
|
|
d7304d4591 | ||
|
|
92827d1d01 | ||
|
|
03b951346b | ||
|
|
c3033b1e86 | ||
|
|
491f9c6c57 | ||
|
|
d2dd0812f5 | ||
|
|
ff6fa11432 | ||
|
|
1209a8d61d | ||
|
|
d17a8a122a | ||
|
|
bd2a84ce19 | ||
|
|
ee7b9cce08 | ||
|
|
c20d538cf8 | ||
|
|
f07db12d48 | ||
|
|
b083aa7fcb | ||
|
|
309549bc13 | ||
|
|
6dfa583ea0 | ||
|
|
0c66adb782 | ||
|
|
14584d9171 | ||
|
|
3f666ddb6b | ||
|
|
178a8ab4c4 | ||
|
|
19290bebbe | ||
|
|
83ae819b1a | ||
|
|
c80f85e43a | ||
|
|
1d1759265a | ||
|
|
e2f9e7ed38 | ||
|
|
93d16237ba | ||
|
|
fb42bb293e | ||
|
|
5d9ad35791 | ||
|
|
482e48304c | ||
|
|
2ceabfc367 | ||
|
|
1f2cc5172e | ||
|
|
8e7b4b56e1 | ||
|
|
92aba744ff | ||
|
|
688bd6e363 | ||
|
|
8abcd3502b | ||
|
|
0c312ecabc | ||
|
|
b53eca2d3e | ||
|
|
b1b4d34eca | ||
|
|
a1851188ad | ||
|
|
76996eca28 | ||
|
|
a4d222a84e | ||
|
|
9aae931af4 | ||
|
|
ed7e2b2c69 | ||
|
|
341afec0b7 | ||
|
|
17aecd365f | ||
|
|
91ac528f24 | ||
|
|
ceb6411038 | ||
|
|
ba1c3efcdb | ||
|
|
fabdf33a3a | ||
|
|
274b9c7cba | ||
|
|
0540488e2f | ||
|
|
360e274e60 | ||
|
|
7c2a8db309 | ||
|
|
235b2264ef | ||
|
|
53623954e7 | ||
|
|
a2081c1384 | ||
|
|
0cca12f938 | ||
|
|
116e440e8f | ||
|
|
2857b4fc22 | ||
|
|
8ff6bdd064 | ||
|
|
2552194dc1 | ||
|
|
34f4368bc7 | ||
|
|
30f92b5384 | ||
|
|
339829d73f | ||
|
|
de004ee832 | ||
|
|
d628da248d | ||
|
|
d308e894c6 | ||
|
|
6d3edda4bf | ||
|
|
b95515675b | ||
|
|
89ffc21a4c | ||
|
|
c7b25b9f01 | ||
|
|
2f5ecdf139 | ||
|
|
c87a3c309a | ||
|
|
2a36bb6896 | ||
|
|
2a03e35f24 | ||
|
|
49c2113a0a | ||
|
|
5e15691604 | ||
|
|
611fe395ff | ||
|
|
7697e188ce | ||
|
|
0ce55a7257 | ||
|
|
c6ae872232 | ||
|
|
6af6f4dcd5 | ||
|
|
a062f6a173 | ||
|
|
c07499770b | ||
|
|
833209bfbf | ||
|
|
ba519bd463 | ||
|
|
4aa9b19c99 | ||
|
|
e72e5ad83f | ||
|
|
dc2ef79fc0 | ||
|
|
afea334ca0 | ||
|
|
c246a94365 | ||
|
|
7c87c541f2 | ||
|
|
587c0aa864 | ||
|
|
d8c596515e | ||
|
|
55d1b84059 | ||
|
|
6814b2ae6b | ||
|
|
686aead9f2 | ||
|
|
20098751ee | ||
|
|
443fb80d6b | ||
|
|
ef43ac99c5 | ||
|
|
7ac449e71e | ||
|
|
44d93ec198 | ||
|
|
294a0df50f | ||
|
|
621c9fbeb2 | ||
|
|
288304c536 | ||
|
|
dbdf8f862c | ||
|
|
4b5df9f680 | ||
|
|
b98ded125a | ||
|
|
62933c7ef6 | ||
|
|
b5363033d6 | ||
|
|
d0e511ff98 | ||
|
|
84016134f2 | ||
|
|
b23f597060 | ||
|
|
2c64ff131b | ||
|
|
b9bed1d6d8 | ||
|
|
e1b1795be2 | ||
|
|
96c499f108 | ||
|
|
dcff70b43b | ||
|
|
7f9c0e8812 | ||
|
|
4f41f766fe | ||
|
|
29248dae3b | ||
|
|
e3a135f337 | ||
|
|
5cafeb9a50 | ||
|
|
14ef7cb40a | ||
|
|
446aed8515 | ||
|
|
1a972a5b09 | ||
|
|
e827c53ebc | ||
|
|
ae84589963 | ||
|
|
81c11062f2 | ||
|
|
704fb336e6 | ||
|
|
7267473617 | ||
|
|
d11f13a0fd | ||
|
|
2a2bd56df4 | ||
|
|
78aa612a50 | ||
|
|
c6275b162f | ||
|
|
fe4073597e | ||
|
|
d5f8ab6909 | ||
|
|
29a15b55cd | ||
|
|
9da435d0af | ||
|
|
2e6aac79ff | ||
|
|
d1d8bbaeb6 | ||
|
|
f6c974f73e | ||
|
|
9aeaedb2d6 | ||
|
|
6b505c474e | ||
|
|
4977dd6e72 | ||
|
|
611b90e4c4 | ||
|
|
f251aab7f2 | ||
|
|
61a39bc973 | ||
|
|
25c5cfc39f | ||
|
|
e3be541ccd | ||
|
|
e3c09bed8d | ||
|
|
837e14ab0e | ||
|
|
0fb3d05d3e | ||
|
|
bf5fb8aea5 | ||
|
|
83ee99c1d1 | ||
|
|
2d8d668f4e | ||
|
|
170456ef76 | ||
|
|
1bf6ed058e | ||
|
|
2bc920719c | ||
|
|
3481d09177 | ||
|
|
d1438e11bf | ||
|
|
2981e57b9a | ||
|
|
c321ae5886 | ||
|
|
fb10cbb7d2 | ||
|
|
8559ccc4f3 | ||
|
|
2b81130e0a | ||
|
|
ae8a75a975 | ||
|
|
14d5bf3d78 | ||
|
|
3f9ab86fae | ||
|
|
d861e9b2ce | ||
|
|
4024f62a6c | ||
|
|
c844176703 | ||
|
|
17ae45e74c | ||
|
|
5e3c72b843 | ||
|
|
4c5e825990 | ||
|
|
c24f179edc | ||
|
|
df4a4e333c | ||
|
|
f505323837 | ||
|
|
b6f4138048 | ||
|
|
c4dd7832f8 | ||
|
|
5697f49bf1 | ||
|
|
06b9d035b1 | ||
|
|
dfb91baa09 | ||
|
|
e216a3b5ae | ||
|
|
0ad4efa6a6 | ||
|
|
9a725ed9c2 | ||
|
|
9dc7291c29 | ||
|
|
270eef92ef | ||
|
|
e58964633c | ||
|
|
b65e808972 | ||
|
|
13d2b1b883 | ||
|
|
37c188ffa7 | ||
|
|
db199feb00 | ||
|
|
ced8c4996e | ||
|
|
e65f6c9209 | ||
|
|
7279c48a10 | ||
|
|
14f3c29c04 | ||
|
|
f1eddbb839 | ||
|
|
5b155d0d9c | ||
|
|
1216c2d748 | ||
|
|
8600f85a8f | ||
|
|
29acc9232f | ||
|
|
fbc4f96976 | ||
|
|
7ebac81dba | ||
|
|
6e3b989a13 | ||
|
|
7c1c1b0045 | ||
|
|
0343b77b1e | ||
|
|
06a0332878 | ||
|
|
18ebaa41c4 | ||
|
|
910e83ea4b | ||
|
|
b2c03d6956 | ||
|
|
433b980c52 | ||
|
|
a500b2631b | ||
|
|
56879c4d64 | ||
|
|
5c825f44df | ||
|
|
e80007e3ea | ||
|
|
309bbfdb62 | ||
|
|
20bc619947 | ||
|
|
9b3cad6488 | ||
|
|
853814df00 | ||
|
|
a0b0e31d5c | ||
|
|
360d8a5220 | ||
|
|
5772bdcd1e | ||
|
|
c43039abca | ||
|
|
1cd87fb87c | ||
|
|
a75ed0f33c | ||
|
|
14f7fc7828 | ||
|
|
89417e6f6d | ||
|
|
f442644bdd | ||
|
|
f8c86c25d4 | ||
|
|
32baa0a091 | ||
|
|
fb607a3c41 | ||
|
|
4057f8105e | ||
|
|
9b84048fe9 | ||
|
|
ed410ebb7f | ||
|
|
610b767814 | ||
|
|
c4d46326ad | ||
|
|
493e9ccc64 | ||
|
|
bac4c55835 | ||
|
|
bf35e6a26d | ||
|
|
c9d95b5edd | ||
|
|
bf68f22bac | ||
|
|
5de1be8b54 | ||
|
|
a33fa55f8c | ||
|
|
f9ff953e0a | ||
|
|
6235597ba6 | ||
|
|
5a7e7a0ab7 | ||
|
|
625b5a5cbd | ||
|
|
74c5171972 | ||
|
|
1ff8565566 | ||
|
|
807e2a69f1 | ||
|
|
95b34af3b7 | ||
|
|
37afeaaa04 | ||
|
|
60f61435bb | ||
|
|
2ed0f94f2f | ||
|
|
cc8c1a5a30 | ||
|
|
1f7a272aff | ||
|
|
a3a86a3d16 | ||
|
|
5a3ecfad93 | ||
|
|
bbc8763e76 | ||
|
|
2464e1d803 | ||
|
|
7ef72424bb | ||
|
|
4344e06558 | ||
|
|
f56ce72034 | ||
|
|
ae5dd3abde | ||
|
|
22a05e2cef | ||
|
|
deb0e60a06 | ||
|
|
03a32aa3d6 | ||
|
|
41acd31fec | ||
|
|
7e7f5ef5fa | ||
|
|
a06620e34b | ||
|
|
952f06f73d | ||
|
|
3838cf2ebf | ||
|
|
e3cc92bde9 | ||
|
|
0eafe25fa2 | ||
|
|
bbf2849a19 | ||
|
|
4ff352b5c1 | ||
|
|
fcc08de485 | ||
|
|
d9f6f165f9 | ||
|
|
a7d1ef9e70 | ||
|
|
d6021c6f28 | ||
|
|
cf9c58799c | ||
|
|
8ad648c194 | ||
|
|
1a6d1959c4 | ||
|
|
7a9b7c5a35 | ||
|
|
32a4b83fa9 | ||
|
|
79097e11df | ||
|
|
8b1ddf6b89 | ||
|
|
c4ac98380a | ||
|
|
e613558f25 | ||
|
|
ca15bf10bb | ||
|
|
4138eed6a2 | ||
|
|
03d53ddc49 | ||
|
|
bf5d742af0 | ||
|
|
3e0d1a4e31 | ||
|
|
a90b4af799 | ||
|
|
027d546151 | ||
|
|
1218e2077c | ||
|
|
8c981d71b0 | ||
|
|
5ce7436e1d | ||
|
|
f6a1edea5b | ||
|
|
126b8679fe | ||
|
|
007fdd7342 | ||
|
|
78bb668fad | ||
|
|
ccdc532142 | ||
|
|
a3e80c306c | ||
|
|
ccc536b83f | ||
|
|
af19dddc5a | ||
|
|
c3f387e5b5 | ||
|
|
7f2a3c5133 | ||
|
|
59d8c30d91 | ||
|
|
45e167dd5b | ||
|
|
742ee01346 | ||
|
|
18b17e846b | ||
|
|
7d82d5ad34 | ||
|
|
b4be7c3ad7 | ||
|
|
4a41424c73 | ||
|
|
c659732c5d | ||
|
|
6ce886212f | ||
|
|
edb3e78650 | ||
|
|
3359662363 | ||
|
|
b586a93722 | ||
|
|
31c746f639 | ||
|
|
f7d1abc91b | ||
|
|
18af6c92f3 | ||
|
|
2b9045b8f4 | ||
|
|
8a4bf159f8 | ||
|
|
b186b7f551 | ||
|
|
5a38f81a4a | ||
|
|
2c81655f97 | ||
|
|
615acd6363 | ||
|
|
539afbd153 | ||
|
|
e2b67fd1cb | ||
|
|
24b2247a1f | ||
|
|
a561368cf4 | ||
|
|
3de4615719 | ||
|
|
8434c19887 | ||
|
|
ef5a6161d3 | ||
|
|
aea7a0eb1e | ||
|
|
29cd7f3952 | ||
|
|
1a954ad675 | ||
|
|
6d66d1ec35 | ||
|
|
eda0d50636 | ||
|
|
37cf01e182 | ||
|
|
01797b9932 | ||
|
|
fd6fdd3960 | ||
|
|
4f2c857bbf | ||
|
|
786ac3f365 | ||
|
|
d3966a8e29 | ||
|
|
d70431691b | ||
|
|
0e9c2fffb5 | ||
|
|
2c9bfdac17 | ||
|
|
4c8a182300 | ||
|
|
9a2fbeacb8 | ||
|
|
608b0b0c41 | ||
|
|
ef6bccc543 | ||
|
|
f6bef97830 | ||
|
|
5feafb676e | ||
|
|
84de6377eb | ||
|
|
a2396a4876 | ||
|
|
cce7839324 | ||
|
|
d1d592c633 | ||
|
|
6a6a6e43d6 | ||
|
|
5efd085da5 | ||
|
|
8c5f5cf858 | ||
|
|
e3747c81f5 | ||
|
|
269b7fa710 | ||
|
|
c4ce270e1a | ||
|
|
b6ffa0f01f | ||
|
|
8f6a6bf47d | ||
|
|
55189e1693 | ||
|
|
04acffa985 | ||
|
|
e456ee1be9 | ||
|
|
1d78471933 | ||
|
|
85ab238067 | ||
|
|
c798070d12 | ||
|
|
e9de98e123 | ||
|
|
33ac4db9ba | ||
|
|
a3f06b2e7f | ||
|
|
83bcc38735 | ||
|
|
da778f7b85 | ||
|
|
d26bd44af7 | ||
|
|
55383ff5fc | ||
|
|
d9ad96249b | ||
|
|
6a41d536fa | ||
|
|
598e78bba7 | ||
|
|
ff1dfebd86 | ||
|
|
e3c422c5a3 | ||
|
|
0210024dc4 | ||
|
|
68e9c5571c | ||
|
|
fa9215fe5b | ||
|
|
0332b25ea0 | ||
|
|
5f343c493b | ||
|
|
9b3beb0dc0 | ||
|
|
ccac6319a1 | ||
|
|
f71a758cc0 | ||
|
|
637f6ee7ac | ||
|
|
54aeccc534 | ||
|
|
7eea91324d | ||
|
|
a2313e4b19 | ||
|
|
d5b94fdbd2 | ||
|
|
d48952079b | ||
|
|
fd77a3703c | ||
|
|
5fee02bfcd | ||
|
|
25671ad532 | ||
|
|
35d3330f9d | ||
|
|
947750c5c9 | ||
|
|
1765620899 | ||
|
|
a48e9d13ab | ||
|
|
d2e6dd6bf3 | ||
|
|
382ef05884 | ||
|
|
4a7f691525 | ||
|
|
92f0cca62d | ||
|
|
fd7057525e | ||
|
|
bd59cc18a7 | ||
|
|
49d0903a2d | ||
|
|
829e1d76c2 | ||
|
|
95a7766507 | ||
|
|
68626a8cfd | ||
|
|
17dba6007b | ||
|
|
1f3164832d | ||
|
|
e5082bbfe7 | ||
|
|
2d1aa60e1c | ||
|
|
2840dec1b7 | ||
|
|
4f5c1a8f2b | ||
|
|
3e41f86386 | ||
|
|
af30593ce4 | ||
|
|
165da4d980 | ||
|
|
5c678d1117 | ||
|
|
4d313aea76 | ||
|
|
d9059263ee | ||
|
|
c7d87be485 | ||
|
|
ed28a26a6b | ||
|
|
d3a71dc6fb | ||
|
|
6555557534 | ||
|
|
f1dc696967 | ||
|
|
5f96b68e5e | ||
|
|
e150bf5f59 | ||
|
|
ee27ffdeef | ||
|
|
cf22855307 | ||
|
|
5ad8dc6ee0 | ||
|
|
9f80450e0c | ||
|
|
bccb99e580 | ||
|
|
5927b8b05d | ||
|
|
1ad60d560f | ||
|
|
fd336262f7 | ||
|
|
682e8d2947 | ||
|
|
ab078d7fd9 | ||
|
|
a216e42922 | ||
|
|
edff9daa62 | ||
|
|
a907462a0a | ||
|
|
92e28b4176 | ||
|
|
f881f7c7b6 | ||
|
|
05b9b6733d | ||
|
|
760269db13 | ||
|
|
2eb6455122 | ||
|
|
e1cdb85d3f | ||
|
|
7b4649b430 | ||
|
|
309d47cb5b | ||
|
|
12ab1035ee | ||
|
|
f177221c7e | ||
|
|
edbbbf770c | ||
|
|
7c4e82b623 | ||
|
|
cfadba7ad3 | ||
|
|
0c72be5d8e | ||
|
|
10dc638f1a | ||
|
|
14681aec1e | ||
|
|
f3d1635c6c | ||
|
|
d9a16fa54b | ||
|
|
5c7a5522d4 | ||
|
|
c2cf1ce0ef | ||
|
|
92f4a59e17 | ||
|
|
a96784dbfb | ||
|
|
d69c31b773 | ||
|
|
caf63a3869 | ||
|
|
9e07b0b957 | ||
|
|
0bb42973ba | ||
|
|
3f8bf89836 | ||
|
|
a4b7beb735 | ||
|
|
6d1eb9d47f | ||
|
|
5a668e63cc | ||
|
|
01812799c4 | ||
|
|
ef6ce5d5e2 | ||
|
|
59cbdd8d4d | ||
|
|
df8452f7de | ||
|
|
680a7df34d | ||
|
|
5dd82a44df | ||
|
|
b4dfec99a2 | ||
|
|
4a4e4a69a9 | ||
|
|
a3258e9d1a | ||
|
|
72c29abdd4 | ||
|
|
6c171a107c | ||
|
|
4f89bc32d1 | ||
|
|
3de8b4ca4d | ||
|
|
633aef8f10 | ||
|
|
145deb5c70 | ||
|
|
aad5603c68 | ||
|
|
7dd5223dea | ||
|
|
e6e3afcca7 | ||
|
|
e1aa2ec029 | ||
|
|
bc3463501f | ||
|
|
f0d887bc0c | ||
|
|
28978f0143 | ||
|
|
1afb76de67 | ||
|
|
78010354bc | ||
|
|
360aed8743 | ||
|
|
b87260f34f | ||
|
|
ac19d53c8c | ||
|
|
edeca69ca9 | ||
|
|
a283490d08 | ||
|
|
3f0dbdcfed | ||
|
|
8836690b1a | ||
|
|
09277b1842 | ||
|
|
26ece732ff | ||
|
|
fb72d68235 | ||
|
|
513e176bf6 | ||
|
|
ffb12a0e6b | ||
|
|
c086f337a4 | ||
|
|
1483691937 | ||
|
|
42bbc6767c | ||
|
|
a5aa853f06 | ||
|
|
a06d1b6d5e | ||
|
|
a35c28b20f | ||
|
|
d9ed65840f | ||
|
|
15cba26b7b | ||
|
|
1097cbb60e | ||
|
|
72c4b6c06a | ||
|
|
b4b8eaecb0 | ||
|
|
83190dc848 | ||
|
|
97b59580ab | ||
|
|
609a74e559 | ||
|
|
2f68e749c7 | ||
|
|
069c104d09 | ||
|
|
57812bf484 | ||
|
|
d12e4edd08 | ||
|
|
088934adbd | ||
|
|
3405090597 | ||
|
|
8fcd186ed3 | ||
|
|
0f561dc394 | ||
|
|
c8c7dbf38e | ||
|
|
b06343c8bf | ||
|
|
2d0f12a9ff | ||
|
|
70db40b68d | ||
|
|
4aa8787fd8 | ||
|
|
8e71f3de18 | ||
|
|
b03f5ae055 | ||
|
|
871eb1f74f | ||
|
|
2502b821d4 | ||
|
|
eab8fa7311 | ||
|
|
65340be4da | ||
|
|
e4b5efd4eb | ||
|
|
ad02997ff7 | ||
|
|
66abf4c711 | ||
|
|
fd11b0cd83 | ||
|
|
0788bd8e79 | ||
|
|
e247aa69ba | ||
|
|
afeb65d616 | ||
|
|
bf210c0cdd | ||
|
|
5783cef8aa | ||
|
|
c092e2cd85 | ||
|
|
b9c15efec4 | ||
|
|
8eb3ef3488 | ||
|
|
b424457fff | ||
|
|
19b681ea97 | ||
|
|
2e2cd0686c | ||
|
|
28b097cfca | ||
|
|
ff125d53aa | ||
|
|
b04870c607 | ||
|
|
f2192d4825 | ||
|
|
22c70edcc4 | ||
|
|
97f4e1bc19 | ||
|
|
d4ffefce8a | ||
|
|
34ea3761f3 | ||
|
|
842b5e59bb | ||
|
|
126af8f857 | ||
|
|
ec97835313 | ||
|
|
6d54e23321 | ||
|
|
b25c14cb88 | ||
|
|
04d3483b06 | ||
|
|
4dd1ee8ecb | ||
|
|
a5c6193e29 | ||
|
|
7db1975e96 | ||
|
|
c3b062cfbf | ||
|
|
abf763e454 | ||
|
|
5088d49c0c | ||
|
|
a3849bb5b7 | ||
|
|
9793d1b274 | ||
|
|
f265cd4053 | ||
|
|
f917c96aa3 | ||
|
|
487c34e6a9 | ||
|
|
9e65eded68 | ||
|
|
cbff4eb618 | ||
|
|
9da28c7363 | ||
|
|
158adc8499 | ||
|
|
52db66616e | ||
|
|
ecc068f976 | ||
|
|
8bdf988a14 | ||
|
|
ace910eb62 | ||
|
|
047c24c151 | ||
|
|
c2740e87d9 | ||
|
|
750ad8fb9a | ||
|
|
e501c1beaf | ||
|
|
8d814257b2 | ||
|
|
118f93fb5a | ||
|
|
b2ac231af3 | ||
|
|
969f597557 | ||
|
|
f63794c9e1 | ||
|
|
bccf4b8d4f | ||
|
|
7808360d1c | ||
|
|
d296acfb94 | ||
|
|
d8f1e361d7 | ||
|
|
3a7d19e8a3 | ||
|
|
6d9a96d0ec | ||
|
|
f218f16781 | ||
|
|
833bc63cad | ||
|
|
5a0842eba7 | ||
|
|
908693fde5 | ||
|
|
9b86d634c5 | ||
|
|
a5a30c5148 | ||
|
|
26751d21f4 | ||
|
|
f0b9ea7385 | ||
|
|
aafa040327 | ||
|
|
869b4f2c35 | ||
|
|
fe57e8a76e | ||
|
|
2001383f0f | ||
|
|
a4d0874eda | ||
|
|
e68239c6ea | ||
|
|
d89375a7ce | ||
|
|
32988d0cee | ||
|
|
01c475ea95 | ||
|
|
b62b23562e | ||
|
|
5fd1522f17 | ||
|
|
9b7613f436 | ||
|
|
84a3e4b384 | ||
|
|
8113852ecc | ||
|
|
cbf15f6c49 | ||
|
|
cd48c4b81c | ||
|
|
6488daac1e | ||
|
|
5cd44c6526 | ||
|
|
4eb0730605 | ||
|
|
b4cb45389b | ||
|
|
0f2789b728 | ||
|
|
98ddab4f7b | ||
|
|
5199cfe947 | ||
|
|
3c97be837d | ||
|
|
70f07549f6 | ||
|
|
641e05cfd7 | ||
|
|
5d62f14378 | ||
|
|
f920a30389 | ||
|
|
c7e52925c1 | ||
|
|
0c140fa4c1 | ||
|
|
eaaa634e5a | ||
|
|
68478588b5 | ||
|
|
d3c943925c | ||
|
|
3cb9790d43 | ||
|
|
5bdfa981cd | ||
|
|
dc8f708cc2 | ||
|
|
8805d78dee | ||
|
|
aab7167e35 | ||
|
|
80392c74d5 | ||
|
|
b12c1b12c6 | ||
|
|
8180769021 | ||
|
|
2c0776d388 | ||
|
|
7fd07db556 | ||
|
|
01d9af671d | ||
|
|
bdb7c8a3f3 | ||
|
|
d37e8e8b4f | ||
|
|
7ff1c39297 | ||
|
|
9401aed189 | ||
|
|
a3f55fc57c | ||
|
|
c7d1488296 | ||
|
|
d5efb69678 | ||
|
|
4ba80a99a5 | ||
|
|
02822598c2 | ||
|
|
3fa1ed6222 | ||
|
|
1256ff79cd | ||
|
|
5d9108c646 | ||
|
|
396e46636a | ||
|
|
8573e20206 | ||
|
|
9b220dbc68 | ||
|
|
28fbbe1a45 | ||
|
|
cbc81f3c74 | ||
|
|
2887294071 | ||
|
|
ff16d1db79 | ||
|
|
d0938be8ab | ||
|
|
f101b715cf | ||
|
|
bbff9d2e4f | ||
|
|
f82b71332e | ||
|
|
4cda519218 | ||
|
|
24b826e688 | ||
|
|
9290236ae8 | ||
|
|
a2b6c89935 | ||
|
|
c2dae8e2bb | ||
|
|
cb6fa7fa74 | ||
|
|
cd156feba9 | ||
|
|
97f9e44e8a | ||
|
|
f6f8141ccf | ||
|
|
6ab1165cff | ||
|
|
433d79254d | ||
|
|
829af27f30 | ||
|
|
925ef2ffc4 | ||
|
|
5f0cf841ed | ||
|
|
85da153440 | ||
|
|
e114e56ab2 | ||
|
|
e7627e5904 | ||
|
|
1be5319436 | ||
|
|
b8de5a8a49 | ||
|
|
2de901a9c9 | ||
|
|
801850f1f7 | ||
|
|
1ddd2d7362 | ||
|
|
1aaeab99cc | ||
|
|
32cecd0e98 | ||
|
|
4d3d0fac2a | ||
|
|
c74bf0da82 | ||
|
|
bb2e4a6721 | ||
|
|
e1875b17da | ||
|
|
93a7689a94 | ||
|
|
380554ac2b | ||
|
|
90b6fcf597 | ||
|
|
f836b738f0 | ||
|
|
3156af3448 | ||
|
|
3681e9f7fa | ||
|
|
8abb7ffd13 | ||
|
|
bfc99196a8 | ||
|
|
6b9eb80be9 | ||
|
|
35bd646600 | ||
|
|
f4d4c04659 | ||
|
|
2322394a84 | ||
|
|
235ccab488 | ||
|
|
3933523142 | ||
|
|
d0d2d6c2df | ||
|
|
03dc9b724c | ||
|
|
da24bd128d | ||
|
|
652bbf42c8 | ||
|
|
f171cfc468 | ||
|
|
fd36e21197 | ||
|
|
f037b4434c | ||
|
|
c9a3febe47 | ||
|
|
c3b653a90a | ||
|
|
d954f37d4d | ||
|
|
c3e899d65a | ||
|
|
cf72ac3c8b | ||
|
|
49ac45a94a | ||
|
|
40fd3e6d2c | ||
|
|
0bc79ac9ba | ||
|
|
fdd6b879fb | ||
|
|
2b7720be38 | ||
|
|
bb373ef391 | ||
|
|
7b69b96a8a | ||
|
|
0e0a5db339 | ||
|
|
aa3dc4e6f1 | ||
|
|
dcf0cddf48 | ||
|
|
1e2fc44cf0 | ||
|
|
85b4b9a1a9 | ||
|
|
e1cd990c76 | ||
|
|
4a986546eb | ||
|
|
57da75ee0d | ||
|
|
bad35a0e0c | ||
|
|
34e21b209d | ||
|
|
233a0a9364 | ||
|
|
ebc4f888a8 | ||
|
|
916736b0fb | ||
|
|
be3ade4a69 | ||
|
|
d1f4cf9e75 | ||
|
|
54958becc1 | ||
|
|
5979dfb148 | ||
|
|
662b306ad7 | ||
|
|
1637a4215a | ||
|
|
d61decc182 | ||
|
|
b0576d0d55 | ||
|
|
8808a71f7c | ||
|
|
62b7ee89d7 | ||
|
|
9762d78148 | ||
|
|
3206ae2f92 | ||
|
|
744b8074e1 | ||
|
|
76ca18d261 | ||
|
|
cf37c22103 | ||
|
|
2984ac1ef0 | ||
|
|
4186800548 | ||
|
|
9e7de82c9c | ||
|
|
e1852e32c4 | ||
|
|
686416521a | ||
|
|
dc1829de5a | ||
|
|
2b018c4132 | ||
|
|
0315b531c8 | ||
|
|
c4b70f47d2 | ||
|
|
8ab2af4f1c | ||
|
|
ca819b108c | ||
|
|
3a1edc1237 | ||
|
|
bba63d28a5 | ||
|
|
0d679e9871 | ||
|
|
7584a2e689 | ||
|
|
f08be13855 | ||
|
|
673ba2f11b | ||
|
|
9ddfe8e284 | ||
|
|
cc1071a22a | ||
|
|
7c2d897f66 | ||
|
|
bcb1e07ff5 | ||
|
|
7f11756c97 | ||
|
|
72c61ec556 | ||
|
|
2cf7a0157e | ||
|
|
dd18d0e64d | ||
|
|
fbad28f76d | ||
|
|
1f080493be | ||
|
|
b23e804e29 | ||
|
|
46a31d79a5 | ||
|
|
658b005f61 | ||
|
|
b485bb7bec | ||
|
|
baed9d8c4b | ||
|
|
9d177646c7 | ||
|
|
d515dcc656 | ||
|
|
d583243da8 | ||
|
|
cb5eb09bba | ||
|
|
48035f22b6 | ||
|
|
5088f29456 | ||
|
|
53fcb9f57f | ||
|
|
3e44f00a25 | ||
|
|
278574a897 | ||
|
|
4fa27150dc | ||
|
|
bbefa6eeea | ||
|
|
123d90503d | ||
|
|
73ce8a77c3 | ||
|
|
c7199a3bc7 | ||
|
|
965293fc14 | ||
|
|
cba8a36aae | ||
|
|
b7e25130ce | ||
|
|
f1db21b302 | ||
|
|
5ef69f5f5d | ||
|
|
38312fc43b | ||
|
|
75fae9aa2d | ||
|
|
5199ed7df4 | ||
|
|
55dddcbb75 | ||
|
|
a7032ae943 | ||
|
|
4692e711aa | ||
|
|
64c0bc05ed | ||
|
|
bbcb8ec37c | ||
|
|
396f81cd58 | ||
|
|
ec81fb7947 | ||
|
|
fad889355b | ||
|
|
1601813062 | ||
|
|
8ad7ed8aaf | ||
|
|
55275eb390 | ||
|
|
b8e3c39c54 | ||
|
|
602afa385f | ||
|
|
100c2ca978 | ||
|
|
55a43504b6 | ||
|
|
b4eafb711f | ||
|
|
4bb5e12d2d | ||
|
|
d16d67dfc6 | ||
|
|
8e23dd4b1e | ||
|
|
506a9a8764 | ||
|
|
e211997a61 | ||
|
|
2ae5f3a793 | ||
|
|
0460b48bbf | ||
|
|
2b0bf4f7fe | ||
|
|
b8cb5ddff9 | ||
|
|
6b57bb3078 | ||
|
|
410377a578 | ||
|
|
520e91ff9d | ||
|
|
8631c0acc4 | ||
|
|
0e03ea65c5 | ||
|
|
8cf944ce80 | ||
|
|
2ea9a04503 | ||
|
|
f24f927a68 | ||
|
|
244e8c8473 | ||
|
|
382f59f545 | ||
|
|
51a9c62beb | ||
|
|
b9c49f75a5 | ||
|
|
777bdc6d93 | ||
|
|
4fc2e9c5df | ||
|
|
c160d89f17 | ||
|
|
e96431dbe0 | ||
|
|
b8f18712a9 | ||
|
|
bd1ae5558c | ||
|
|
bbf527d419 | ||
|
|
7e32707c8b | ||
|
|
dd8d91d021 | ||
|
|
2c57b36537 | ||
|
|
9861f7a774 | ||
|
|
9b8fc7e1dc | ||
|
|
16458454bd | ||
|
|
fe53668185 | ||
|
|
9c3be6bcc7 | ||
|
|
c30588b9ea | ||
|
|
b6837feb2c | ||
|
|
379d826b44 | ||
|
|
a6034b3535 | ||
|
|
871e88d1e5 | ||
|
|
66ba2b5e82 | ||
|
|
3426100635 | ||
|
|
d20d77c8ec | ||
|
|
150ec0701c | ||
|
|
29946b79d9 | ||
|
|
a765af69ee | ||
|
|
768d187ba6 | ||
|
|
5a76c726c4 | ||
|
|
5dd72f7b2d | ||
|
|
64f8ebd43f | ||
|
|
ac20216437 | ||
|
|
adf90f21e0 | ||
|
|
5f59b7bdd9 | ||
|
|
a9e9d30308 | ||
|
|
a41052cd9c | ||
|
|
10d66dda21 | ||
|
|
7580a79422 | ||
|
|
d9f8d2f4bb | ||
|
|
00553e32e8 | ||
|
|
5a95250bcd | ||
|
|
793669a976 | ||
|
|
dab6ba84d2 | ||
|
|
a3d169d2f0 | ||
|
|
d25ee35268 | ||
|
|
c887a0a14a | ||
|
|
1132be64dc | ||
|
|
67f4bddc4c | ||
|
|
50759aec9f | ||
|
|
e05f313c1a | ||
|
|
74e4ca6479 | ||
|
|
d2c6d02b82 | ||
|
|
3c05d41246 | ||
|
|
8c7806bf3d | ||
|
|
cc9ac79e45 | ||
|
|
4737c354e4 | ||
|
|
1c1784943e | ||
|
|
47c2cd12fe | ||
|
|
25461b7f8f | ||
|
|
2dbd9d542b | ||
|
|
61252f4527 | ||
|
|
4c05c1a7b2 | ||
|
|
f78f323db2 | ||
|
|
3f9d251990 | ||
|
|
f5f93381ab | ||
|
|
1d56ce77f7 | ||
|
|
1482ff8cee | ||
|
|
54438022ff | ||
|
|
0ff054afed | ||
|
|
cbe94c7916 | ||
|
|
3fa46c9afd | ||
|
|
fac92a6c7a | ||
|
|
bd361fa881 | ||
|
|
eb950f11bf | ||
|
|
accb629e14 | ||
|
|
5f791290ca | ||
|
|
fb9992e616 | ||
|
|
6f848954d1 | ||
|
|
0b36b4b81f | ||
|
|
49ad561d54 | ||
|
|
1133684e3b | ||
|
|
8f746dcfea | ||
|
|
602f088dba | ||
|
|
208104c751 | ||
|
|
d84c7679b7 | ||
|
|
1932dbf8a8 | ||
|
|
2ab79d949a | ||
|
|
cc96feb587 | ||
|
|
60baba6bde | ||
|
|
078327e8d5 | ||
|
|
f2f7e511a3 | ||
|
|
2d86b6a928 | ||
|
|
82a4e58c08 | ||
|
|
be58e21519 | ||
|
|
c9263befb3 | ||
|
|
1affa3afbb | ||
|
|
32506c47d4 | ||
|
|
6aa221391a | ||
|
|
81d8f3e421 | ||
|
|
49c149c531 | ||
|
|
9b62c93016 | ||
|
|
20936ca4c8 | ||
|
|
845c83bb09 | ||
|
|
52b0778d59 | ||
|
|
20fcc857d5 | ||
|
|
d807f7f51c | ||
|
|
045d54844f | ||
|
|
99532b7aec |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -2,7 +2,6 @@
|
||||
|
||||
jx-callback
|
||||
*.tmp
|
||||
swagger/
|
||||
debug
|
||||
.DS_Store
|
||||
*.log
|
||||
@@ -15,3 +14,4 @@ param_parser.go
|
||||
*.exe
|
||||
*.exe~
|
||||
.vscode
|
||||
.idea
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -276,7 +277,7 @@ func LoginInternal(ctx *Context, authType, authID, authIDType, authSecret string
|
||||
//如果是小程序
|
||||
if authType == "weixinmini" || authType == "weixinapp" {
|
||||
appID := strings.Split(authSecret, ",")[0]
|
||||
if appID == "wx08a5c2a8581414ff" || appID == "wx2d6949f724b2541d" || appID == "wx18111a41fd17f24f" { //菜市或者果园
|
||||
if appID == "wxa4a76d7b4c88604e" || appID == "wx2d6949f724b2541d" || appID == "wx18111a41fd17f24f" { //菜市或者果园
|
||||
if user != nil {
|
||||
binds, err := dao.GetUserBindAuthInfo(dao.GetDB(), user.GetID(), 0, nil, "", "", "wx2bb99eb5d2c9b82c")
|
||||
if err != nil {
|
||||
@@ -339,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 {
|
||||
@@ -475,3 +488,16 @@ func DeletedTokenInfoWithoutParam(authInfo *AuthInfo) (err error) {
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func CheckWeixinminiAuthBind(userID string) (err error) {
|
||||
var (
|
||||
db = dao.GetDB()
|
||||
)
|
||||
authBinds, err := dao.GetUserBindAuthInfo(db, userID, model.AuthBindTypeAuth, []string{"weixinmini", "weixinapp"}, "", "", "")
|
||||
if len(authBinds) == 0 {
|
||||
return fmt.Errorf("请绑定微信认证方式!")
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package mobile
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/auth2"
|
||||
@@ -44,7 +45,9 @@ func init() {
|
||||
|
||||
// 特殊接口
|
||||
func (a *Auther) SendVerifyCode(mobileNumber string) (verifyCode string, err error) {
|
||||
verifyCode = a.GenerateVerifyCode(mobileNumber)
|
||||
verifyCode = fmt.Sprintf("%06d", rand.Intn(1000000))
|
||||
globals.SugarLogger.Debugf("SendVerifyCode code: %v", verifyCode)
|
||||
// a.GenerateVerifyCode(mobileNumber)
|
||||
smsClient := aliyunsmsclient.New("http://dysmsapi.aliyuncs.com/")
|
||||
response, err := smsClient.Execute(globals.AliKey, globals.AliSecret, mobileNumber, globals.SMSSignName, globals.SMSMobileVerifyTemplate, string(utils.MustMarshal(map[string]interface{}{
|
||||
"code": verifyCode,
|
||||
@@ -69,11 +72,12 @@ func (a *Auther) SendVerifyCode(mobileNumber string) (verifyCode string, err err
|
||||
|
||||
func (a *Auther) VerifySecret(mobileNumber, code string) (authBindEx *auth2.AuthBindEx, err error) {
|
||||
globals.SugarLogger.Debugf("VerifySecret mobileNumber:%s, code:%s", mobileNumber, code)
|
||||
|
||||
def := &authprovider.DefAuther{}
|
||||
err = ErrVerifyCodeIsWrong
|
||||
if (code == auth2.InternalAuthSecret ||
|
||||
auth2.TestMobileMap[mobileNumber] == 1 && code == TestVerifyCode) ||
|
||||
a.VerifyCode(mobileNumber, code) {
|
||||
savedVerifyCode := def.LoadVerifyCode(mobileNumber)
|
||||
if code == auth2.InternalAuthSecret ||
|
||||
auth2.TestMobileMap[mobileNumber] == 1 && code == TestVerifyCode || (code != "" && savedVerifyCode != "" && code == savedVerifyCode) {
|
||||
// || a.VerifyCode(mobileNumber, code)
|
||||
err = nil
|
||||
}
|
||||
return nil, err
|
||||
|
||||
@@ -2,7 +2,6 @@ package weixin
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/weixinapi"
|
||||
@@ -57,13 +56,13 @@ func (a *MiniAuther) DecryptData(authInfo *auth2.AuthInfo, jsCode, encryptedData
|
||||
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
|
||||
}
|
||||
// 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
|
||||
@@ -79,7 +78,7 @@ func (a *MiniAuther) DecryptData(authInfo *auth2.AuthInfo, jsCode, encryptedData
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
authInfo.AuthBindInfo.UserData = sessionKey
|
||||
// authInfo.AuthBindInfo.UserData = sessionKey
|
||||
return string(decryptedData), nil
|
||||
}
|
||||
|
||||
@@ -89,9 +88,6 @@ func (a *MiniAuther) GetUserType() (userType int8) {
|
||||
|
||||
func getWxApp(appID string) (miniApi *weixinapi.API) {
|
||||
miniApi = api.WeixinMiniAPI
|
||||
if len(appID) > 0 && appID == api.WeixinMiniAppID2 {
|
||||
miniApi = api.WeixinMiniAPI2
|
||||
}
|
||||
return miniApi
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ package casbinauth
|
||||
import (
|
||||
jxmodel "git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"github.com/astaxie/beego/orm"
|
||||
"github.com/astaxie/beego/client/orm"
|
||||
"github.com/casbin/casbin/model"
|
||||
"github.com/casbin/casbin/persist"
|
||||
)
|
||||
|
||||
@@ -1,128 +0,0 @@
|
||||
package cs
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/baseapi/platformapi/weimobapi"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/authz/autils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxstore/cms"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
)
|
||||
|
||||
const (
|
||||
minCSOrderPayment = 0 // 供货订单的最小金额(单位为元)
|
||||
maxUnitPrice = 3000 // 为防止误填单价,限制单价最高(单位为分)
|
||||
)
|
||||
|
||||
func OnCallbackMsg(msg *weimobapi.CallbackMsg) (response *weimobapi.CallbackResponse) {
|
||||
orderID := utils.Int64ToStr(msg.OrderNo)
|
||||
jxutils.CallMsgHandler(func() {
|
||||
response = onOrderMsg(msg)
|
||||
}, jxutils.ComposeUniversalOrderID(orderID, model.VendorIDWSC))
|
||||
return response
|
||||
}
|
||||
|
||||
func onOrderMsg(msg *weimobapi.CallbackMsg) (response *weimobapi.CallbackResponse) {
|
||||
globals.SugarLogger.Debugf("onOrderMsg:%s", utils.Format4Output(msg, true))
|
||||
if msg.Event == weimobapi.MsgEventOrderStatusChange {
|
||||
if utils.ForceInterface2Int64(msg.MsgBody["orderStatus"]) == weimobapi.MsgOrderStatusFinished {
|
||||
if orderDetail, err := api.WeimobAPI.QueryOrderDetail2(msg.OrderNo, false); err == nil {
|
||||
if orderDetail.OrderStatus == weimobapi.OrderStatusFinished && orderDetail.PaymentAmount >= minCSOrderPayment {
|
||||
changeStoreSkusByOrder(orderDetail)
|
||||
}
|
||||
} else {
|
||||
globals.SugarLogger.Debugf("onOrderMsg order:%s failed with err:%v", msg.OrderNo, err)
|
||||
response = weimobapi.Err2CallbackResponse(err, "")
|
||||
}
|
||||
}
|
||||
}
|
||||
return response
|
||||
}
|
||||
|
||||
func changeStoreSkusByOrder(order *weimobapi.OrderDetail) {
|
||||
globals.SugarLogger.Debugf("changeStoreSkusByOrder order:%s", utils.Format4Output(order, true))
|
||||
receiverMobile := order.DeliveryDetail.LogisticsDeliveryDetail.ReceiverMobile
|
||||
ctx := jxcontext.NewWithUserName(nil, utils.LimitStringLen(utils.Int64ToStr(order.OrderNo), 32), nil, nil)
|
||||
if storeList, err := GetStoreList4Mobile(dao.GetDB(), []string{receiverMobile}); err == nil {
|
||||
if len(storeList) >= 1 {
|
||||
var skuBindInfos []*cms.StoreSkuBindInfo
|
||||
storeID := storeList[0].ID
|
||||
globals.SugarLogger.Debugf("changeStoreSkusByOrder storeID:%d", storeID)
|
||||
for _, v := range order.ItemList {
|
||||
nameID := int(utils.Str2Int64WithDefault(v.SkuCode, 0))
|
||||
unitPrice := v.CostPrice
|
||||
if nameID > 0 && (unitPrice > 0 && unitPrice < maxUnitPrice) {
|
||||
skuBindInfos = append(skuBindInfos, &cms.StoreSkuBindInfo{
|
||||
StoreID: storeID,
|
||||
NameID: nameID,
|
||||
UnitPrice: int(jxutils.StandardPrice2Int(unitPrice)),
|
||||
IsFocus: 1,
|
||||
IsSale: 1,
|
||||
})
|
||||
} else {
|
||||
globals.SugarLogger.Infof("[运营],微商城订单:%d,商品:%s没有设置正确的SkuName编码或单价,当前商家编码:%s,市场价:%s", order.OrderNo, v.SkuNum, v.SkuCode, jxutils.IntPrice2StandardString(jxutils.StandardPrice2Int(unitPrice)))
|
||||
}
|
||||
}
|
||||
if len(skuBindInfos) > 0 {
|
||||
var nameIDs []int
|
||||
for _, v := range skuBindInfos {
|
||||
nameIDs = append(nameIDs, v.NameID)
|
||||
}
|
||||
if skuNamesInfo, err := cms.GetSkuNames(ctx, "", false, false, map[string]interface{}{
|
||||
"nameIDs": string(utils.MustMarshal(nameIDs)),
|
||||
}, 0, 0); err == nil {
|
||||
for _, skuName := range skuNamesInfo.SkuNames {
|
||||
if skuName.Status != model.SkuStatusNormal {
|
||||
cms.UpdateSkuName(ctx, skuName.ID, map[string]interface{}{
|
||||
"status": model.SkuStatusNormal,
|
||||
}, false)
|
||||
}
|
||||
for _, sku := range skuName.Skus {
|
||||
if sku.Status != model.SkuStatusNormal {
|
||||
cms.UpdateSku(ctx, sku.ID, map[string]interface{}{
|
||||
"status": model.SkuStatusNormal,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
cms.UpdateStoreSkus(ctx, 0, storeID, skuBindInfos, true, true)
|
||||
} else {
|
||||
globals.SugarLogger.Debugf("changeStoreSkusByOrder orderID:%d, storeID:%d is empty", order.OrderNo, storeID)
|
||||
}
|
||||
} else {
|
||||
globals.SugarLogger.Infof("[运营],微商城订单:%d,手机:%s找不到唯一一个本地门店%d", order.OrderNo, receiverMobile, len(storeList))
|
||||
}
|
||||
} else {
|
||||
globals.SugarLogger.Warnf("changeStoreSkusByOrder orderNo:%d, receiverMobile:%s failed with err:%v", order.OrderNo, receiverMobile, err)
|
||||
}
|
||||
}
|
||||
|
||||
func GetStoreList4Mobile(db *dao.DaoDB, mobileList []string) (storeList []*model.Store, err error) {
|
||||
sql := `
|
||||
SELECT t1.*
|
||||
FROM store t1
|
||||
WHERE t1.deleted_at = ? /*AND t1.change_price_type = ?*/`
|
||||
sqlParams := []interface{}{
|
||||
utils.DefaultTimeValue,
|
||||
// model.StoreChangePriceTypeBossDisabled,
|
||||
}
|
||||
if len(mobileList) > 0 {
|
||||
questionMarks := dao.GenQuestionMarks(len(mobileList))
|
||||
sql += " AND (t1.tel1 IN (" + questionMarks + ") OR t1.tel2 IN (" + questionMarks + `)
|
||||
OR (SELECT
|
||||
COUNT(*)
|
||||
FROM casbin_rule t2
|
||||
JOIN user t3 ON t3.user_id = t2.v0 AND t3.mobile IN (` + questionMarks + `)
|
||||
WHERE t2.v1 = CONCAT(?, t1.id)
|
||||
) > 0)
|
||||
`
|
||||
sqlParams = append(sqlParams, mobileList, mobileList, mobileList, autils.NewStoreBossRole(-1).GetFullName())
|
||||
}
|
||||
err = dao.GetRows(db, &storeList, sql, sqlParams...)
|
||||
return storeList, err
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
package cs
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/globals/api2"
|
||||
"git.rosy.net.cn/jx-callback/globals/testinit"
|
||||
)
|
||||
|
||||
func init() {
|
||||
testinit.Init()
|
||||
api2.Init()
|
||||
}
|
||||
|
||||
func TestGetStoreList4Mobile(t *testing.T) {
|
||||
storeList, err := GetStoreList4Mobile(dao.GetDB(), []string{"18180948107"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(utils.Format4Output(storeList, false))
|
||||
t.Log(len(storeList))
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
package orderman
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/netprinter"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/weixinmsg"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/partner/purchase/jd"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
)
|
||||
|
||||
func (c *OrderManager) OnNewFakeJdOrder(vendorOrderID string) (err error) {
|
||||
utils.CallFuncAsync(func() {
|
||||
orderInfo, err := api.FakeJdAPI.FakeQuerySingleOrderRaw(vendorOrderID)
|
||||
if err == nil {
|
||||
order := jd.Map2Order(orderInfo)
|
||||
jxutils.RefreshOrderSkuRelated(order)
|
||||
err = c.notifyNewFakeJdOrder(order)
|
||||
}
|
||||
if err != nil {
|
||||
globals.SugarLogger.Warnf("OnNewFakeJdOrder failed with err:%v", err)
|
||||
}
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *OrderManager) notifyNewFakeJdOrder(order *model.GoodsOrder) (err error) {
|
||||
db := dao.GetDB()
|
||||
storeDetail, err := dao.GetStoreDetailByVendorStoreID(db, order.VendorStoreID, model.VendorIDJD)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
realStoreID := storeDetail.ID
|
||||
if storeDetail.LinkStoreID != 0 {
|
||||
realStoreID = storeDetail.LinkStoreID
|
||||
}
|
||||
notifyWxNewFakeJdOrder(order, realStoreID)
|
||||
netprinter.PrintOrderByOrder4Store(jxcontext.AdminCtx, order, realStoreID)
|
||||
return err
|
||||
}
|
||||
|
||||
func notifyWxNewFakeJdOrder(order *model.GoodsOrder, storeID int) (err error) {
|
||||
globals.SugarLogger.Debugf("notifyWxNewFakeJdOrder orderID:%s", order.VendorOrderID)
|
||||
|
||||
sb := new(strings.Builder)
|
||||
sb.WriteString("老板,你有新订单了\n")
|
||||
sb.WriteString(fmt.Sprintf("订单号:%s\n", order.VendorOrderID))
|
||||
sb.WriteString("送达时间:")
|
||||
if order.BusinessType == model.BusinessTypeDingshida {
|
||||
sb.WriteString(utils.Time2Str(order.ExpectedDeliveredTime))
|
||||
} else {
|
||||
sb.WriteString("立即达")
|
||||
}
|
||||
sb.WriteString("\n")
|
||||
sb.WriteString(fmt.Sprintf("买家:%s\n", order.ConsigneeName))
|
||||
sb.WriteString(fmt.Sprintf("电话:%s\n", order.ConsigneeMobile))
|
||||
sb.WriteString(fmt.Sprintf("收货地址:%s\n", order.ConsigneeAddress))
|
||||
sb.WriteString("商品详情:\n")
|
||||
for _, sku := range order.Skus {
|
||||
sb.WriteString(fmt.Sprintf("\t%s*%d\n", sku.SkuName, sku.Count))
|
||||
}
|
||||
title := fmt.Sprintf("你有到家菜市新订单%d", order.OrderSeq)
|
||||
content := sb.String()
|
||||
// globals.SugarLogger.Debugf("notifyWxNewFakeJdOrder, orderID:%s, content:%s", order.VendorOrderID, content)
|
||||
_, err = weixinmsg.SendStoreMessage(jxcontext.AdminCtx, title, content, []int{storeID}, true, true)
|
||||
return err
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package orderman
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestOnNewFakeJdOrder(t *testing.T) {
|
||||
err := FixedOrderManager.OnNewFakeJdOrder("2002984074001021")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
time.Sleep(3 * time.Second)
|
||||
}
|
||||
@@ -1,262 +0,0 @@
|
||||
package orderman
|
||||
|
||||
import (
|
||||
"math"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
)
|
||||
|
||||
const (
|
||||
TotalRate = 200 // 总费率(千分之200)= 第三方平台费+京西品牌费+京西服务费,现阶段都是合计200‰
|
||||
MaxFreightMoneyFromJxByShop = 7 // 商家自送实际转美团/达达后由商家承担的运费金额上限
|
||||
)
|
||||
|
||||
// 处理正向订单结账信息
|
||||
func (c *OrderManager) SaveOrderFinancialInfo(order *model.OrderFinancial, operation string) (err error) {
|
||||
db := dao.GetDB()
|
||||
dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil || err != nil {
|
||||
dao.Rollback(db)
|
||||
if r != nil {
|
||||
panic(r)
|
||||
}
|
||||
}
|
||||
}()
|
||||
if operation == partner.UpdatedPeration {
|
||||
// db := orm.NewOrm()
|
||||
err = utils.CallFuncLogError(func() error {
|
||||
_, err = dao.ExecuteSQL(db, "DELETE FROM order_financial WHERE vendor_order_id = ? AND vendor_id = ?", order.VendorOrderID, order.VendorID)
|
||||
return err
|
||||
}, "SaveOrderFinancialInfo delete order_financial, orderID:%s", order.VendorOrderID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = utils.CallFuncLogError(func() error {
|
||||
_, err = dao.ExecuteSQL(db, "DELETE FROM order_sku_financial WHERE vendor_order_id = ? AND vendor_id = ? AND is_afs_order = 0", order.VendorOrderID, order.VendorID)
|
||||
return err
|
||||
}, "SaveOrderFinancialInfo delete order_sku_financial, orderID:%s", order.VendorOrderID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = utils.CallFuncLogError(func() error {
|
||||
_, err = dao.ExecuteSQL(db, "DELETE FROM order_discount_financial WHERE vendor_order_id = ? AND vendor_id = ?", order.VendorOrderID, order.VendorID)
|
||||
return err
|
||||
}, "SaveOrderFinancialInfo delete order_discount_financial, orderID:%s", order.VendorOrderID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
for _, activity := range order.Discounts {
|
||||
if err = dao.CreateEntity(db, activity); err != nil {
|
||||
if !dao.IsDuplicateError(err) {
|
||||
globals.SugarLogger.Warnf("On SaveOrderDiscountFinancialInfo order.VendorOrderID:%s err: order is err", order.VendorOrderID)
|
||||
return err
|
||||
}
|
||||
dao.Rollback(db)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
order.ShopMoneyByCal = order.SalePriceMoney - order.TotalDiscountMoney - order.PointsDeductionMoney + order.PmFreightDiscountMoney - order.DistanceFreightMoney - order.FreightTipsMoney - order.DonationMoney + order.SelfDeliveryDiscountMoney + order.PmSubsidyMoney + order.SkuBoxMoney + order.BoxMoney - order.PmMoney
|
||||
order.JxPmMoney = utils.Float64TwoInt64(float64(order.ShopMoney+order.PmMoney)*TotalRate/1000) - order.PmMoney // 京西平台费 = 总金额*20%-第三方平台费
|
||||
if order.JxPmMoney < 0 { // 如果算出京西平台费为负数,则置0
|
||||
order.JxPmMoney = 0
|
||||
}
|
||||
|
||||
order.JxShopMoney = order.ShopMoney - order.JxPmMoney + order.JxSubsidyMoney - order.JxFreightMoneyByShop
|
||||
// 订单结算金额拆分计算,拆分到单条sku
|
||||
// 先获取订单主体优惠金额
|
||||
platOrderGoodsDiscountMoney := order.PmSubsidyMoney - order.PmSkuSubsidyMoney + order.SelfDeliveryDiscountMoney
|
||||
// 结算平台扣除项汇总---平台佣金,商家设置运费减免,远距离费,小费,公益捐款、、、、
|
||||
deductionsByPm := order.FreightDiscountMoney + order.DistanceFreightMoney + order.FreightTipsMoney + order.DonationMoney + order.PmMoney
|
||||
// 结算京西扣除项汇总---京西佣金,京西配送运费
|
||||
deductionsByJx := order.JxPmMoney + order.JxFreightMoneyByShop
|
||||
for _, sku := range order.Skus[1:] {
|
||||
// 用户支付菜品金额,用户为这一条sku支付的菜品金额
|
||||
sku.UserMoney = utils.Float64TwoInt64(float64(order.SalePriceMoney-order.DiscountMoney-order.PointsDeductionMoney+order.BoxMoney+order.SkuBoxMoney) * float64(sku.SalePrice*int64(sku.Count)+sku.SkuBoxMoney) / float64(order.SalePriceMoney+order.SkuBoxMoney)) // 林峰确认,比如49-2满减,算餐盒费满49元,不算餐盒费不足49元,是可以参加满减活动的,那么餐盒费也应该和商品金额一起进行折算
|
||||
order.Skus[0].UserMoney += sku.UserMoney
|
||||
// 计算平台订单主体补贴拆分到单条sku的金额 + sku.PmSubsidyMoneyForSku
|
||||
sku.PmSubsidyMoney = sku.PmSkuSubsidyMoney + utils.Float64TwoInt64(float64(platOrderGoodsDiscountMoney*sku.SalePrice*int64(sku.Count)+sku.SkuBoxMoney)/float64(order.SalePriceMoney+order.SkuBoxMoney))
|
||||
order.Skus[0].PmSubsidyMoney += sku.PmSubsidyMoney
|
||||
// 计算京西满减补贴拆分到单条sku的金额 + sku.JxSubsidyMoneyForSku
|
||||
sku.JxSubsidyMoney = sku.JxSkuSubsidyMoney + utils.Float64TwoInt64(float64(order.JxSubsidyMoney-order.PmSkuSubsidyMoney)*float64(sku.SalePrice*int64(sku.Count)+sku.SkuBoxMoney)/float64(order.SalePriceMoney+order.SkuBoxMoney))
|
||||
order.Skus[0].JxSubsidyMoney += sku.JxSubsidyMoney
|
||||
// 计算单条sku需要承担的平台扣费金额
|
||||
sku.PmDeductionsMoney = utils.Float64TwoInt64(float64(deductionsByPm) * (float64(sku.UserMoney + sku.PmSubsidyMoney)) / (float64(order.SalePriceMoney + order.BoxMoney + order.SkuBoxMoney - order.DiscountMoney - order.PointsDeductionMoney + order.PmSubsidyMoney)))
|
||||
order.Skus[0].PmDeductionsMoney += sku.PmDeductionsMoney
|
||||
// 计算单条sku平台应该结算给京西的金额
|
||||
sku.ShopMoneyByCal = sku.UserMoney + sku.PmSubsidyMoney - sku.PmDeductionsMoney
|
||||
order.Skus[0].ShopMoneyByCal += sku.ShopMoneyByCal
|
||||
// j计算单条sku需要承担的京西扣费金额
|
||||
sku.JxDeductionsMoney = utils.Float64TwoInt64(float64(deductionsByJx*sku.ShopMoneyByCal) / float64(order.ShopMoney))
|
||||
order.Skus[0].JxDeductionsMoney += sku.JxDeductionsMoney
|
||||
// 计算单条sku京西应该结算给商家的金额
|
||||
sku.JxShopMoney = sku.ShopMoneyByCal + sku.JxSubsidyMoney - sku.JxDeductionsMoney
|
||||
order.Skus[0].JxShopMoney += sku.JxShopMoney
|
||||
if sku.SkuID >= math.MaxInt32 {
|
||||
sku.SkuID = sku.JxSkuID
|
||||
}
|
||||
if err = dao.CreateEntity(db, sku); err != nil {
|
||||
if !dao.IsDuplicateError(err) {
|
||||
globals.SugarLogger.Warnf("On SaveOrderSkuFinancialInfo order.VendorOrderID:%s err:%v", order.VendorOrderID, err)
|
||||
return err
|
||||
}
|
||||
dao.Rollback(db)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
if len(order.Skus) > 0 {
|
||||
sku := order.Skus[0]
|
||||
if sku.SkuID > math.MaxInt32 {
|
||||
sku.SkuID = sku.JxSkuID
|
||||
}
|
||||
sku.UserMoney = order.SalePriceMoney - order.DiscountMoney - sku.UserMoney
|
||||
sku.PmSubsidyMoney = platOrderGoodsDiscountMoney + order.SelfDeliveryDiscountMoney - sku.PmSubsidyMoney
|
||||
sku.JxSubsidyMoney = order.JxSubsidyMoney - sku.JxSubsidyMoney
|
||||
sku.PmDeductionsMoney = deductionsByPm - sku.PmDeductionsMoney
|
||||
sku.ShopMoneyByCal = order.ShopMoney - sku.ShopMoneyByCal
|
||||
sku.JxDeductionsMoney = deductionsByJx - sku.JxDeductionsMoney
|
||||
sku.JxShopMoney = order.JxShopMoney - sku.JxShopMoney
|
||||
if err = dao.CreateEntity(db, sku); err != nil {
|
||||
if !dao.IsDuplicateError(err) {
|
||||
globals.SugarLogger.Warnf("On SaveOrderSkuFinancialInfo order.VendorOrderID:%s err:%v", order.VendorOrderID, err)
|
||||
return err
|
||||
}
|
||||
dao.Rollback(db)
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
globals.SugarLogger.Warnf("On SaveOrderSkuFinancialInfo order.VendorOrderID:%s err: order have no sku", order.VendorOrderID)
|
||||
}
|
||||
// 加上京西对单条sku的补贴,再存数据库
|
||||
order.JxSubsidyMoney += order.JxSkuSubsidyMoney
|
||||
if err = dao.CreateEntity(db, order); err != nil {
|
||||
if !dao.IsDuplicateError(err) {
|
||||
globals.SugarLogger.Warnf("On SaveOrderFinancialInfo order.VendorOrderID:%s err: order is err", order.VendorOrderID)
|
||||
return err
|
||||
}
|
||||
dao.Rollback(db)
|
||||
return nil
|
||||
}
|
||||
dao.Commit(db)
|
||||
return err
|
||||
}
|
||||
|
||||
// 处理售后订单结账信息
|
||||
func (c *OrderManager) SaveAfsOrderFinancialInfo(afsOrder *model.AfsOrder) (err error) {
|
||||
globals.SugarLogger.Debug(afsOrder.AfsOrderID)
|
||||
db := dao.GetDB()
|
||||
dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil || err != nil {
|
||||
dao.Rollback(db)
|
||||
if r != nil {
|
||||
panic(r)
|
||||
}
|
||||
}
|
||||
}()
|
||||
// 平台结算扣除汇总--平台补贴,售后产生运费,平台收包装费,同城运费、、、
|
||||
deductionsByPm := afsOrder.PmSubsidyMoney + afsOrder.AfsFreightMoney + afsOrder.BoxMoney + afsOrder.TongchengFreightMoney
|
||||
afsOrder.RefundMoneyByCal = afsOrder.SkuUserMoney + afsOrder.FreightUserMoney + deductionsByPm - afsOrder.PmRefundMoney
|
||||
// order.TotalMoney += order.SkuJxMoney // 退款单京西补贴部分先不作计算
|
||||
if err = dao.CreateEntity(db, afsOrder); err != nil {
|
||||
if !dao.IsDuplicateError(err) {
|
||||
globals.SugarLogger.Warnf("On SaveAfsOrderFinancialInfo afsOrder.AfsOrderID:%s err: SaveAfsOrder is err", afsOrder.AfsOrderID)
|
||||
return err
|
||||
}
|
||||
dao.Rollback(db)
|
||||
return nil
|
||||
}
|
||||
|
||||
// 京西结算扣除汇总,先不作计算,计算单条sku最终扣款金额(+该条sku承担的平台结算扣除金额)
|
||||
for _, orderSku := range afsOrder.Skus[1:] {
|
||||
orderSku.RefundMoneyByCal = orderSku.PmSkuSubsidyMoney +
|
||||
utils.Float64TwoInt64(float64(afsOrder.RefundMoneyByCal-afsOrder.PmSkuSubsidyMoney)*float64(orderSku.UserMoney+orderSku.PmSubsidyMoney-orderSku.PmSkuSubsidyMoney)/float64(afsOrder.SkuUserMoney+afsOrder.PmSubsidyMoney-afsOrder.PmSkuSubsidyMoney))
|
||||
afsOrder.Skus[0].RefundMoneyByCal += orderSku.RefundMoneyByCal
|
||||
if err = dao.CreateEntity(db, orderSku); err != nil {
|
||||
if !dao.IsDuplicateError(err) {
|
||||
globals.SugarLogger.Warnf("On SaveAfsOrderFinancialInfo afsOrder.AfsOrderID:%s err: SaveAfsOrderSku is err", afsOrder.AfsOrderID)
|
||||
return err
|
||||
}
|
||||
dao.Rollback(db)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
if len(afsOrder.Skus) > 0 {
|
||||
orderSku := afsOrder.Skus[0]
|
||||
orderSku.RefundMoneyByCal = afsOrder.RefundMoneyByCal - orderSku.RefundMoneyByCal
|
||||
if err = dao.CreateEntity(db, orderSku); err != nil {
|
||||
if !dao.IsDuplicateError(err) {
|
||||
globals.SugarLogger.Warnf("On SaveAfsOrderFinancialInfo afsOrder.AfsOrderID:%s err: SaveAfsOrderSku is err", afsOrder.AfsOrderID)
|
||||
return err
|
||||
}
|
||||
dao.Rollback(db)
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
globals.SugarLogger.Warnf("On SaveAfsOrderFinancialInfo afsOrder.AfsOrderID:%s err: afsOrder have no sku", afsOrder.AfsOrderID)
|
||||
}
|
||||
dao.Commit(db)
|
||||
return err
|
||||
}
|
||||
|
||||
// 转自送实际使用美团/达达配送,调用此方法
|
||||
func (c *OrderManager) UpdataOrderFinancialInfo(orderFinancial *model.OrderFinancial, wayBill *model.Waybill) (err error) {
|
||||
// 通过本地数据库去取是否转美团/达达,并计算运费,写在上级调用函数里面传递过来
|
||||
// wayBill, err2 := partner.CurOrderManager.LoadWaybill(orderFinancial.VendorOrderID, orderFinancial.VendorID)
|
||||
// if err = err2; err == nil {
|
||||
// orderFinancial.JxFreightMoney = wayBill.DesiredFee
|
||||
// }
|
||||
db := dao.GetDB()
|
||||
dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil || err != nil {
|
||||
dao.Rollback(db)
|
||||
if r != nil {
|
||||
panic(r)
|
||||
}
|
||||
}
|
||||
}()
|
||||
orderFinancial.JxFreightMoney = wayBill.DesiredFee
|
||||
if (orderFinancial.JxFreightMoney - orderFinancial.SelfDeliveryDiscountMoney) > MaxFreightMoneyFromJxByShop {
|
||||
orderFinancial.JxFreightMoneyByShop = orderFinancial.SelfDeliveryDiscountMoney + MaxFreightMoneyFromJxByShop
|
||||
} else if (orderFinancial.JxFreightMoney - orderFinancial.SelfDeliveryDiscountMoney) < 0 {
|
||||
orderFinancial.JxFreightMoneyByShop = orderFinancial.SelfDeliveryDiscountMoney
|
||||
} else {
|
||||
orderFinancial.JxFreightMoneyByShop = orderFinancial.JxFreightMoney
|
||||
}
|
||||
orderFinancial.JxShopMoney -= orderFinancial.JxFreightMoneyByShop
|
||||
// orderFinancial.JxFreightMoneyByShop 的改变直接影响到单条sku的京西结算金额的改变
|
||||
jxDecMoney := orderFinancial.JxFreightMoneyByShop
|
||||
for _, sku := range orderFinancial.Skus[1:] {
|
||||
// 重新计算单条sku京西应该结算的金额
|
||||
skuJxDecMoney := utils.Float64TwoInt64(float64(jxDecMoney*sku.SalePrice*int64(sku.Count)+sku.SkuBoxMoney) / float64(orderFinancial.SalePriceMoney+orderFinancial.SkuBoxMoney))
|
||||
sku.JxDeductionsMoney += skuJxDecMoney
|
||||
sku.JxShopMoney -= skuJxDecMoney
|
||||
jxDecMoney -= skuJxDecMoney
|
||||
if _, err = dao.UpdateEntity(db, sku); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if len(orderFinancial.Skus) > 0 {
|
||||
sku := orderFinancial.Skus[0]
|
||||
sku.JxDeductionsMoney += jxDecMoney
|
||||
sku.JxShopMoney -= jxDecMoney
|
||||
if _, err = dao.UpdateEntity(db, sku); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err = dao.CreateEntity(db, orderFinancial); err != nil {
|
||||
globals.SugarLogger.Warnf("On SaveOrderFinancialInfo err: order is err")
|
||||
return err
|
||||
}
|
||||
dao.Commit(db)
|
||||
// orderFinancial 和 OrderSkuFinancial 数据计算完毕,准备进行更新
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,424 +0,0 @@
|
||||
package orderman
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxcallback/scheduler"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"github.com/astaxie/beego/orm"
|
||||
)
|
||||
|
||||
func (c *OrderManager) LoadAfsOrder(vendorAfsOrderID string, vendorID int) (afsOrder *model.AfsOrder, err error) {
|
||||
return c.loadAfsOrder(dao.GetDB(), vendorAfsOrderID, vendorID)
|
||||
}
|
||||
|
||||
func (c *OrderManager) loadAfsOrder(db *dao.DaoDB, vendorAfsOrderID string, vendorID int) (afsOrder *model.AfsOrder, err error) {
|
||||
afsOrder = &model.AfsOrder{
|
||||
AfsOrderID: vendorAfsOrderID,
|
||||
VendorID: vendorID,
|
||||
}
|
||||
if err = dao.GetEntity(db, afsOrder, "AfsOrderID", "VendorID"); err != nil {
|
||||
afsOrder = nil
|
||||
}
|
||||
return afsOrder, err
|
||||
}
|
||||
|
||||
func (c *OrderManager) OnAfsOrderAdjust(afsOrder *model.AfsOrder, orderStatus *model.OrderStatus) (err error) {
|
||||
return c.onAfsOrderNew(afsOrder, orderStatus, true)
|
||||
}
|
||||
|
||||
func (c *OrderManager) OnAfsOrderNew(afsOrder *model.AfsOrder, orderStatus *model.OrderStatus) (err error) {
|
||||
return c.onAfsOrderNew(afsOrder, orderStatus, false)
|
||||
}
|
||||
|
||||
func (c *OrderManager) onAfsOrderNew(afsOrder *model.AfsOrder, orderStatus *model.OrderStatus, isAdjust bool) (err error) {
|
||||
db := dao.GetDB()
|
||||
globals.SugarLogger.Debugf("onAfsOrderNew1 orderID:%s", afsOrder.VendorOrderID)
|
||||
c.setAfsOrderID(db, orderStatus)
|
||||
if afsOrder.AfsOrderID == "" {
|
||||
afsOrder.AfsOrderID = orderStatus.VendorOrderID
|
||||
}
|
||||
if afsOrder.VendorStatus == "" {
|
||||
afsOrder.VendorStatus = orderStatus.VendorStatus
|
||||
}
|
||||
if afsOrder.Status == model.OrderStatusUnknown {
|
||||
afsOrder.Status = orderStatus.Status
|
||||
}
|
||||
globals.SugarLogger.Debugf("onAfsOrderNew2 orderID:%s", afsOrder.VendorOrderID)
|
||||
//
|
||||
if order, _ := c.LoadOrder(afsOrder.VendorOrderID, afsOrder.VendorID); order != nil {
|
||||
if order.ConsigneeMobile2 == "" {
|
||||
if handler := partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID); handler != nil {
|
||||
if order2, _ := handler.GetOrder(order.VendorOrgCode, order.VendorOrderID); order2 != nil && order.ConsigneeMobile != order2.ConsigneeMobile {
|
||||
order.ConsigneeMobile = order2.ConsigneeMobile
|
||||
c.UpdateOrderFields(order, []string{"ConsigneeMobile"})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//
|
||||
dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil || err != nil {
|
||||
dao.Rollback(db)
|
||||
panic(r)
|
||||
}
|
||||
}()
|
||||
isDuplicated, err := addOrderOrWaybillStatus(orderStatus, db)
|
||||
globals.SugarLogger.Debugf("onAfsOrderNew afsOrderID:%s, isDuplicated:%t", afsOrder.AfsOrderID, isDuplicated)
|
||||
if err != nil || isDuplicated {
|
||||
if err == nil {
|
||||
dao.Commit(db)
|
||||
}
|
||||
return err
|
||||
}
|
||||
var existAfsOrder *model.AfsOrder
|
||||
if existAfsOrder, err = c.loadAfsOrder(db, afsOrder.AfsOrderID, afsOrder.VendorID); err != nil {
|
||||
if !dao.IsNoRowsError(err) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if existAfsOrder != nil {
|
||||
// todo 可能导致状态回绕
|
||||
existAfsOrder.Status = afsOrder.Status
|
||||
existAfsOrder.VendorStatus = afsOrder.VendorStatus
|
||||
if _, err = dao.UpdateEntity(db, existAfsOrder, "Status", "VendorStatus"); err != nil {
|
||||
return err
|
||||
}
|
||||
afsOrder = existAfsOrder
|
||||
} else {
|
||||
// 全退都要先全删除再建
|
||||
if afsOrder.RefundType == model.AfsTypeFullRefund {
|
||||
isAdjust = true
|
||||
}
|
||||
if err = c.SaveAfsOrder(db, afsOrder, isAdjust); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
dao.Commit(db)
|
||||
scheduler.CurrentScheduler.OnAfsOrderNew(afsOrder, false)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *OrderManager) SaveAfsOrder(db *dao.DaoDB, afsOrder *model.AfsOrder, isDeleteFirst bool) (err error) {
|
||||
globals.SugarLogger.Debug(afsOrder.AfsOrderID)
|
||||
if db == nil {
|
||||
db = dao.GetDB()
|
||||
}
|
||||
if err = c.updateAfsOrderOtherInfo(db, afsOrder); err != nil {
|
||||
return err
|
||||
}
|
||||
dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil || err != nil {
|
||||
dao.Rollback(db)
|
||||
if r != nil {
|
||||
panic(r)
|
||||
}
|
||||
}
|
||||
}()
|
||||
if isDeleteFirst {
|
||||
err = utils.CallFuncLogError(func() error {
|
||||
_, err = dao.DeleteEntity(db, afsOrder, "VendorOrderID", "VendorID")
|
||||
return err
|
||||
}, "SaveAfsOrder delete AfsOrder, afsOrderID:%s", afsOrder.AfsOrderID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = utils.CallFuncLogError(func() error {
|
||||
_, err = dao.DeleteEntity(db, &model.OrderSkuFinancial{
|
||||
VendorOrderID: afsOrder.VendorOrderID,
|
||||
VendorID: afsOrder.VendorID,
|
||||
IsAfsOrder: 1,
|
||||
}, "VendorOrderID", "VendorID", "IsAfsOrder")
|
||||
return err
|
||||
}, "SaveAfsOrder delete OrderSkuFinancial, afsOrderID:%s", afsOrder.AfsOrderID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// 平台结算扣除汇总--平台补贴,售后产生运费,平台收包装费,同城运费、、、
|
||||
deductionsByPm := afsOrder.PmSubsidyMoney + afsOrder.AfsFreightMoney + afsOrder.BoxMoney + afsOrder.TongchengFreightMoney
|
||||
afsOrder.RefundMoneyByCal = afsOrder.SkuUserMoney + afsOrder.FreightUserMoney + deductionsByPm - afsOrder.PmRefundMoney
|
||||
// order.TotalMoney += order.SkuJxMoney // 退款单京西补贴部分先不作计算
|
||||
if err = dao.CreateEntity(db, afsOrder); err != nil {
|
||||
globals.SugarLogger.Warnf("On SaveAfsOrder afsOrder.AfsOrderID:%s err:%v", afsOrder.AfsOrderID, err)
|
||||
return err
|
||||
}
|
||||
|
||||
// 京西结算扣除汇总,先不作计算,计算单条sku最终扣款金额(+该条sku承担的平台结算扣除金额)
|
||||
for _, orderSku := range afsOrder.Skus[1:] {
|
||||
orderSku.RefundMoneyByCal = orderSku.PmSkuSubsidyMoney +
|
||||
utils.Float64TwoInt64(float64(afsOrder.RefundMoneyByCal-afsOrder.PmSkuSubsidyMoney)*float64(orderSku.UserMoney+orderSku.PmSubsidyMoney-orderSku.PmSkuSubsidyMoney)/float64(afsOrder.SkuUserMoney+afsOrder.PmSubsidyMoney-afsOrder.PmSkuSubsidyMoney))
|
||||
afsOrder.Skus[0].RefundMoneyByCal += orderSku.RefundMoneyByCal
|
||||
if err = dao.CreateEntity(db, orderSku); err != nil {
|
||||
globals.SugarLogger.Warnf("On SaveAfsOrder afsOrder.AfsOrderID:%s err:%v, orderSku:%s", afsOrder.AfsOrderID, err, utils.Format4Output(orderSku, true))
|
||||
return err
|
||||
}
|
||||
}
|
||||
if len(afsOrder.Skus) > 0 {
|
||||
orderSku := afsOrder.Skus[0]
|
||||
orderSku.RefundMoneyByCal = afsOrder.RefundMoneyByCal - orderSku.RefundMoneyByCal
|
||||
if err = dao.CreateEntity(db, orderSku); err != nil {
|
||||
globals.SugarLogger.Warnf("On SaveAfsOrder afsOrder.AfsOrderID:%s err:%v, orderSku:%s", afsOrder.AfsOrderID, err, utils.Format4Output(orderSku, true))
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
globals.SugarLogger.Warnf("On SaveAfsOrder afsOrder.AfsOrderID:%s err: afsOrder have no sku", afsOrder.AfsOrderID)
|
||||
}
|
||||
dao.Commit(db)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *OrderManager) OnAfsOrderStatusChanged(orderStatus *model.OrderStatus) (err error) {
|
||||
db := dao.GetDB()
|
||||
c.setAfsOrderID(db, orderStatus)
|
||||
dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
dao.Rollback(db)
|
||||
panic(r)
|
||||
}
|
||||
}()
|
||||
isDuplicated, afsOrder, err := c.addAfsOrderStatus(db, orderStatus)
|
||||
if err != nil || isDuplicated {
|
||||
if err == nil {
|
||||
dao.Commit(db)
|
||||
} else {
|
||||
dao.Rollback(db)
|
||||
}
|
||||
return err
|
||||
}
|
||||
dao.Commit(db)
|
||||
scheduler.CurrentScheduler.OnAfsOrderStatusChanged(afsOrder, orderStatus, false)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *OrderManager) addAfsOrderStatus(db *dao.DaoDB, orderStatus *model.OrderStatus) (isDuplicated bool, order *model.AfsOrder, err error) {
|
||||
globals.SugarLogger.Debugf("addAfsOrderStatus refOrderID:%s, orderID:%s", orderStatus.RefVendorOrderID, orderStatus.VendorOrderID)
|
||||
if db == nil {
|
||||
db = dao.GetDB()
|
||||
}
|
||||
isDuplicated, err = addOrderOrWaybillStatus(orderStatus, db)
|
||||
if err == nil && !isDuplicated && (orderStatus.Status != model.OrderStatusUnknown && orderStatus.Status != model.OrderStatusMsg) {
|
||||
order = &model.AfsOrder{
|
||||
AfsOrderID: orderStatus.VendorOrderID,
|
||||
VendorID: orderStatus.VendorID,
|
||||
}
|
||||
if err = db.Db.ReadForUpdate(order, "AfsOrderID", "VendorID"); err == nil {
|
||||
if orderStatus.Status > model.OrderStatusUnknown { // todo 要求status不能回绕
|
||||
order.VendorStatus = orderStatus.VendorStatus
|
||||
order.Status = orderStatus.Status
|
||||
updateFields := []string{
|
||||
"VendorStatus",
|
||||
"Status",
|
||||
}
|
||||
if model.IsAfsOrderFinalStatus(orderStatus.Status) {
|
||||
order.AfsFinishedAt = orderStatus.StatusTime
|
||||
updateFields = append(updateFields, "AfsFinishedAt")
|
||||
}
|
||||
utils.CallFuncLogError(func() error {
|
||||
_, err = dao.UpdateEntity(db, order, updateFields...)
|
||||
return err
|
||||
}, "addAfsOrderStatus update orderID:%s, status:%v", order.VendorOrderID, orderStatus)
|
||||
} else {
|
||||
isDuplicated = true
|
||||
}
|
||||
} else {
|
||||
if dao.IsNoRowsError(err) { // todo 消息错序
|
||||
err = nil
|
||||
} else {
|
||||
globals.SugarLogger.Warnf("addAfsOrderStatus orderID:%s read failed with error:%v", order.VendorOrderID, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return isDuplicated, order, err
|
||||
}
|
||||
|
||||
func (c *OrderManager) updateAfsOrderSkuOtherInfo(db *dao.DaoDB, order *model.AfsOrder) (err error) {
|
||||
globals.SugarLogger.Debugf("updateAfsOrderSkuOtherInfo orderID:%s, VendorStoreID:%s", order.VendorOrderID, order.VendorStoreID)
|
||||
jxStoreID := jxutils.GetSaleStoreIDFromAfsOrder(order)
|
||||
opNumStr := "2"
|
||||
if jxStoreID == 0 {
|
||||
globals.SugarLogger.Infof("updateAfsOrderSkuOtherInfo [运营%s]订单在京西与平台都找不到京西门店信息orderID:%s, VendorStoreID:%s", opNumStr, order.VendorOrderID, order.VendorStoreID)
|
||||
return nil
|
||||
}
|
||||
orderSkus := order.Skus
|
||||
var vendorSkuIDs []string
|
||||
skuIDMap := make(map[int]int)
|
||||
for _, v := range orderSkus {
|
||||
if v.VendorSkuID != "" {
|
||||
vendorSkuIDs = append(vendorSkuIDs, v.VendorSkuID)
|
||||
}
|
||||
|
||||
if skuID := jxutils.GetSkuIDFromOrderSkuFinancial(v); skuID > 0 {
|
||||
skuIDMap[skuID] = 1
|
||||
}
|
||||
}
|
||||
if len(vendorSkuIDs) > 0 {
|
||||
var vendorStoreID string
|
||||
if order.VendorID == model.VendorIDJDShop {
|
||||
vendorStoreID = model.JdShopMainVendorStoreID
|
||||
} else {
|
||||
vendorStoreID = order.VendorStoreID
|
||||
}
|
||||
l, err := dao.GetStoreSkuPriceAndWeight(db, vendorStoreID, order.VendorID, vendorSkuIDs)
|
||||
if err != nil {
|
||||
globals.SugarLogger.Warnf("updateAfsOrderSkuOtherInfo orderID:%s failed with err:%v", order.VendorOrderID, err)
|
||||
return err
|
||||
}
|
||||
skumapper := storeSkuPriceAndWeight2Map(l)
|
||||
|
||||
var actStoreSkuMap *jxutils.ActStoreSkuMap
|
||||
if len(skuIDMap) > 0 {
|
||||
if order2, err2 := c.LoadOrder(order.VendorOrderID, order.VendorID); err2 == nil {
|
||||
actStoreSkuList, err := dao.GetEffectiveActStoreSkuInfo(db, 0, []int{order.VendorID}, model.ActTypeAll, []int{jxStoreID}, jxutils.IntMap2List(skuIDMap), order2.OrderCreatedAt, order2.OrderCreatedAt)
|
||||
if err != nil {
|
||||
globals.SugarLogger.Errorf("updateAfsOrderSkuOtherInfo can not get sku promotion info for error:%v", err)
|
||||
return err
|
||||
}
|
||||
actStoreSkuMap = jxutils.NewActStoreSkuMap(actStoreSkuList, false)
|
||||
}
|
||||
}
|
||||
for _, v := range orderSkus {
|
||||
v.AfsOrderID = order.AfsOrderID
|
||||
v.VendorID = order.VendorID
|
||||
v.VendorOrderID = order.VendorOrderID
|
||||
v.IsAfsOrder = 1
|
||||
v.VendorStoreID = order.VendorStoreID
|
||||
v.StoreID = order.StoreID
|
||||
v.JxStoreID = jxStoreID
|
||||
|
||||
intVendorSkuID := utils.Str2Int64WithDefault(v.VendorSkuID, 0)
|
||||
if intVendorSkuID != 0 && v.VendorSkuID != "-70000" { // todo hard code
|
||||
skuBindInfo := skumapper[v.VendorSkuID]
|
||||
if skuBindInfo == nil {
|
||||
globals.SugarLogger.Infof("updateAfsOrderSkuOtherInfo [运营%s]%s订单sku找不到门店价格(或商品映射),orderID:%s, StoreID:%d, VendorSkuID:%s, sku:%v", opNumStr, model.VendorChineseNames[order.VendorID], order.VendorOrderID, jxStoreID, v.VendorSkuID, v)
|
||||
} else {
|
||||
v.JxSkuID = skuBindInfo.SkuID
|
||||
v.ShopPrice = int64(skuBindInfo.Price)
|
||||
}
|
||||
}
|
||||
if actStoreSkuMap != nil {
|
||||
if skuID := jxutils.GetSkuIDFromOrderSkuFinancial(v); skuID > 0 && v.StoreSubName != "" {
|
||||
if actStoreSku := actStoreSkuMap.GetActStoreSku(jxStoreID, skuID, order.VendorID); actStoreSku != nil {
|
||||
v.StoreSubID = actStoreSku.ActID
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *OrderManager) updateAfsOrderOtherInfo(db *dao.DaoDB, afsOrder *model.AfsOrder) (err error) {
|
||||
globals.SugarLogger.Debugf("updateAfsOrderOtherInfo orderID:%s, VendorStoreID:%s", afsOrder.VendorOrderID, afsOrder.VendorStoreID)
|
||||
if afsOrder.VendorStoreID != "" {
|
||||
if storeDetail, err := dao.GetStoreDetailByVendorStoreID(db, afsOrder.VendorStoreID, 0); err == nil {
|
||||
afsOrder.JxStoreID = storeDetail.Store.ID
|
||||
}
|
||||
}
|
||||
if afsOrder.StoreID == 0 && afsOrder.JxStoreID == 0 {
|
||||
if order, err2 := c.LoadOrder(afsOrder.VendorOrderID, afsOrder.VendorID); err2 == nil {
|
||||
afsOrder.JxStoreID = order.JxStoreID
|
||||
if afsOrder.StoreID == 0 {
|
||||
afsOrder.StoreID = order.StoreID
|
||||
}
|
||||
if afsOrder.VendorStoreID == "" {
|
||||
afsOrder.VendorStoreID = order.VendorStoreID
|
||||
}
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
if err = c.updateAfsOrderSkuOtherInfo(db, afsOrder); err == nil {
|
||||
jxutils.RefreshAfsOrderSkuRelated(afsOrder)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *OrderManager) UpdateAfsOrderFields(afsOrder *model.AfsOrder, fieldList []string) (err error) {
|
||||
db := orm.NewOrm()
|
||||
utils.CallFuncLogError(func() error {
|
||||
_, err = db.Update(afsOrder, fieldList...)
|
||||
return err
|
||||
}, "UpdateAfsOrderFields orderID:%s failed with error:%v", afsOrder.VendorOrderID, err)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *OrderManager) setAfsOrderID(db *dao.DaoDB, orderStatus *model.OrderStatus) {
|
||||
// globals.SugarLogger.Debugf("setAfsOrderID1 orderStatus:%v", utils.Format4Output(orderStatus, true))
|
||||
if dao.IsVendorThingIDEmpty(orderStatus.VendorOrderID) {
|
||||
index := 1
|
||||
if afsOrderList, err2 := dao.GetAfsOrders(db, orderStatus.RefVendorID, orderStatus.RefVendorOrderID, ""); err2 == nil {
|
||||
if len(afsOrderList) > 0 {
|
||||
list := strings.Split(afsOrderList[0].AfsOrderID, "-")
|
||||
if len(list) > 1 {
|
||||
index = int(utils.Str2Int64WithDefault(list[1], 0))
|
||||
if afsOrderList[0].Status >= model.AfsOrderStatusFinished {
|
||||
index++
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
globals.SugarLogger.Warnf("setAfsOrderID err2:%v", err2)
|
||||
}
|
||||
orderStatus.VendorOrderID = composeAfsOrderID(orderStatus.RefVendorOrderID, index)
|
||||
}
|
||||
// globals.SugarLogger.Debugf("setAfsOrderID2 orderStatus:%v", utils.Format4Output(orderStatus, true))
|
||||
}
|
||||
|
||||
func composeAfsOrderID(vendorOrderID string, index int) (afsOrderID string) {
|
||||
return strings.Join([]string{
|
||||
vendorOrderID,
|
||||
utils.Int2Str(index),
|
||||
}, "-")
|
||||
}
|
||||
|
||||
func (c *OrderManager) CreateAfsOrderFromOrder(vendorOrderID string, vendorID int) (afsOrder *model.AfsOrder, err error) {
|
||||
order, err := c.LoadOrder(vendorOrderID, vendorID)
|
||||
// globals.SugarLogger.Debug(utils.Format4Output(order, false))
|
||||
if err == nil {
|
||||
afsOrder = &model.AfsOrder{
|
||||
VendorID: vendorID,
|
||||
VendorOrderID: vendorOrderID,
|
||||
JxStoreID: order.JxStoreID,
|
||||
VendorStoreID: order.VendorStoreID,
|
||||
StoreID: order.StoreID,
|
||||
VendorOrgCode: order.VendorOrgCode,
|
||||
}
|
||||
} else {
|
||||
globals.SugarLogger.Warnf("CreateAfsOrderFromOrder, orderID:%s is not found from partner.CurOrderManager.LoadOrder", vendorOrderID)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, sku := range order.Skus {
|
||||
orderSkuFinancial := &model.OrderSkuFinancial{
|
||||
VendorID: sku.VendorID,
|
||||
VendorOrderID: sku.VendorOrderID,
|
||||
// OrderFinancialID: sku.VendorOrderID,
|
||||
// ConfirmTime: afsOrder.AfsCreateAt,
|
||||
VendorStoreID: afsOrder.VendorStoreID,
|
||||
StoreID: afsOrder.StoreID,
|
||||
JxStoreID: afsOrder.JxStoreID,
|
||||
VendorSkuID: sku.VendorSkuID,
|
||||
SkuID: sku.SkuID,
|
||||
PromotionType: sku.PromotionType,
|
||||
Name: sku.SkuName,
|
||||
ShopPrice: sku.ShopPrice,
|
||||
SalePrice: sku.SalePrice,
|
||||
Count: sku.Count,
|
||||
// UserMoney: sku.UserMoney,
|
||||
// PmSubsidyMoney: sku.PmSubsidyMoney,
|
||||
IsAfsOrder: 1,
|
||||
}
|
||||
afsOrder.Skus = append(afsOrder.Skus, orderSkuFinancial)
|
||||
}
|
||||
return afsOrder, nil
|
||||
}
|
||||
@@ -1,213 +0,0 @@
|
||||
package orderman
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/weixinmsg"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/model/legacymodel"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
)
|
||||
|
||||
const (
|
||||
COMMENT_NOT_RESOLVED = 0 //未解决的差评状态
|
||||
COMMENT_RESOLVED = 1 //已解决的差评状态
|
||||
|
||||
JX_BAD_COMMENTS_MAX_LEVEL = 2 // 差评最大分
|
||||
JX_MIDDLE_COMMENTS_MAX_LEVEL = 4 // 中评最大分
|
||||
|
||||
COMMENTS_SCORE_ONE_ORTWO_BEGIN_DELAY_TIME = 1 * 60 //评论回复一星或二星回复延迟开始时间区间
|
||||
COMMENTS_SCORE_ONE_ORTWO_END_DELAY_TIME = 3 * 60 //评论回复一星或二星回复延迟结束时间区间
|
||||
COMMENTS_SCORE_THREE_BEGIN_DELAY_TIME = 2 * 60 //评论回复三星回复延迟开始时间区间
|
||||
COMMENTS_SCORE_THREE_END_DELAY_TIME = 4 * 60 //评论回复三星回复延迟结束时间区间
|
||||
COMMENTS_SCORE_FOUR_ORFIVE_BEGIN_DELAY_TIME = 2 * 60 //评论回复四星或五星回复延迟开始时间区间
|
||||
COMMENTS_SCORE_FOUR_ORFIVE_END_DELAY_TIME = 5 * 60 //评论回复四星或五星回复延迟结束时间区间
|
||||
|
||||
MAX_REAPLY_TIME = 18 * time.Hour
|
||||
)
|
||||
|
||||
type tReplyConfig struct {
|
||||
delayGapBegin int
|
||||
delayGapEnd int
|
||||
comments []string
|
||||
}
|
||||
|
||||
var (
|
||||
replyConfig = map[int]*tReplyConfig{
|
||||
1: &tReplyConfig{
|
||||
delayGapBegin: COMMENTS_SCORE_ONE_ORTWO_BEGIN_DELAY_TIME,
|
||||
delayGapEnd: COMMENTS_SCORE_ONE_ORTWO_END_DELAY_TIME,
|
||||
comments: []string{
|
||||
"非常抱歉让您没有得到十分满意的购物体验,我们会及时与您联系进行确认并解决问题!",
|
||||
},
|
||||
},
|
||||
3: &tReplyConfig{
|
||||
delayGapBegin: COMMENTS_SCORE_THREE_BEGIN_DELAY_TIME,
|
||||
delayGapEnd: COMMENTS_SCORE_THREE_END_DELAY_TIME,
|
||||
comments: []string{
|
||||
"感谢您对我们的肯定,祝您生活愉快!欢迎再次光临,谢谢!",
|
||||
fmt.Sprintf("感谢您对%s的关照,我们会更加精益求精。", globals.StoreName),
|
||||
"感谢您的光临,您的支持是我们前进的动力!",
|
||||
},
|
||||
},
|
||||
4: &tReplyConfig{
|
||||
delayGapBegin: COMMENTS_SCORE_FOUR_ORFIVE_BEGIN_DELAY_TIME,
|
||||
delayGapEnd: COMMENTS_SCORE_FOUR_ORFIVE_END_DELAY_TIME,
|
||||
comments: []string{
|
||||
"感谢您的信赖!我们会不断提升菜品质量以及优质的服务,期待与您的再次相遇!",
|
||||
"感谢您的支持,愿您天天好心情!",
|
||||
"感谢您的认可!您的支持是我们前进的动力。",
|
||||
"感谢您的肯定与支持!我们会坚持把最好的服务带给您,期待和您的再次相遇!",
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
func (c *OrderManager) OnOrderComments(orderCommentList []*model.OrderComment) (err error) {
|
||||
globals.SugarLogger.Debug("OnOrderComments")
|
||||
db := dao.GetDB()
|
||||
for _, orderComment := range orderCommentList {
|
||||
globals.SugarLogger.Debugf("OnOrderComments, orderID:%s", orderComment.VendorOrderID)
|
||||
comment2 := &legacymodel.JxBadComments{
|
||||
OrderId: orderComment.VendorOrderID,
|
||||
}
|
||||
err = dao.GetEntity(db, comment2, "OrderId")
|
||||
if err == nil || dao.IsNoRowsError(err) {
|
||||
isNewComment := false
|
||||
if dao.IsNoRowsError(err) {
|
||||
err = nil
|
||||
isNewComment = true
|
||||
if orderComment.IsReplied == 0 && time.Now().Sub(orderComment.CommentCreatedAt) < time.Duration(orderComment.ModifyDuration)*time.Hour {
|
||||
if storeDetail, err2 := dao.GetStoreDetail(db, orderComment.StoreID, orderComment.VendorID); err2 == nil {
|
||||
if storeDetail.AutoReplyType == model.AutoReplyAll ||
|
||||
orderComment.Score > JX_BAD_COMMENTS_MAX_LEVEL && storeDetail.AutoReplyType == model.AutoReplyGoodComment {
|
||||
c.replyOrderComment(storeDetail.VendorOrgCode, orderComment)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if isNewComment /*&& orderComment.Score <= JX_BAD_COMMENTS_MAX_LEVEL*/ || !isNewComment && orderComment.Score > JX_BAD_COMMENTS_MAX_LEVEL { // 如果是直接非差评,或补评仍然是差评,忽略
|
||||
if isNewComment {
|
||||
comment2.Createtime = utils.Time2Str(orderComment.CommentCreatedAt)
|
||||
comment2.Score = int(orderComment.Score)
|
||||
comment2.Scorecontent = orderComment.Content
|
||||
comment2.Vendertags = orderComment.TagList
|
||||
comment2.Msg = orderComment.OriginalMsg
|
||||
|
||||
comment2.Status = COMMENT_NOT_RESOLVED
|
||||
comment2.OrderFlag = utils.Int2Str(orderComment.VendorID)
|
||||
comment2.Maxmodifytime = int(orderComment.ModifyDuration)
|
||||
|
||||
order, _ := partner.CurOrderManager.LoadOrder(orderComment.VendorOrderID, orderComment.VendorID)
|
||||
if order != nil {
|
||||
orderComment.StoreID = jxutils.GetSaleStoreIDFromOrder(order)
|
||||
if order.ConsigneeMobile2 != "" {
|
||||
orderComment.ConsigneeMobile = order.ConsigneeMobile2
|
||||
} else {
|
||||
if handler := partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID); handler != nil {
|
||||
if order2, _ := handler.GetOrder(order.VendorOrgCode, order.VendorOrderID); order2 != nil && order.ConsigneeMobile != order2.ConsigneeMobile {
|
||||
order.ConsigneeMobile = order2.ConsigneeMobile
|
||||
partner.CurOrderManager.UpdateOrderFields(order, []string{"ConsigneeMobile"})
|
||||
}
|
||||
}
|
||||
orderComment.ConsigneeMobile = order.ConsigneeMobile
|
||||
}
|
||||
} else {
|
||||
if storeDetail, err := dao.GetStoreDetailByVendorStoreID(db, orderComment.VendorStoreID, orderComment.VendorID); err == nil {
|
||||
orderComment.StoreID = storeDetail.ID
|
||||
}
|
||||
}
|
||||
if orderComment.StoreID > 0 {
|
||||
comment2.Jxstoreid = utils.Int2Str(orderComment.StoreID)
|
||||
}
|
||||
comment2.Userphone = orderComment.ConsigneeMobile
|
||||
if comment2.Jxstoreid != "" && orderComment.Score <= JX_MIDDLE_COMMENTS_MAX_LEVEL && time.Now().Sub(orderComment.CommentCreatedAt) < MAX_REAPLY_TIME {
|
||||
comment2.LastPushTime = utils.Time2Str(time.Now())
|
||||
comment2.PushNo = 1
|
||||
weixinmsg.PushJDBadCommentToWeiXin(comment2, orderComment.Score <= JX_BAD_COMMENTS_MAX_LEVEL, order)
|
||||
}
|
||||
} else { // 修改评价,高于JX_BAD_COMMENTS_MAX_LEVEL
|
||||
if orderComment.CommentCreatedAt.Sub(str2Time(comment2.Createtime)) == 0 ||
|
||||
orderComment.CommentCreatedAt.Sub(str2Time(comment2.Updatetime)) == 0 {
|
||||
comment2 = nil // 重复
|
||||
} else {
|
||||
comment2.Updatetime = utils.Time2Str(orderComment.CommentCreatedAt)
|
||||
comment2.UpdatedMsg = orderComment.OriginalMsg
|
||||
comment2.UpdatedScore = int(orderComment.Score)
|
||||
comment2.UpdatedScorecontent = orderComment.Content
|
||||
comment2.UpdatedVendertags = orderComment.TagList
|
||||
comment2.Status = COMMENT_RESOLVED
|
||||
|
||||
if comment2.Jxstoreid != "" && orderComment.Score <= JX_MIDDLE_COMMENTS_MAX_LEVEL && time.Now().Sub(orderComment.CommentCreatedAt) < MAX_REAPLY_TIME {
|
||||
comment2.LastPushTime = utils.Time2Str(time.Now())
|
||||
comment2.PushNo++
|
||||
|
||||
comment3 := *comment2
|
||||
comment3.Createtime = comment2.Updatetime
|
||||
comment3.Score = comment2.UpdatedScore
|
||||
comment3.Scorecontent = comment2.UpdatedScorecontent
|
||||
comment3.Vendertags = comment2.UpdatedVendertags
|
||||
order, _ := partner.CurOrderManager.LoadOrder(orderComment.VendorOrderID, orderComment.VendorID)
|
||||
weixinmsg.PushJDBadCommentToWeiXin(&comment3, orderComment.Score <= JX_BAD_COMMENTS_MAX_LEVEL, order)
|
||||
}
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
if isNewComment {
|
||||
err = dao.CreateEntity(db, comment2)
|
||||
} else if comment2 != nil {
|
||||
_, err = dao.UpdateEntity(db, comment2)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
globals.SugarLogger.Warnf("OnOrderComments orderID:%s failed with error:%v", orderComment.VendorOrderID, err)
|
||||
break
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *OrderManager) replyOrderComment(vendorOrgCode string, orderComment *model.OrderComment) (err error) {
|
||||
score := int(orderComment.Score)
|
||||
if score <= 2 {
|
||||
score = 1
|
||||
} else if score >= 5 {
|
||||
score = 4
|
||||
}
|
||||
config := replyConfig[score]
|
||||
delaySeconds := config.delayGapBegin + rand.Intn(config.delayGapEnd-config.delayGapBegin)
|
||||
content := config.comments[rand.Intn(len(config.comments))]
|
||||
globals.SugarLogger.Debugf("replyOrderComment orderID:%s, delaySeconds:%d, content:%s", orderComment.VendorOrderID, delaySeconds, content)
|
||||
utils.AfterFuncWithRecover(time.Duration(delaySeconds)*time.Second, func() {
|
||||
if handler := partner.GetPurchaseOrderHandlerFromVendorID(orderComment.VendorID); handler != nil {
|
||||
if err = handler.ReplyOrderComment(jxcontext.AdminCtx, vendorOrgCode, orderComment, content); err != nil {
|
||||
globals.SugarLogger.Debugf("replyOrderComment orderID:%s, error:%v", orderComment.VendorOrderID, err)
|
||||
}
|
||||
} else {
|
||||
globals.SugarLogger.Warnf("replyOrderComment can not find handler orderID:%s", orderComment.VendorOrderID)
|
||||
}
|
||||
})
|
||||
// todo 这里直接延时,可以导致服务器重启时漏掉回复,但如果用管理任务,又会导致大量评价任务存在与任务列表中
|
||||
// task := tasksch.NewParallelTask(fmt.Sprintf("回复订单:%s评价", orderComment.VendorOrderID), nil, jxcontext.AdminCtx,
|
||||
// func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
// return retVal, err
|
||||
// }, []int{0})
|
||||
// tasksch.HandleTask(task, nil, true).Run()
|
||||
return err
|
||||
}
|
||||
|
||||
func str2Time(timeStr string) time.Time {
|
||||
if timeStr == "" {
|
||||
return utils.DefaultTimeValue
|
||||
}
|
||||
return utils.Str2Time(timeStr)
|
||||
}
|
||||
@@ -1,180 +0,0 @@
|
||||
package orderman
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxcallback/scheduler"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
)
|
||||
|
||||
const (
|
||||
pendingOrderGapMax = 2 * 24 * time.Hour // 每次重启机子时,要检查几天内的订单状态
|
||||
maxTimeHandlePendingOrder = 2 * time.Second //处理pending order的最长时间
|
||||
maxSleepGapHandlePendingOrder = 5 * time.Millisecond // 每个pending order的最长时间间隙
|
||||
)
|
||||
|
||||
var (
|
||||
ErrCanNotFindOrder = errors.New("找不到相应订单")
|
||||
ErrCanNotFindWaybill = errors.New("找不到相应运单")
|
||||
)
|
||||
|
||||
var (
|
||||
FixedOrderManager *OrderManager
|
||||
)
|
||||
|
||||
// 所有公共接口调用前,要求在order里或status中设置合适的Status
|
||||
type OrderManager struct {
|
||||
}
|
||||
|
||||
func NewOrderManager() *OrderManager {
|
||||
return &OrderManager{}
|
||||
}
|
||||
|
||||
type IStatusTimer interface {
|
||||
GetStatusTime() time.Time
|
||||
}
|
||||
|
||||
type StatusTimerSlice []IStatusTimer
|
||||
|
||||
func (s StatusTimerSlice) Len() int {
|
||||
return len(s)
|
||||
}
|
||||
|
||||
func (s StatusTimerSlice) Less(i, j int) bool {
|
||||
return s[i].GetStatusTime().Sub(s[j].GetStatusTime()) < 0
|
||||
}
|
||||
|
||||
func (s StatusTimerSlice) Swap(i, j int) {
|
||||
tmp := s[i]
|
||||
s[i] = s[j]
|
||||
s[j] = tmp
|
||||
}
|
||||
|
||||
func init() {
|
||||
FixedOrderManager = NewOrderManager()
|
||||
partner.InitOrderManager(FixedOrderManager)
|
||||
}
|
||||
|
||||
func addOrderOrWaybillStatus(status *model.OrderStatus, db *dao.DaoDB) (isDuplicated bool, err error) {
|
||||
if status.OrderType == model.OrderTypeOrder {
|
||||
globals.SugarLogger.Debugf("addOrderStatus order:%v", status)
|
||||
} else if status.OrderType == model.OrderTypeWaybill {
|
||||
globals.SugarLogger.Debugf("addOrderStatus waybill:%v", status)
|
||||
} else {
|
||||
globals.SugarLogger.Debugf("addOrderStatus afsOrder:%v", status)
|
||||
}
|
||||
dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil || err != nil {
|
||||
globals.SugarLogger.Debug("rollback")
|
||||
dao.Rollback(db)
|
||||
if r != nil {
|
||||
panic(r)
|
||||
}
|
||||
}
|
||||
}()
|
||||
status.ID = 0
|
||||
status.Remark = utils.LimitUTF8StringLen(status.Remark, 255)
|
||||
created, _, err := db.Db.ReadOrCreate(status, "VendorOrderID", "VendorID", "OrderType", "Status", "VendorStatus", "StatusTime")
|
||||
if err == nil {
|
||||
if !created {
|
||||
globals.SugarLogger.Debugf("duplicated event:%v", status)
|
||||
isDuplicated = true
|
||||
status.DuplicatedCount++
|
||||
utils.CallFuncLogError(func() error {
|
||||
_, err = db.Db.Update(status, "DuplicatedCount")
|
||||
return err
|
||||
}, "addOrderOrWaybillStatus update DuplicatedCount, status:%v", status)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
// todo 这里居然会有主键重复错误,逻辑上是不应该的
|
||||
globals.SugarLogger.Warnf("addOrderOrWaybillStatus status:%v, access db error:%v", status, err)
|
||||
} else {
|
||||
dao.Commit(db)
|
||||
}
|
||||
return isDuplicated, err
|
||||
}
|
||||
|
||||
func (c *OrderManager) GetStatusDuplicatedCount(status *model.OrderStatus) (duplicatedCount int) {
|
||||
if status == nil {
|
||||
return 0
|
||||
}
|
||||
db := dao.GetDB()
|
||||
if err := dao.GetEntity(db, status, "VendorOrderID", "VendorID", "OrderType", "VendorStatus", "StatusTime"); err == nil {
|
||||
return status.DuplicatedCount
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// todo 最好还是改成全事件回放算了
|
||||
func LoadPendingOrders() {
|
||||
orders, err := dao.LoadPendingOrders(dao.GetDB(), time.Now().Add(-pendingOrderGapMax), model.OrderStatusEndBegin)
|
||||
globals.SugarLogger.Infof("LoadPendingOrders orders count:%d, err:%v", len(orders), err)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
ordersCount := len(orders)
|
||||
if ordersCount > 0 {
|
||||
bills := FixedOrderManager.LoadPendingWaybills()
|
||||
globals.SugarLogger.Infof("LoadPendingOrders waybills count:%d", len(bills))
|
||||
var sortOrders StatusTimerSlice
|
||||
orderMap := make(map[string]*model.GoodsOrder)
|
||||
for _, order := range orders {
|
||||
if order.Status > model.OrderStatusNew {
|
||||
status := model.Order2Status(order)
|
||||
sortOrders = append(sortOrders, status)
|
||||
}
|
||||
// order.Status = model.OrderStatusNew // 就是要以实际order状态来调用scheduler.OnOrderNew
|
||||
order.StatusTime = order.OrderCreatedAt
|
||||
sortOrders = append(sortOrders, order)
|
||||
orderMap[jxutils.ComposeUniversalOrderID(order.VendorOrderID, order.VendorID)] = order
|
||||
}
|
||||
for _, bill := range bills {
|
||||
if bill.Status > model.WaybillStatusNew {
|
||||
bill2 := *bill
|
||||
sortOrders = append(sortOrders, &bill2)
|
||||
}
|
||||
bill.Status = model.WaybillStatusNew
|
||||
bill.StatusTime = bill.WaybillCreatedAt
|
||||
sortOrders = append(sortOrders, bill)
|
||||
}
|
||||
sort.Sort(sortOrders)
|
||||
sleepGap := maxTimeHandlePendingOrder / time.Duration(ordersCount)
|
||||
if sleepGap > maxSleepGapHandlePendingOrder {
|
||||
sleepGap = maxSleepGapHandlePendingOrder
|
||||
}
|
||||
lastTime := time.Now()
|
||||
for _, item := range sortOrders {
|
||||
if order, ok := item.(*model.GoodsOrder); ok {
|
||||
jxutils.CallMsgHandlerAsync(func() {
|
||||
scheduler.CurrentScheduler.OnOrderNew(order, true)
|
||||
}, jxutils.ComposeUniversalOrderID(order.VendorOrderID, order.VendorID))
|
||||
} else if status, ok := item.(*model.OrderStatus); ok {
|
||||
jxutils.CallMsgHandlerAsync(func() {
|
||||
order := orderMap[jxutils.ComposeUniversalOrderID(status.VendorOrderID, status.VendorID)]
|
||||
scheduler.CurrentScheduler.OnOrderStatusChanged(order, status, true)
|
||||
}, jxutils.ComposeUniversalOrderID(status.RefVendorOrderID, status.RefVendorID))
|
||||
} else {
|
||||
bill := item.(*model.Waybill)
|
||||
jxutils.CallMsgHandlerAsync(func() {
|
||||
scheduler.CurrentScheduler.OnWaybillStatusChanged(bill, true)
|
||||
}, jxutils.ComposeUniversalOrderID(bill.VendorOrderID, bill.OrderVendorID))
|
||||
}
|
||||
curTime := time.Now()
|
||||
timeout := sleepGap - curTime.Sub(lastTime)
|
||||
if timeout > 0 {
|
||||
time.Sleep(timeout)
|
||||
}
|
||||
lastTime = curTime
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,17 +0,0 @@
|
||||
package orderman
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/jx-callback/globals/api2"
|
||||
"git.rosy.net.cn/jx-callback/globals/testinit"
|
||||
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/ebai"
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/elm"
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/jd"
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/mtwm"
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/weimob/wsc"
|
||||
)
|
||||
|
||||
func init() {
|
||||
testinit.Init()
|
||||
api2.Init()
|
||||
}
|
||||
@@ -1,265 +0,0 @@
|
||||
package orderman
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/dadaapi"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxcallback/scheduler"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"github.com/astaxie/beego/orm"
|
||||
)
|
||||
|
||||
var (
|
||||
waybillOrderStatusMap = map[int]int{
|
||||
model.WaybillStatusApplyFailedGetGoods: model.OrderStatusApplyFailedGetGoods,
|
||||
model.WaybillStatusAgreeFailedGetGoods: model.OrderStatusAgreeFailedGetGoods,
|
||||
model.WaybillStatusRefuseFailedGetGoods: model.OrderStatusRefuseFailedGetGoods,
|
||||
model.WaybillStatusDeliverFailed: model.OrderStatusDeliverFailed,
|
||||
}
|
||||
complaintReasonsMap = map[int]string{
|
||||
1: "骑手态度恶劣",
|
||||
2: "骑手接单后未取货",
|
||||
3: "骑手取货太慢",
|
||||
4: "骑手送货太慢",
|
||||
5: "货品未送达",
|
||||
6: "货品有损坏",
|
||||
7: "骑手违规收取顾客其他费用",
|
||||
69: "骑手恶意取消订单",
|
||||
71: "骑手提前点击取货/送达",
|
||||
}
|
||||
)
|
||||
|
||||
func (w *OrderManager) LoadPendingWaybills() []*model.Waybill {
|
||||
db := orm.NewOrm()
|
||||
var bills []*model.Waybill
|
||||
tillTime := time.Now().Add(-pendingOrderGapMax)
|
||||
_, err := db.Raw(`
|
||||
SELECT t1.*
|
||||
FROM waybill t1
|
||||
JOIN goods_order t2 ON t2.vendor_order_id = t1.vendor_order_id
|
||||
AND t2.vendor_id = t1.order_vendor_id
|
||||
AND t2.order_created_at >= ?
|
||||
AND t2.status < ?
|
||||
WHERE t1.waybill_created_at >= ?
|
||||
AND t1.status < ?
|
||||
`, tillTime, model.OrderStatusEndBegin, tillTime, model.WaybillStatusEndBegin).QueryRows(&bills)
|
||||
if err != nil {
|
||||
globals.SugarLogger.Warnf("LoadPendingWaybills load pending waybills error:%v", err)
|
||||
return nil
|
||||
}
|
||||
return bills
|
||||
}
|
||||
|
||||
func (w *OrderManager) onWaybillNew(bill2 *model.Waybill, db *dao.DaoDB) (isDuplicated bool, err error) {
|
||||
globals.SugarLogger.Debugf("onWaybillNew bill:%v", bill2)
|
||||
isDuplicated, err = addOrderOrWaybillStatus(model.Waybill2Status(bill2), db)
|
||||
if err == nil && !isDuplicated {
|
||||
bill2.ID = 0
|
||||
bill2.WaybillCreatedAt = bill2.StatusTime
|
||||
bill2.WaybillFinishedAt = utils.DefaultTimeValue
|
||||
billCopied := *bill2
|
||||
bill := &billCopied
|
||||
created, _, err2 := db.Db.ReadOrCreate(bill, "VendorWaybillID", "WaybillVendorID")
|
||||
if err = err2; err == nil {
|
||||
if !created {
|
||||
bill.DuplicatedCount++
|
||||
if bill2.VendorOrderID == bill2.VendorWaybillID { // 购物平台(比如京东)重新建的运单,单号始终是与订单相同的
|
||||
globals.SugarLogger.Infof("onWaybillNew duplicated1, DuplicatedCount:%d, bill:%v msg received", bill2.DuplicatedCount, bill2)
|
||||
bill2.ID = bill.ID
|
||||
bill2.CreatedAt = bill.CreatedAt
|
||||
bill2.DuplicatedCount = bill.DuplicatedCount
|
||||
err = utils.CallFuncLogError(func() error {
|
||||
_, err = db.Db.Update(bill2) //更新所有字段
|
||||
return err
|
||||
}, "onWaybillNew Update1")
|
||||
} else {
|
||||
globals.SugarLogger.Infof("onWaybillNew duplicated2 DuplicatedCount:%d, bill:%v msg received", bill.DuplicatedCount, bill2)
|
||||
isDuplicated = true
|
||||
err = utils.CallFuncLogError(func() error {
|
||||
_, err = db.Db.Update(bill, "DuplicatedCount")
|
||||
return err
|
||||
}, "onWaybillNew Update2")
|
||||
}
|
||||
} else {
|
||||
*bill2 = *bill
|
||||
globals.SugarLogger.Debugf("onWaybillNew created bill:%v", bill2)
|
||||
}
|
||||
} else {
|
||||
globals.SugarLogger.Warnf("onWaybillNew create bill:%v, error:%v", bill2, err)
|
||||
}
|
||||
}
|
||||
return isDuplicated, err
|
||||
}
|
||||
|
||||
func (w *OrderManager) OnWaybillStatusChanged(bill *model.Waybill) (err error) {
|
||||
var isDuplicated bool
|
||||
if bill.ActualFee == 0 {
|
||||
bill.ActualFee = bill.DesiredFee + bill.TipFee
|
||||
}
|
||||
bill.CourierMobile = jxutils.FormalizeMobile(bill.CourierMobile)
|
||||
db := dao.GetDB()
|
||||
dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
dao.Rollback(db)
|
||||
panic(r)
|
||||
}
|
||||
}()
|
||||
duplicatedCount := 0
|
||||
if bill.Status == model.WaybillStatusNew {
|
||||
isDuplicated, err = w.onWaybillNew(bill, db)
|
||||
if isDuplicated {
|
||||
duplicatedCount = 1
|
||||
}
|
||||
} else {
|
||||
existingBill, err2 := w.LoadWaybill(bill.VendorWaybillID, bill.WaybillVendorID)
|
||||
// todo
|
||||
if err2 == nil {
|
||||
bill.DeliveryFlag = existingBill.DeliveryFlag
|
||||
}
|
||||
if bill.Status == model.WaybillStatusAccepted { // 处理美团配送丢失新运单消息的情况
|
||||
if err2 != nil {
|
||||
if dao.IsNoRowsError(err2) || err2 == ErrCanNotFindWaybill {
|
||||
existingBill = bill
|
||||
billCopy := *bill
|
||||
billCopy.Status = model.WaybillStatusNew
|
||||
if isDuplicated, err = w.onWaybillNew(&billCopy, db); err != nil {
|
||||
dao.Rollback(db)
|
||||
return err
|
||||
}
|
||||
dao.Commit(db)
|
||||
// 进运单调度器OnWaybillStatusChanged之前要确保事务是提交了的,否则会导致死锁
|
||||
scheduler.CurrentScheduler.OnWaybillStatusChanged(&billCopy, false)
|
||||
dao.Begin(db)
|
||||
} else {
|
||||
dao.Rollback(db)
|
||||
return err2
|
||||
}
|
||||
}
|
||||
// 运单消息错序,之前已经结束了,直接返回
|
||||
if existingBill.Status >= model.WaybillStatusEndBegin {
|
||||
dao.Commit(db)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
addParams := orm.Params{}
|
||||
if bill.Status >= model.WaybillStatusAccepted {
|
||||
if bill.Status == model.WaybillStatusAccepted {
|
||||
if bill.DesiredFee > 0 {
|
||||
addParams["desired_fee"] = bill.DesiredFee
|
||||
}
|
||||
if bill.ActualFee > 0 {
|
||||
addParams["actual_fee"] = bill.ActualFee
|
||||
}
|
||||
}
|
||||
if bill.CourierMobile != "" {
|
||||
addParams["courier_name"] = bill.CourierName
|
||||
addParams["courier_mobile"] = bill.CourierMobile
|
||||
}
|
||||
if bill.Status >= model.WaybillStatusEndBegin {
|
||||
addParams["waybill_finished_at"] = bill.StatusTime
|
||||
}
|
||||
}
|
||||
duplicatedCount, err = w.addWaybillStatus(bill, db, addParams)
|
||||
if err != nil {
|
||||
dao.Rollback(db)
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
dao.Commit(db)
|
||||
if duplicatedCount == 0 {
|
||||
scheduler.CurrentScheduler.OnWaybillStatusChanged(bill, false)
|
||||
}
|
||||
} else {
|
||||
dao.Rollback(db)
|
||||
}
|
||||
if bill.VendorOrderID == bill.VendorWaybillID {
|
||||
if status, ok := waybillOrderStatusMap[bill.Status]; ok {
|
||||
fakeOrderStatus := &model.OrderStatus{
|
||||
VendorOrderID: bill.VendorOrderID,
|
||||
VendorID: bill.OrderVendorID,
|
||||
OrderType: model.OrderTypeOrder,
|
||||
RefVendorOrderID: bill.VendorOrderID,
|
||||
RefVendorID: bill.OrderVendorID,
|
||||
Status: status,
|
||||
VendorStatus: bill.VendorStatus,
|
||||
StatusTime: bill.StatusTime,
|
||||
Remark: bill.Remark,
|
||||
}
|
||||
w.OnOrderStatusChanged(bill.VendorOrgCode, fakeOrderStatus)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (w *OrderManager) addWaybillStatus(bill *model.Waybill, db *dao.DaoDB, addParams orm.Params) (duplicatedCount int, err error) {
|
||||
waybillStatus := model.Waybill2Status(bill)
|
||||
isDuplicated, err := addOrderOrWaybillStatus(waybillStatus, db)
|
||||
if err == nil && !isDuplicated {
|
||||
if waybillStatus.Status > model.WaybillStatusUnknown { // todo 这里应该和addOrderStatus一样的改法,状态不能回绕
|
||||
params := utils.MergeMaps(orm.Params{
|
||||
"status": bill.Status,
|
||||
"vendor_status": bill.VendorStatus,
|
||||
"status_time": bill.StatusTime,
|
||||
}, addParams)
|
||||
utils.CallFuncLogError(func() error {
|
||||
_, err = db.Db.QueryTable("waybill").Filter("vendor_waybill_id", bill.VendorWaybillID).Filter("waybill_vendor_id", bill.WaybillVendorID).Filter("status__lte", bill.Status).Update(params)
|
||||
return err
|
||||
}, "addWaybillStatus update waybill status, bill:%v", bill)
|
||||
} else {
|
||||
duplicatedCount = -1
|
||||
}
|
||||
} else {
|
||||
duplicatedCount = 1
|
||||
}
|
||||
return duplicatedCount, err
|
||||
}
|
||||
|
||||
func (c *OrderManager) LoadWaybill(vendorWaybillID string, waybillVendorID int) (bill *model.Waybill, err error) {
|
||||
db := orm.NewOrm()
|
||||
bill = &model.Waybill{
|
||||
VendorWaybillID: vendorWaybillID,
|
||||
WaybillVendorID: waybillVendorID,
|
||||
}
|
||||
if err = db.Read(bill, "VendorWaybillID", "WaybillVendorID"); err != nil {
|
||||
bill = nil
|
||||
if err == orm.ErrNoRows {
|
||||
err = ErrCanNotFindWaybill
|
||||
}
|
||||
globals.SugarLogger.Infof("LoadWaybill vendorWaybillID:%s failed with error:%v", vendorWaybillID, err)
|
||||
}
|
||||
return bill, err
|
||||
}
|
||||
|
||||
func GetComplaintReasons() (complaintReasonList []*dadaapi.ComplaintReason) {
|
||||
for k, v := range complaintReasonsMap {
|
||||
complaintReason := &dadaapi.ComplaintReason{
|
||||
ID: k,
|
||||
Reason: v,
|
||||
}
|
||||
complaintReasonList = append(complaintReasonList, complaintReason)
|
||||
}
|
||||
return complaintReasonList
|
||||
}
|
||||
|
||||
func ComplaintRider(ctx *jxcontext.Context, vendorOrderID string, vendorID, waybillVendorID, complaintID int) (err error) {
|
||||
db := dao.GetDB()
|
||||
p := partner.GetDeliveryPlatformFromVendorID(waybillVendorID).Handler
|
||||
wayBillList, err := dao.GetWayBillByOrderID(db, 0, vendorID, waybillVendorID, vendorOrderID)
|
||||
if err == nil && len(wayBillList) > 0 {
|
||||
err = p.ComplaintRider(wayBillList[0], complaintID, complaintReasonsMap[complaintID])
|
||||
} else {
|
||||
return fmt.Errorf("未查询到到相关订单!订单号:[%v] ,厂商:[%v],运送厂商:[%v]", vendorOrderID, vendorID, waybillVendorID)
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -1,200 +0,0 @@
|
||||
package basesch
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxcallback/scheduler"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
)
|
||||
|
||||
var (
|
||||
FixedBaseScheduler *BaseScheduler
|
||||
)
|
||||
|
||||
type BaseScheduler struct {
|
||||
IsReallyCallPlatformAPI bool
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) AcceptOrRefuseOrder(order *model.GoodsOrder, isAcceptIt bool, userName string) (err error) {
|
||||
globals.SugarLogger.Infof("AcceptOrRefuseOrder orderID:%s, isAcceptIt:%t", order.VendorOrderID, isAcceptIt)
|
||||
if /*order.LockStatus == model.OrderStatusUnknown && */ order.Status == model.OrderStatusNew || order.Status == model.OrderStatusWaitAccepted {
|
||||
if c.IsReallyCallPlatformAPI {
|
||||
err = utils.CallFuncLogErrorWithInfo(func() error {
|
||||
return partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID).AcceptOrRefuseOrder(order, isAcceptIt, userName)
|
||||
}, "AcceptOrRefuseOrder orderID:%s, isAcceptIt:%t", order.VendorOrderID, isAcceptIt)
|
||||
}
|
||||
} else {
|
||||
return scheduler.ErrOrderStatusAlreadySatisfyCurOperation
|
||||
globals.SugarLogger.Debugf("AcceptOrRefuseOrder orderID:%s, status:%d is not suitable, isAcceptIt:%t", order.VendorOrderID, order.Status, isAcceptIt)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) PickupGoods(order *model.GoodsOrder, isSelfDelivery bool, userName string) (err error) {
|
||||
globals.SugarLogger.Infof("PickupGoods orderID:%s", order.VendorOrderID)
|
||||
if /*order.LockStatus == model.OrderStatusUnknown && */ order.Status == model.OrderStatusAccepted {
|
||||
if c.IsReallyCallPlatformAPI {
|
||||
handler := partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID)
|
||||
err = utils.CallFuncLogErrorWithInfo(func() (err error) {
|
||||
if err = handler.PickupGoods(order, isSelfDelivery, userName); err != nil {
|
||||
if status, err2 := handler.GetOrderStatus(order.VendorOrgCode, order.VendorOrderID); err2 == nil && status >= model.OrderStatusFinished {
|
||||
err = nil
|
||||
}
|
||||
}
|
||||
return err
|
||||
}, "PickupGoods orderID:%s", order.VendorOrderID)
|
||||
}
|
||||
} else {
|
||||
if order.LockStatus != model.OrderStatusUnknown || order.Status < model.OrderStatusAccepted {
|
||||
err = scheduler.ErrOrderStatusIsNotSuitable4CurOperation
|
||||
globals.SugarLogger.Infof("PickupGoods orderID:%s, status:%d is not suitable", order.VendorOrderID, order.Status)
|
||||
} else {
|
||||
err = scheduler.ErrOrderStatusAlreadySatisfyCurOperation
|
||||
globals.SugarLogger.Debugf("PickupGoods orderID:%s status:%d already ok", order.VendorOrderID, order.Status)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) Swtich2SelfDeliver(order *model.GoodsOrder, userName string) (err error) {
|
||||
globals.SugarLogger.Infof("Swtich2SelfDeliver orderID:%s", order.VendorOrderID)
|
||||
if /*order.LockStatus == model.OrderStatusUnknown && */ order.Status >= model.OrderStatusFinishedPickup && order.Status <= model.OrderStatusDelivering {
|
||||
if order.DeliveryFlag&model.OrderDeliveryFlagMaskPurcahseDisabled == 0 && c.IsReallyCallPlatformAPI {
|
||||
err = utils.CallFuncLogErrorWithInfo(func() error {
|
||||
return partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID).Swtich2SelfDeliver(order, userName)
|
||||
}, "Swtich2SelfDeliver orderID:%s", order.VendorOrderID)
|
||||
}
|
||||
if err == nil { // 因为有些平台转自送后,不会再发送订单在配送中消息过来,所以成功后就强制设置状态为配送中
|
||||
order.Status = model.OrderStatusDelivering
|
||||
order.DeliveryFlag |= model.OrderDeliveryFlagMaskPurcahseDisabled
|
||||
err = partner.CurOrderManager.UpdateOrderStatusAndDeliveryFlag(order)
|
||||
}
|
||||
} else {
|
||||
if order.LockStatus != model.OrderStatusUnknown || order.Status < model.OrderStatusFinishedPickup || order.VendorID == order.WaybillVendorID {
|
||||
err = scheduler.ErrOrderStatusIsNotSuitable4CurOperation
|
||||
globals.SugarLogger.Infof("Swtich2SelfDeliver orderID:%s, status:%d is not suitable", order.VendorOrderID, order.Status)
|
||||
} else {
|
||||
err = scheduler.ErrOrderStatusAlreadySatisfyCurOperation
|
||||
globals.SugarLogger.Debugf("Swtich2SelfDeliver orderID:%s status:%d already ok", order.VendorOrderID, order.Status)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) Swtich2SelfDelivered(order *model.GoodsOrder, userName string) (err error) {
|
||||
globals.SugarLogger.Infof("Swtich2SelfDelivered orderID:%s", order.VendorOrderID)
|
||||
if /*order.LockStatus == model.OrderStatusUnknown && */ order.Status == model.OrderStatusDelivering {
|
||||
if c.IsReallyCallPlatformAPI {
|
||||
err = utils.CallFuncLogError(func() error {
|
||||
return partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID).Swtich2SelfDelivered(order, userName)
|
||||
}, "Swtich2SelfDelivered orderID:%s", order.VendorOrderID)
|
||||
}
|
||||
} else {
|
||||
if order.LockStatus != model.OrderStatusUnknown || order.Status < model.OrderStatusDelivering {
|
||||
err = scheduler.ErrOrderStatusIsNotSuitable4CurOperation
|
||||
globals.SugarLogger.Infof("Swtich2SelfDelivered orderID:%s, status:%d is not suitable", order.VendorOrderID, order.Status)
|
||||
} else {
|
||||
err = scheduler.ErrOrderStatusAlreadySatisfyCurOperation
|
||||
globals.SugarLogger.Debugf("Swtich2SelfDelivered orderID:%s status:%d already ok", order.VendorOrderID, order.Status)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) SelfDeliverDelivering(order *model.GoodsOrder, userName string) (err error) {
|
||||
globals.SugarLogger.Infof("SelfDeliverDelivering orderID:%s", order.VendorOrderID)
|
||||
if /*order.LockStatus == model.OrderStatusUnknown && */ order.Status == model.OrderStatusFinishedPickup {
|
||||
if c.IsReallyCallPlatformAPI {
|
||||
err = utils.CallFuncLogError(func() error {
|
||||
return partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID).SelfDeliverDelivering(order, userName)
|
||||
}, "SelfDeliverDelivering orderID:%s", order.VendorOrderID)
|
||||
if err == nil { // 因为有些平台设置配送中后,不会发送订单在配送中消息过来,所以成功后就强制设置状态为配送中
|
||||
order.Status = model.OrderStatusDelivering
|
||||
err = partner.CurOrderManager.UpdateOrderStatusAndDeliveryFlag(order)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if order.LockStatus != model.OrderStatusUnknown || order.Status < model.OrderStatusFinishedPickup {
|
||||
err = scheduler.ErrOrderStatusIsNotSuitable4CurOperation
|
||||
globals.SugarLogger.Infof("SelfDeliverDelivering orderID:%s, status:%d is not suitable", order.VendorOrderID, order.Status)
|
||||
} else {
|
||||
err = scheduler.ErrOrderStatusAlreadySatisfyCurOperation
|
||||
globals.SugarLogger.Debugf("SelfDeliverDelivering orderID:%s, status:%d already ok", order.VendorOrderID, order.Status)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) SelfDeliverDelivered(order *model.GoodsOrder, userName string) (err error) {
|
||||
globals.SugarLogger.Infof("SelfDeliverDelivered orderID:%s", order.VendorOrderID)
|
||||
if /*order.LockStatus == model.OrderStatusUnknown && */ order.Status >= model.OrderStatusFinishedPickup &&
|
||||
order.Status <= model.OrderStatusDelivering {
|
||||
if c.IsReallyCallPlatformAPI {
|
||||
err = utils.CallFuncLogError(func() error {
|
||||
return partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID).SelfDeliverDelivered(order, userName)
|
||||
}, "SelfDeliverDelivered orderID:%s", order.VendorOrderID)
|
||||
}
|
||||
} else {
|
||||
if order.LockStatus != model.OrderStatusUnknown || order.Status < model.OrderStatusDelivering {
|
||||
err = scheduler.ErrOrderStatusIsNotSuitable4CurOperation
|
||||
globals.SugarLogger.Infof("SelfDeliverDelivered orderID:%s, status:%d is not suitable", order.VendorOrderID, order.Status)
|
||||
} else {
|
||||
err = scheduler.ErrOrderStatusAlreadySatisfyCurOperation
|
||||
globals.SugarLogger.Debugf("SelfDeliverDelivered orderID:%s, status:%d already ok", order.VendorOrderID, order.Status)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) CreateWaybill(platformVendorID int, order *model.GoodsOrder, maxDeliveryFee int64) (bill *model.Waybill, err error) {
|
||||
globals.SugarLogger.Infof("CreateWaybill orderID:%s, vendor:%s", order.VendorOrderID, jxutils.GetVendorName(platformVendorID))
|
||||
if !model.IsOrderSolid(order) { // 如果订单是不完整的
|
||||
globals.SugarLogger.Warnf("CreateWaybill orderID:%s, vendorID:%d is not solid!!!", order.VendorOrderID, platformVendorID)
|
||||
return nil, scheduler.ErrOrderIsNotSolid
|
||||
}
|
||||
// if order.DeliveryFlag&model.OrderDeliveryFlagMaskScheduleDisabled != 0 {
|
||||
// waybillList, err := partner.CurOrderManager.GetOrderWaybillInfo(jxcontext.AdminCtx, order.VendorOrderID, order.VendorID, true)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// if len(waybillList) > 0 {
|
||||
// return nil, fmt.Errorf("转商家自送的订单只允许有一个有效运单,当前已经有%s运单", jxutils.GetVendorName(waybillList[0].WaybillVendorID))
|
||||
// }
|
||||
// }
|
||||
handlerInfo := partner.GetDeliveryPlatformFromVendorID(platformVendorID)
|
||||
if handlerInfo != nil && handlerInfo.Use4CreateWaybill {
|
||||
if c.IsReallyCallPlatformAPI {
|
||||
bill, err = handlerInfo.Handler.CreateWaybill(order, maxDeliveryFee)
|
||||
if err != nil {
|
||||
globals.SugarLogger.Infof("CreateWaybill failed orderID:%s vendorID:%d with error:%v", order.VendorOrderID, platformVendorID, err)
|
||||
} else {
|
||||
order.DeliveryFlag |= model.WaybillVendorID2Mask(platformVendorID)
|
||||
err = partner.CurOrderManager.UpdateOrderStatusAndDeliveryFlag(order)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
err = scheduler.ErrDeliverProviderWrong
|
||||
}
|
||||
return bill, err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) CancelWaybill(bill *model.Waybill, cancelReasonID int, cancelReason string) (err error) {
|
||||
globals.SugarLogger.Infof("CancelWaybill bill:%v, cancelReasonID:%d cancelReason:%s", bill, cancelReasonID, cancelReason)
|
||||
// 部分快递平台在取消成功后有时会不发运单取消消息过来(比如达达,904200512000442),为避免二次取消报错,添加状态判断
|
||||
if c.IsReallyCallPlatformAPI && bill.OrderVendorID != bill.WaybillVendorID && bill.Status != model.WaybillStatusCanceled {
|
||||
if handlerInfo := partner.GetDeliveryPlatformFromVendorID(bill.WaybillVendorID); handlerInfo != nil {
|
||||
if err = utils.CallFuncLogErrorWithInfo(func() error {
|
||||
return handlerInfo.Handler.CancelWaybill(bill, cancelReasonID, cancelReason)
|
||||
}, "CancelWaybill bill:%v", bill); err == nil {
|
||||
bill.Status = model.WaybillStatusCanceled
|
||||
bill.DeliveryFlag |= model.WaybillDeliveryFlagMaskActiveCancel
|
||||
_, err = dao.UpdateEntity(nil, bill, "Status", "DeliveryFlag")
|
||||
}
|
||||
globals.SugarLogger.Debugf("CancelWaybill bill:%v canceled by myself", bill)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -1,422 +0,0 @@
|
||||
package basesch
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/jdshopapi"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/dingdingapi"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/baseapi/utils/errlist"
|
||||
"git.rosy.net.cn/jx-callback/business/jxstore/cms"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/ddmsg"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/business/partner/purchase/jd"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
)
|
||||
|
||||
const (
|
||||
autoSelfTakeCode = "135246"
|
||||
)
|
||||
|
||||
func (c *BaseScheduler) CreateWaybillOnProviders(ctx *jxcontext.Context, order *model.GoodsOrder, courierVendorIDs, excludeCourierVendorIDs []int, maxDeliveryFee int64, createOnlyOne bool) (bills []*model.Waybill, err error) {
|
||||
userName := ctx.GetUserName()
|
||||
globals.SugarLogger.Infof("CreateWaybillOnProviders orderID:%s userName:%s, courierVendorIDs:%v, excludeCourierVendorIDs:%v", order.VendorOrderID, userName, courierVendorIDs, excludeCourierVendorIDs)
|
||||
storeCourierList, err := dao.GetStoreCourierList(dao.GetDB(), []int{jxutils.GetSaleStoreIDFromOrder(order)}, nil, model.StoreStatusOpened, model.StoreAuditStatusOnline)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
courierVendorIDMap := jxutils.IntList2Map(courierVendorIDs)
|
||||
excludeCourierVendorIDMap := jxutils.IntList2Map(excludeCourierVendorIDs)
|
||||
errList := errlist.New()
|
||||
for _, storeCourier := range storeCourierList {
|
||||
if (courierVendorIDs == nil || courierVendorIDMap[storeCourier.VendorID] == 1) &&
|
||||
(excludeCourierVendorIDs == nil || excludeCourierVendorIDMap[storeCourier.VendorID] == 0) {
|
||||
if handler := partner.GetDeliveryPlatformFromVendorID(storeCourier.VendorID); handler != nil && handler.Use4CreateWaybill {
|
||||
courierVendorID := storeCourier.VendorID
|
||||
bill, err2 := c.CreateWaybill(courierVendorID, order, maxDeliveryFee)
|
||||
if err = err2; err == nil {
|
||||
globals.SugarLogger.Debugf("CreateWaybillOnProviders orderID:%s userName:%s vendorID:%d bill:%v", order.VendorOrderID, userName, courierVendorID, bill)
|
||||
bills = append(bills, bill)
|
||||
if createOnlyOne {
|
||||
break
|
||||
}
|
||||
} else {
|
||||
globals.SugarLogger.Debugf("CreateWaybillOnProviders orderID:%s userName:%s vendorID:%d failed with error:%v", order.VendorOrderID, userName, courierVendorID, err)
|
||||
errList.AddErr(fmt.Errorf("平台:%s,%s", jxutils.GetVendorName(courierVendorID), err.Error()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(bills) > 0 {
|
||||
err = errList.GetErrListAsOne()
|
||||
if err != nil {
|
||||
partner.CurOrderManager.OnOrderMsg(order, "创建三方运单部分失败", err.Error())
|
||||
}
|
||||
err = nil
|
||||
} else if errList.GetErrListAsOne() == nil {
|
||||
err = fmt.Errorf("orderID:%s没有绑定有效的三方配送门店或没有剩下可用的三方配送", order.VendorOrderID)
|
||||
} else {
|
||||
err = fmt.Errorf("orderID:%s所有运单失败:%s", order.VendorOrderID, errList.GetErrListAsOne().Error())
|
||||
}
|
||||
globals.SugarLogger.Infof("CreateWaybillOnProviders orderID:%s userName:%s error:%v", order.VendorOrderID, userName, err)
|
||||
return bills, err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) SelfDeliveredAndUpdateStatus(ctx *jxcontext.Context, vendorOrderID string, vendorID int, userName string) (err error) {
|
||||
jxutils.CallMsgHandler(func() {
|
||||
err = func() (err error) {
|
||||
globals.SugarLogger.Infof("SelfDeliveredAndUpdateStatus orderID:%s userName:%s", vendorOrderID, userName)
|
||||
order, err := partner.CurOrderManager.LoadOrder(vendorOrderID, vendorID)
|
||||
if err == nil {
|
||||
if model.IsOrderDeliveryByStore(order) {
|
||||
err = c.SelfDeliverDelivered(order, userName)
|
||||
} else if model.IsOrderDeliveryByPlatform(order) {
|
||||
err = c.Swtich2SelfDelivered(order, userName)
|
||||
}
|
||||
if err == nil {
|
||||
// order.Status = model.OrderStatusFinished // todo 是否需要强制设置完成状态?
|
||||
if err = dao.SetOrderFlag(dao.GetDB(), ctx.GetUserName(), order.VendorOrderID, order.VendorID, model.OrderFlagMaskSetDelivered); err == nil {
|
||||
globals.SugarLogger.Infof("SelfDeliveredAndUpdateStatus orderID:%s userName:%s successfully", vendorOrderID, userName)
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
globals.SugarLogger.Infof("SelfDeliveredAndUpdateStatus orderID:%s userName:%s error:%v", vendorOrderID, userName, err)
|
||||
return err
|
||||
}()
|
||||
}, jxutils.ComposeUniversalOrderID(vendorOrderID, vendorID))
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) PickupGoodsAndUpdateStatus(ctx *jxcontext.Context, vendorOrderID string, vendorID int, userName string) (err error) {
|
||||
jxutils.CallMsgHandler(func() {
|
||||
err = func() (err error) {
|
||||
globals.SugarLogger.Infof("PickupGoodsAndUpdateStatus orderID:%s userName:%s", vendorOrderID, userName)
|
||||
order, err := partner.CurOrderManager.LoadOrder(vendorOrderID, vendorID)
|
||||
if err == nil {
|
||||
err = c.PickupGoods(order, model.IsOrderDeliveryByStore(order), userName)
|
||||
if err == nil {
|
||||
order.Status = model.OrderStatusFinishedPickup
|
||||
if err = partner.CurOrderManager.UpdateOrderStatusAndDeliveryFlag(order); err == nil {
|
||||
globals.SugarLogger.Infof("PickupGoodsAndUpdateStatus orderID:%s userName:%s successfully", vendorOrderID, userName)
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
globals.SugarLogger.Infof("PickupGoodsAndUpdateStatus orderID:%s userName:%s error:%v", vendorOrderID, userName, err)
|
||||
return err
|
||||
}()
|
||||
}, jxutils.ComposeUniversalOrderID(vendorOrderID, vendorID))
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) AdjustOrder(ctx *jxcontext.Context, order *model.GoodsOrder, removedSkuList []*model.OrderSku, reason string) (err error) {
|
||||
if c.IsReallyCallPlatformAPI {
|
||||
err = partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID).AdjustOrder(ctx, order, removedSkuList, reason)
|
||||
if err == nil {
|
||||
var skuIDs []string
|
||||
for _, v := range removedSkuList {
|
||||
skuIDs = append(skuIDs, utils.Int2Str(v.SkuID))
|
||||
}
|
||||
noticeMsg := fmt.Sprintf("商品skuID列表:%v,订单号(点击进入详情):%v", strings.Join(skuIDs, ","), globals.BackstageHost+"/#/ordermanager/"+order.VendorOrderID)
|
||||
user, err := dao.GetUserByID(dao.GetDB(), "mobile", "18982250714")
|
||||
if user != nil && err == nil {
|
||||
ddmsg.SendUserMessage(dingdingapi.MsgTyeText, user.UserID, "调整单调整商品", noticeMsg)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) CancelOrder(ctx *jxcontext.Context, order *model.GoodsOrder, reason string) (err error) {
|
||||
if c.IsReallyCallPlatformAPI {
|
||||
if globals.IsAddEvent {
|
||||
err = cms.AddEventDetail(dao.GetDB(), ctx, model.OperateUpdate, order.StoreID, model.ThingTypeOrder, order.StoreID, order.VendorOrderID, order.StoreName)
|
||||
}
|
||||
err = partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID).CancelOrder(ctx, order, reason)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) AcceptOrRefuseFailedGetOrder(ctx *jxcontext.Context, order *model.GoodsOrder, isAcceptIt bool, reason string) (err error) {
|
||||
if c.IsReallyCallPlatformAPI {
|
||||
err = partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID).AcceptOrRefuseFailedGetOrder(ctx, order, isAcceptIt)
|
||||
}
|
||||
if err == nil {
|
||||
flag := model.OrderFlagAgreeFailedGetGoods
|
||||
if !isAcceptIt {
|
||||
flag = model.OrderFlagRefuseFailedGetGoods
|
||||
}
|
||||
dao.SetOrderFlag(dao.GetDB(), ctx.GetUserName(), order.VendorOrderID, order.VendorID, flag)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) CallPMCourier(ctx *jxcontext.Context, order *model.GoodsOrder) (err error) {
|
||||
if c.IsReallyCallPlatformAPI {
|
||||
err = partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID).CallCourier(ctx, order)
|
||||
}
|
||||
if err == nil {
|
||||
dao.SetOrderFlag(dao.GetDB(), ctx.GetUserName(), order.VendorOrderID, order.VendorID, model.OrderFlagMaskCallPMCourier)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) ConfirmReceiveGoods(ctx *jxcontext.Context, order *model.GoodsOrder) (err error) {
|
||||
if c.IsReallyCallPlatformAPI {
|
||||
err = partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID).ConfirmReceiveGoods(ctx, order)
|
||||
}
|
||||
if err == nil {
|
||||
dao.SetOrderFlag(dao.GetDB(), ctx.GetUserName(), order.VendorOrderID, order.VendorID, model.OrderFlagMaskFailedDeliver)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) AgreeOrRefuseCancel(ctx *jxcontext.Context, order *model.GoodsOrder, isAcceptIt bool, reason string) (err error) {
|
||||
if c.IsReallyCallPlatformAPI {
|
||||
err = partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID).AgreeOrRefuseCancel(ctx, order, isAcceptIt, reason)
|
||||
}
|
||||
if err == nil {
|
||||
flag := model.OrderFlagAgreeUserApplyCancel
|
||||
if !isAcceptIt {
|
||||
flag = model.OrderFlagRefuseUserApplyCancel
|
||||
}
|
||||
dao.SetOrderFlag(dao.GetDB(), ctx.GetUserName(), order.VendorOrderID, order.VendorID, flag)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) CancelWaybillByID(ctx *jxcontext.Context, vendorWaybillID string, waybillVendorID int, cancelReasonID int, cancelReason string) (err error) {
|
||||
bill, err := partner.CurOrderManager.LoadWaybill(vendorWaybillID, waybillVendorID)
|
||||
if err == nil {
|
||||
err = c.CancelWaybill(bill, cancelReasonID, cancelReason)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) AgreeOrRefuseRefund(ctx *jxcontext.Context, afsOrderID string, vendorID, approveType int, reason string) (err error) {
|
||||
afsOrder, err := partner.CurOrderManager.LoadAfsOrder(afsOrderID, vendorID)
|
||||
if err == nil {
|
||||
if c.IsReallyCallPlatformAPI {
|
||||
err = partner.GetPurchaseOrderHandlerFromVendorID(vendorID).AgreeOrRefuseRefund(ctx, afsOrder, approveType, reason)
|
||||
}
|
||||
if err == nil {
|
||||
flag := model.AfsOrderFlagAgreeUserRefund
|
||||
if approveType == partner.AfsApproveTypeRefused {
|
||||
flag = model.AfsOrderFlagRefuseUserRefund
|
||||
afsOrder.RefuseReason = reason
|
||||
partner.CurOrderManager.UpdateAfsOrderFields(afsOrder, []string{"RefuseReason"})
|
||||
} else {
|
||||
if order, _ := partner.CurOrderManager.LoadOrder(afsOrder.VendorOrderID, afsOrder.VendorID); order != nil {
|
||||
if order.EarningType == model.EarningTypePoints {
|
||||
var (
|
||||
skuMap = make(map[int]*model.OrderSku)
|
||||
diff int64
|
||||
db = dao.GetDB()
|
||||
)
|
||||
for _, sku := range order.Skus {
|
||||
skuMap[sku.SkuID] = sku
|
||||
}
|
||||
storeDetail, _ := dao.GetStoreDetail(db, jxutils.GetSaleStoreIDFromOrder(order), order.VendorID)
|
||||
waybills, _ := dao.GetWaybills(db, order.VendorOrderID)
|
||||
//京东商城和京西要重新算totalshopmoney等
|
||||
if order.VendorID == model.VendorIDJDShop || order.VendorID == model.VendorIDJX {
|
||||
skus, _ := dao.GetAfsOrderSkuInfo(db, order.VendorOrderID, afsOrderID, order.VendorID, false)
|
||||
for _, v := range skus {
|
||||
if skuMap[v.SkuID] != nil {
|
||||
diff += skuMap[v.SkuID].SalePrice * int64(v.Count)
|
||||
}
|
||||
}
|
||||
order.TotalShopMoney = utils.Float64TwoInt64(float64(float64(order.TotalShopMoney)/jdshopapi.JdsPayPercentage-float64(diff)) * jdshopapi.JdsPayPercentage)
|
||||
if len(waybills) > 0 {
|
||||
jxutils.RefreshOrderEarningPrice3(order, storeDetail.PayPercentage, waybills[0])
|
||||
} else {
|
||||
jxutils.RefreshOrderEarningPrice2(order, storeDetail.PayPercentage)
|
||||
}
|
||||
dao.UpdateEntity(db, order, "TotalShopMoney", "NewEarningPrice")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
dao.SetAfsOrderFlag(dao.GetDB(), ctx.GetUserName(), afsOrderID, vendorID, flag)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) ConfirmReceivedReturnGoods(ctx *jxcontext.Context, afsOrderID string, vendorID int) (err error) {
|
||||
afsOrder, err := partner.CurOrderManager.LoadAfsOrder(afsOrderID, vendorID)
|
||||
if err == nil {
|
||||
if c.IsReallyCallPlatformAPI {
|
||||
err = partner.GetPurchaseOrderHandlerFromVendorID(vendorID).ConfirmReceivedReturnGoods(ctx, afsOrder)
|
||||
}
|
||||
if err == nil {
|
||||
dao.SetAfsOrderFlag(dao.GetDB(), ctx.GetUserName(), afsOrderID, vendorID, model.AfsOrderFlagMaskReturnGoods)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) PartRefundOrder(ctx *jxcontext.Context, order *model.GoodsOrder, refundSkuList []*model.OrderSku, reason string) (err error) {
|
||||
if c.IsReallyCallPlatformAPI {
|
||||
err = partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID).PartRefundOrder(ctx, order, refundSkuList, reason)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) RefundOrder(ctx *jxcontext.Context, order *model.GoodsOrder, reason string) (err error) {
|
||||
if c.IsReallyCallPlatformAPI {
|
||||
err = partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID).RefundOrder(ctx, order, reason)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) ConfirmSelfTake(ctx *jxcontext.Context, vendorOrderID string, vendorID int, selfTakeCode string) (err error) {
|
||||
order, err2 := partner.CurOrderManager.LoadOrder(vendorOrderID, vendorID)
|
||||
if err = err2; err == nil {
|
||||
err = c.confirmSelfTake(ctx, order, selfTakeCode)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) SetOrderWaybillTip(ctx *jxcontext.Context, vendorOrderID string, vendorID int, tipFee int64) (err error) {
|
||||
order, err2 := partner.CurOrderManager.LoadOrder(vendorOrderID, vendorID)
|
||||
if err = err2; err == nil {
|
||||
err = c.SetOrderWaybillTipByOrder(ctx, order, tipFee)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func isWaybillCanAddTip(waybill *model.Waybill) (isCan bool) {
|
||||
isCan = waybill.Status >= model.WaybillStatusNew && waybill.Status < model.WaybillStatusAccepted && partner.GetWaybillTipUpdater(waybill.WaybillVendorID) != nil
|
||||
return isCan
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) SetOrderWaybillTipByOrder(ctx *jxcontext.Context, order *model.GoodsOrder, tipFee int64) (err error) {
|
||||
roundTipFee := tipFee / 100 * 100
|
||||
if roundTipFee != tipFee {
|
||||
return fmt.Errorf("小费必须是1元的整数倍")
|
||||
}
|
||||
if order.WaybillTipMoney >= tipFee {
|
||||
return fmt.Errorf("当前小费已经是%s元,想要设置%s元", jxutils.IntPrice2StandardString(order.WaybillTipMoney), jxutils.IntPrice2StandardString(tipFee))
|
||||
}
|
||||
|
||||
db := dao.GetDB()
|
||||
storeDetail, err2 := dao.GetStoreDetail(db, jxutils.GetSaleStoreIDFromOrder(order), order.VendorID)
|
||||
if err = err2; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 如果平台支持设置配送小费,必须要成功设置
|
||||
if handler := partner.GetWaybillTipUpdater(order.VendorID); handler != nil {
|
||||
if err = handler.UpdateWaybillTip(ctx, order.VendorOrgCode, order.VendorStoreID, order.VendorOrderID, "", "", utils.Int2Str(storeDetail.CityCode), tipFee); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
order.WaybillTipMoney = tipFee
|
||||
partner.CurOrderManager.UpdateOrderFields(order, []string{"WaybillTipMoney"})
|
||||
|
||||
waybills, err := dao.GetWayBillByOrderID(db, 0, order.VendorID, 0, order.VendorOrderID)
|
||||
if err == nil {
|
||||
var waybills2 []*model.Waybill
|
||||
for _, v := range waybills {
|
||||
// 必须是三方配送
|
||||
if !model.IsWaybillPlatformOwn(v) && isWaybillCanAddTip(v) {
|
||||
waybills2 = append(waybills2, v)
|
||||
}
|
||||
}
|
||||
if len(waybills2) > 0 {
|
||||
task := tasksch.NewParallelTask("SetOrderWaybillTipByOrder", nil, ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
waybill := batchItemList[0].(*model.Waybill)
|
||||
handler := partner.GetWaybillTipUpdater(waybill.WaybillVendorID)
|
||||
if err == nil {
|
||||
err = handler.UpdateWaybillTip(ctx, waybill.VendorOrgCode, storeDetail.VendorStoreID, waybill.VendorOrderID, waybill.VendorWaybillID, waybill.VendorWaybillID2, utils.Int2Str(storeDetail.CityCode), tipFee)
|
||||
}
|
||||
return nil, err
|
||||
}, waybills2)
|
||||
tasksch.HandleTask(task, nil, false).Run()
|
||||
_, err = task.GetResult(0)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) confirmSelfTake(ctx *jxcontext.Context, order *model.GoodsOrder, selfTakeCode string) (err error) {
|
||||
globals.SugarLogger.Debugf("confirmSelfTake orderID:%s, selfTakeCode:%s", order.VendorOrderID, selfTakeCode)
|
||||
vendorID := order.VendorID
|
||||
if vendorID == model.VendorIDJD || vendorID == model.VendorIDJX {
|
||||
if vendorID == model.VendorIDJD {
|
||||
if selfTakeCode == autoSelfTakeCode {
|
||||
if selfTakeCode, err = jd.CurPurchaseHandler.GetSelfTakeCode(ctx, order); err != nil {
|
||||
return fmt.Errorf("获取订单:%s自提货码失败,原始错误:%s", order.VendorOrderID, err.Error())
|
||||
}
|
||||
if selfTakeCode == "" {
|
||||
return fmt.Errorf("订单:%s看起来不是一个自提订单,如果确认是自提订单,请联系开发", order.VendorOrderID)
|
||||
}
|
||||
}
|
||||
err = jd.CurPurchaseHandler.ConfirmSelfTake(ctx, order, selfTakeCode)
|
||||
} else {
|
||||
orderStatus := &model.OrderStatus{
|
||||
VendorOrderID: order.VendorOrderID,
|
||||
VendorID: model.VendorIDJX,
|
||||
OrderType: model.OrderTypeOrder,
|
||||
RefVendorOrderID: order.VendorOrderID,
|
||||
RefVendorID: model.VendorIDJX,
|
||||
VendorStatus: utils.Int2Str(model.OrderStatusFinished),
|
||||
Status: model.OrderStatusFinished,
|
||||
StatusTime: time.Now(),
|
||||
Remark: "自提完成",
|
||||
}
|
||||
jxutils.CallMsgHandlerAsync(func() {
|
||||
err = partner.CurOrderManager.OnOrderStatusChanged("", orderStatus)
|
||||
}, jxutils.ComposeUniversalOrderID(order.VendorOrderID, model.VendorIDJX))
|
||||
}
|
||||
} else {
|
||||
err = fmt.Errorf("自提核销不支持%s平台订单", model.VendorChineseNames[order.VendorID])
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) ConfirmSelfTakeOrders(ctx *jxcontext.Context, vendorIDs []int, orderCreatedAfter, orderCreatedBefore time.Time, isAsync, isContinueWhenError bool) (hint string, err error) {
|
||||
orderList, err := dao.GetPendingFakeOrders(dao.GetDB(), vendorIDs, orderCreatedAfter, orderCreatedBefore)
|
||||
if err == nil {
|
||||
if len(orderList) > 0 {
|
||||
task := tasksch.NewParallelTask(fmt.Sprintf("自动完成内部自提单%v,%s", vendorIDs, utils.Time2Str(orderCreatedAfter)), tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError), ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
order := batchItemList[0].(*model.GoodsOrder)
|
||||
if order.Status == model.OrderStatusAccepted {
|
||||
if handler := partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID); handler != nil {
|
||||
err = handler.AcceptOrRefuseOrder(order, true, ctx.GetUserName())
|
||||
time.Sleep(2 * time.Second)
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
if err = c.confirmSelfTake(ctx, order, autoSelfTakeCode); err == nil {
|
||||
retVal = []int{1}
|
||||
}
|
||||
}
|
||||
return retVal, err
|
||||
}, orderList)
|
||||
tasksch.HandleTask(task, nil, true).Run()
|
||||
if isAsync {
|
||||
hint = task.GetID()
|
||||
} else {
|
||||
resultList, err2 := task.GetResult(0)
|
||||
if err = err2; err == nil {
|
||||
hint = utils.Int2Str(len(resultList))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return hint, err
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,59 +0,0 @@
|
||||
package defsch
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
push "git.rosy.net.cn/jx-callback/business/jxutils/unipush"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/weixinmsg"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/msghub"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
)
|
||||
|
||||
var (
|
||||
autoRejectSkuMap = map[int]int{
|
||||
33996: 1,
|
||||
33995: 1,
|
||||
33994: 1,
|
||||
33991: 1,
|
||||
}
|
||||
)
|
||||
|
||||
func (s *DefScheduler) OnAfsOrderNew(order *model.AfsOrder, isPending bool) (err error) {
|
||||
if order.Status == model.AfsOrderStatusWait4Approve {
|
||||
if !isPending {
|
||||
if isAutoRejectAfsOrder(order) {
|
||||
if handler := partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID); handler != nil {
|
||||
if err := handler.AgreeOrRefuseRefund(jxcontext.AdminCtx, order, partner.AfsApproveTypeRefused, "抱歉,蟹券不接受退货或换货"); err != nil {
|
||||
globals.SugarLogger.Debugf("OnAfsOrderNew, orderID:%s, afsOrderID:%s failed with err:%v", order.VendorOrderID, order.AfsOrderID, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
msghub.OnNewWait4ApproveAfsOrder(order)
|
||||
weixinmsg.NotifyAfsOrderStatus(order)
|
||||
push.NotifyAfsOrder(order)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *DefScheduler) OnAfsOrderStatusChanged(order *model.AfsOrder, status *model.OrderStatus, isPending bool) (err error) {
|
||||
if status.Status == model.AfsOrderStatusWait4ReceiveGoods {
|
||||
if !isPending {
|
||||
msghub.OnKeyAfsOrderStatusChanged(order)
|
||||
weixinmsg.NotifyAfsOrderStatus(order)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func isAutoRejectAfsOrder(order *model.AfsOrder) (isReject bool) {
|
||||
for _, v := range order.Skus {
|
||||
if autoRejectSkuMap[jxutils.GetSkuIDFromOrderSkuFinancial(v)] == 1 {
|
||||
isReject = true
|
||||
break
|
||||
}
|
||||
}
|
||||
return isReject
|
||||
}
|
||||
@@ -1,275 +0,0 @@
|
||||
package defsch
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/jxcallback/scheduler"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
)
|
||||
|
||||
func (s *DefScheduler) loadSavedOrderByID(vendorOrderID string, vendorID int, isForceLoad bool) *WatchOrderInfo {
|
||||
return s.loadSavedOrderFromMap(&model.OrderStatus{
|
||||
RefVendorOrderID: vendorOrderID,
|
||||
RefVendorID: vendorID,
|
||||
}, isForceLoad)
|
||||
}
|
||||
|
||||
func (s *DefScheduler) SelfDeliveringAndUpdateStatus(ctx *jxcontext.Context, vendorOrderID string, vendorID int, userName string) (err error) {
|
||||
var order *model.GoodsOrder
|
||||
jxutils.CallMsgHandler(func() {
|
||||
err = func() (err error) {
|
||||
globals.SugarLogger.Infof("SelfDeliveringAndUpdateStatus orderID:%s userName:%s", vendorOrderID, userName)
|
||||
savedOrderInfo := s.loadSavedOrderByID(vendorOrderID, vendorID, true)
|
||||
if savedOrderInfo != nil {
|
||||
order = savedOrderInfo.order
|
||||
if err = s.isPossibleSwitch2SelfDelivery(order); err == nil {
|
||||
err = s.cancelOtherWaybillsCheckOrderDeliveryFlag(savedOrderInfo, nil, partner.CancelWaybillReasonOther, partner.CancelWaybillReasonStrActive)
|
||||
if err == nil {
|
||||
if model.IsOrderDeliveryByStore(order) {
|
||||
if order.Status < model.OrderStatusDelivering {
|
||||
storeDetail, err2 := dao.GetStoreDetail(dao.GetDB(), order.StoreID, order.VendorID)
|
||||
phone := userName
|
||||
if err = err2; err == nil {
|
||||
phone = storeDetail.Tel1
|
||||
}
|
||||
err = s.SelfDeliverDelivering(order, phone)
|
||||
}
|
||||
} else {
|
||||
if order.Status < model.OrderStatusDelivering {
|
||||
err = s.Swtich2SelfDeliver(order, userName)
|
||||
} else if order.VendorID == order.WaybillVendorID { // 状态为配送中,且是购物平台运单,不能转自送了
|
||||
err = scheduler.ErrOrderStatusIsNotSuitable4CurOperation
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
order.Status = model.OrderStatusDelivering
|
||||
order.DeliveryFlag |= model.OrderDeliveryFlagMaskScheduleDisabled | model.OrderDeliveryFlagMaskPurcahseDisabled
|
||||
if err = partner.CurOrderManager.UpdateOrderStatusAndDeliveryFlag(order); err == nil {
|
||||
s.stopTimer(savedOrderInfo)
|
||||
globals.SugarLogger.Infof("SelfDeliveringAndUpdateStatus orderID:%s userName:%s successfully", vendorOrderID, userName)
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
order = &model.GoodsOrder{
|
||||
VendorOrderID: vendorOrderID,
|
||||
VendorID: vendorID,
|
||||
}
|
||||
err = scheduler.ErrCanNotFindOrder
|
||||
}
|
||||
globals.SugarLogger.Infof("SelfDeliveringAndUpdateStatus orderID:%s userName:%s error:%v", vendorOrderID, userName, err)
|
||||
return err
|
||||
}()
|
||||
}, jxutils.ComposeUniversalOrderID(vendorOrderID, vendorID))
|
||||
vendorStatus := fmt.Sprintf("%s转商户自送成功", ctx.GetUserName())
|
||||
remark := ""
|
||||
if err != nil {
|
||||
vendorStatus = fmt.Sprintf("%s转商户自送失败", ctx.GetUserName())
|
||||
remark = err.Error()
|
||||
}
|
||||
partner.CurOrderManager.OnOrderMsg(order, vendorStatus, remark)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *DefScheduler) canOrderCreateWaybillNormally(order *model.GoodsOrder, savedOrderInfo *WatchOrderInfo) (err error) {
|
||||
if !(order.LockStatus != model.OrderStatusLocked && order.Status >= model.OrderStatusFinishedPickup && order.Status < model.OrderStatusEndBegin) {
|
||||
err = fmt.Errorf("当前订单%s没有处于拣货完成且没有结束没有锁定的订单才能进行召唤配送操作", order.VendorOrderID)
|
||||
} else if model.IsOrderHaveWaybill(order) {
|
||||
err = fmt.Errorf("当前订单%s已经有了有效的承运人%s了", order.VendorOrderID, jxutils.GetVendorName(order.WaybillVendorID))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *DefScheduler) isPossibleSwitch2SelfDelivery(order *model.GoodsOrder) (err error) {
|
||||
if model.IsOrderDeliveryByPlatform(order) {
|
||||
if order.Status < model.OrderStatusFinishedPickup {
|
||||
err = fmt.Errorf("拣货完成后才能转自配送")
|
||||
} else if order.Status == model.OrderStatusFinishedPickup {
|
||||
if time.Now().Sub(order.StatusTime) < minMinute2Schedule3rdCarrier*time.Minute {
|
||||
err = fmt.Errorf("非自配送门店转3方配送至少要求拣货完成后%d分钟才能操作", minMinute2Schedule3rdCarrier)
|
||||
}
|
||||
} else if order.Status >= model.OrderStatusDelivering && order.Status < model.OrderStatusEndBegin {
|
||||
if model.IsOrderHaveOwnWaybill(order) {
|
||||
err = fmt.Errorf("%s物流已在配送中,不能转自配送", jxutils.GetVendorName(order.VendorID))
|
||||
}
|
||||
} else if order.Status >= model.OrderStatusEndBegin {
|
||||
err = fmt.Errorf("订单%s已经结束,请刷新状态", order.VendorOrderID)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *DefScheduler) CreateWaybillOnProviders4SavedOrder(ctx *jxcontext.Context, savedOrderInfo *WatchOrderInfo, courierVendorIDs, excludeCourierVendorIDs []int, forceCreate bool, maxDeliveryFee int64) (bills []*model.Waybill, err error) {
|
||||
order := savedOrderInfo.order
|
||||
if !forceCreate {
|
||||
err = s.canOrderCreateWaybillNormally(order, nil)
|
||||
}
|
||||
if err == nil {
|
||||
if forceCreate {
|
||||
maxDeliveryFee = math.MaxInt64
|
||||
}
|
||||
if bills, err = s.CreateWaybillOnProviders(ctx, order, courierVendorIDs, excludeCourierVendorIDs, maxDeliveryFee, forceCreate); err == nil {
|
||||
if forceCreate {
|
||||
order.DeliveryFlag |= model.OrderDeliveryFlagMaskScheduleDisabled
|
||||
err = partner.CurOrderManager.UpdateOrderStatusAndDeliveryFlag(order)
|
||||
}
|
||||
if err == nil {
|
||||
if forceCreate {
|
||||
s.stopTimer(savedOrderInfo)
|
||||
}
|
||||
globals.SugarLogger.Debugf("CreateWaybillOnProviders4SavedOrder orderID:%s userName:%s successfully", order.VendorOrderID, ctx.GetUserName())
|
||||
return bills, err
|
||||
}
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
globals.SugarLogger.Debugf("CreateWaybillOnProviders4SavedOrder orderID:%s failed with error:%v", order.VendorOrderID, err)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func (s *DefScheduler) CreateWaybillOnProvidersEx(ctx *jxcontext.Context, vendorOrderID string, vendorID int, courierVendorIDs []int, forceCreate bool, maxDeliveryFee int64) (bills []*model.Waybill, err error) {
|
||||
jxutils.CallMsgHandler(func() {
|
||||
bills, err = func() (bills []*model.Waybill, err error) {
|
||||
userName := ctx.GetUserName()
|
||||
globals.SugarLogger.Debugf("CreateWaybillOnProvidersEx orderID:%s userName:%s", vendorOrderID, userName)
|
||||
if vendorID == model.VendorIDELM {
|
||||
return nil, fmt.Errorf("不要直接使用饿了么订单号,请使用相应的饿百订单号")
|
||||
}
|
||||
savedOrderInfo := s.loadSavedOrderByID(vendorOrderID, vendorID, true)
|
||||
if savedOrderInfo != nil {
|
||||
order := savedOrderInfo.order
|
||||
if order.DeliveryType == model.OrderDeliveryTypeSelfTake {
|
||||
return nil, fmt.Errorf("订单:%s是自提单", vendorOrderID)
|
||||
}
|
||||
if !forceCreate {
|
||||
err = s.isPossibleSwitch2SelfDelivery(order)
|
||||
}
|
||||
if err == nil {
|
||||
if bills, err = s.CreateWaybillOnProviders4SavedOrder(ctx, savedOrderInfo, courierVendorIDs, nil, forceCreate, maxDeliveryFee); err == nil && len(bills) > 0 {
|
||||
partner.CurOrderManager.OnOrderMsg(order, "手动创建运单成功", fmt.Sprintf("%s创建%s平台运单,强发:%t,最高限价:%d", ctx.GetUserName(), model.VendorChineseNames[bills[0].WaybillVendorID], forceCreate, maxDeliveryFee))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
err = scheduler.ErrCanNotFindOrder
|
||||
}
|
||||
globals.SugarLogger.Infof("CreateWaybillOnProvidersEx orderID:%s userName:%s error:%v", vendorOrderID, userName, err)
|
||||
return bills, err
|
||||
}()
|
||||
}, jxutils.ComposeUniversalOrderID(vendorOrderID, vendorID))
|
||||
return bills, err
|
||||
}
|
||||
|
||||
// todo 这个函数可以和SelfDeliveringAndUpdateStatus合并
|
||||
func (s *DefScheduler) CancelAll3rdWaybills(ctx *jxcontext.Context, vendorOrderID string, vendorID int, isStopSchedule bool) (err error) {
|
||||
jxutils.CallMsgHandler(func() {
|
||||
err = func() (err error) {
|
||||
globals.SugarLogger.Infof("CancelAll3rdWaybills orderID:%s userName:%s", vendorOrderID, ctx.GetUserName())
|
||||
savedOrderInfo := s.loadSavedOrderByID(vendorOrderID, vendorID, true)
|
||||
if savedOrderInfo != nil {
|
||||
err = s.cancelOtherWaybills(savedOrderInfo, nil, partner.CancelWaybillReasonOther, partner.CancelWaybillReasonStrActive)
|
||||
} else {
|
||||
err = scheduler.ErrCanNotFindOrder
|
||||
}
|
||||
globals.SugarLogger.Infof("CancelAll3rdWaybills orderID:%s userName:%s error:%v", vendorOrderID, ctx.GetUserName(), err)
|
||||
if err == nil && isStopSchedule {
|
||||
order := savedOrderInfo.order
|
||||
order.DeliveryFlag |= model.OrderDeliveryFlagMaskScheduleDisabled
|
||||
if err = partner.CurOrderManager.UpdateOrderStatusAndDeliveryFlag(order); err == nil {
|
||||
s.stopTimer(savedOrderInfo)
|
||||
globals.SugarLogger.Infof("CancelAll3rdWaybills orderID:%s userName:%s successfully", vendorOrderID, ctx.GetUserName())
|
||||
}
|
||||
}
|
||||
return err
|
||||
}()
|
||||
}, jxutils.ComposeUniversalOrderID(vendorOrderID, vendorID))
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *DefScheduler) QueryOrderWaybillFeeInfoEx(ctx *jxcontext.Context, vendorOrderID string, vendorID int) (deliveryFeeMap map[int]*partner.WaybillFeeInfo, err error) {
|
||||
jxutils.CallMsgHandler(func() {
|
||||
deliveryFeeMap, err = func() (deliveryFeeMap map[int]*partner.WaybillFeeInfo, err error) {
|
||||
userName := ctx.GetUserName()
|
||||
globals.SugarLogger.Infof("GetWaybillsInfoEx orderID:%s userName:%s", vendorOrderID, userName)
|
||||
|
||||
db := dao.GetDB()
|
||||
order, err := partner.CurOrderManager.LoadOrder(vendorOrderID, vendorID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if order.DeliveryType == model.OrderDeliveryTypeSelfTake {
|
||||
return nil, fmt.Errorf("订单:%s是自提单", vendorOrderID)
|
||||
}
|
||||
storeCourierList, err := dao.GetStoreCourierList(db, []int{jxutils.GetSaleStoreIDFromOrder(order)}, nil, model.StoreStatusAll, model.StoreAuditStatusOnline)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
waybillList, err := partner.CurOrderManager.GetOrderWaybillInfo(ctx, vendorOrderID, vendorID, true, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
waybillMap := make(map[int]*model.Waybill)
|
||||
for _, bill := range waybillList {
|
||||
waybillMap[bill.WaybillVendorID] = &bill.Waybill
|
||||
}
|
||||
deliveryFeeMap = make(map[int]*partner.WaybillFeeInfo)
|
||||
|
||||
var timeoutSecond int
|
||||
if savedOrderInfo := s.loadSavedOrderByID(vendorOrderID, vendorID, false); savedOrderInfo != nil {
|
||||
timeoutSecond = savedOrderInfo.GetCreateWaybillTimeout()
|
||||
}
|
||||
for _, storeCourier := range storeCourierList {
|
||||
var feeInfo *partner.WaybillFeeInfo
|
||||
if waybillMap[storeCourier.VendorID] != nil {
|
||||
feeInfo = &partner.WaybillFeeInfo{
|
||||
Waybill: waybillMap[storeCourier.VendorID],
|
||||
}
|
||||
} else {
|
||||
if storeCourier.Status != model.StoreStatusOpened {
|
||||
feeInfo = &partner.WaybillFeeInfo{
|
||||
ErrCode: partner.WaybillFeeErrCodeCourierNotOpen,
|
||||
ErrStr: fmt.Sprintf("暂未开通,联系运营"),
|
||||
}
|
||||
} else {
|
||||
if handler := partner.GetDeliveryPlatformFromVendorID(storeCourier.VendorID); handler != nil {
|
||||
if handler.Use4CreateWaybill {
|
||||
if feeInfo, err = handler.Handler.GetWaybillFee(order); err != nil {
|
||||
feeInfo = &partner.WaybillFeeInfo{
|
||||
ErrCode: partner.WaybillFeeErrCodeCourierOthers,
|
||||
ErrStr: err.Error(),
|
||||
}
|
||||
} else {
|
||||
feeInfo.TimeoutSecond = timeoutSecond
|
||||
}
|
||||
} else {
|
||||
feeInfo = &partner.WaybillFeeInfo{
|
||||
ErrCode: partner.WaybillFeeErrCodeCourierForbidden,
|
||||
ErrStr: fmt.Sprintf("内部错误,%d不能用于创建运单", storeCourier.VendorID),
|
||||
}
|
||||
}
|
||||
} else {
|
||||
feeInfo = &partner.WaybillFeeInfo{
|
||||
ErrCode: partner.WaybillFeeErrCodeCourierNotSupported,
|
||||
ErrStr: fmt.Sprintf("内部错误,%d不被支持", storeCourier.VendorID),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
deliveryFeeMap[storeCourier.VendorID] = feeInfo
|
||||
}
|
||||
err = nil
|
||||
return deliveryFeeMap, err
|
||||
}()
|
||||
}, jxutils.ComposeUniversalOrderID(vendorOrderID, vendorID))
|
||||
return deliveryFeeMap, err
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
package scheduler
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
)
|
||||
|
||||
const (
|
||||
StoreDeliveryTypeCrowdSourcing = 0 //缺省,平台众包配送,可转自送
|
||||
StoreDeliveryTypeByPlatform = 1 //平台专送
|
||||
StoreDeliveryTypeByStore = 2 //完全门店自送,这个表示的意思是平台的门店属性(就是购物平台不负责配送),而不是真正是否是老板自己送
|
||||
)
|
||||
|
||||
const (
|
||||
TimerStatusTypeUnknown = -1
|
||||
TimerStatusTypeOrder = 0
|
||||
TimerStatusTypeWaybill = 1
|
||||
)
|
||||
|
||||
var (
|
||||
CurrentScheduler IScheduler
|
||||
)
|
||||
|
||||
var (
|
||||
ErrOrderStatusIsNotSuitable4CurOperation = errors.New("订单锁定或状态不适合当前操作")
|
||||
ErrOrderStatusAlreadySatisfyCurOperation = errors.New("订单当前状态已满足当前操作")
|
||||
|
||||
ErrCanNotCreateAtLeastOneWaybill = errors.New("一个运单都不能创建")
|
||||
ErrCanNotFindOrder = errors.New("不能找到订单(一般是由于事件错序)")
|
||||
ErrCanNotFindWaybill = errors.New("不能找到运单(一般是由于事件错序)")
|
||||
ErrOrderIsNotSolid = errors.New("订单是临时订单,不完整,不能用于创建运单")
|
||||
ErrDeliverProviderWrong = errors.New("快递商不存在或不能用于创建运单")
|
||||
)
|
||||
|
||||
type IScheduler interface {
|
||||
// 以下是订单
|
||||
OnOrderNew(order *model.GoodsOrder, isPending bool) (err error)
|
||||
OnOrderStatusChanged(order *model.GoodsOrder, status *model.OrderStatus, isPending bool) (err error)
|
||||
|
||||
// 以下是运单
|
||||
OnWaybillStatusChanged(bill *model.Waybill, isPending bool) (err error)
|
||||
|
||||
// 以下是售后单
|
||||
OnAfsOrderNew(order *model.AfsOrder, isPending bool) (err error)
|
||||
OnAfsOrderStatusChanged(order *model.AfsOrder, status *model.OrderStatus, isPending bool) (err error)
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,209 +0,0 @@
|
||||
package act
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/testinit"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/ebai"
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/jd"
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/mtwm"
|
||||
)
|
||||
|
||||
func init() {
|
||||
testinit.Init()
|
||||
}
|
||||
|
||||
func TestInitDb(t *testing.T) {
|
||||
dao.ExecuteSQL(dao.GetDB(), `
|
||||
DROP TABLE IF EXISTS act, act_map, act_order_rule, act_store_sku, act_store_sku_map;
|
||||
`)
|
||||
}
|
||||
|
||||
func TestCreateActOnAlpha(t *testing.T) {
|
||||
actStoreSkuList := []*ActStoreSkuParam{
|
||||
&ActStoreSkuParam{
|
||||
ActStoreSku: model.ActStoreSku{
|
||||
StoreID: 2,
|
||||
SkuID: 2142,
|
||||
},
|
||||
},
|
||||
&ActStoreSkuParam{
|
||||
ActStoreSku: model.ActStoreSku{
|
||||
StoreID: 2,
|
||||
SkuID: 1162,
|
||||
},
|
||||
},
|
||||
&ActStoreSkuParam{
|
||||
ActStoreSku: model.ActStoreSku{
|
||||
StoreID: 2,
|
||||
SkuID: 1167,
|
||||
},
|
||||
},
|
||||
&ActStoreSkuParam{
|
||||
ActStoreSku: model.ActStoreSku{
|
||||
StoreID: 2,
|
||||
SkuID: 1172,
|
||||
},
|
||||
},
|
||||
}
|
||||
t.Log(utils.Format4Output(actStoreSkuList, true))
|
||||
// actID, err := CreateAct(jxcontext.AdminCtx, &model.Act{
|
||||
// Name: "测试活动",
|
||||
// PricePercentage: 80,
|
||||
// Type: model.ActSkuDirectDown,
|
||||
// }, []int{model.VendorIDJD, model.VendorIDMTWM, model.VendorIDEBAI}, nil, actStoreSkuList, false)
|
||||
// if err != nil {
|
||||
// t.Fatal(err)
|
||||
// }
|
||||
// globals.SugarLogger.Debug(actID)
|
||||
}
|
||||
|
||||
func TestCreateActOnDev(t *testing.T) {
|
||||
actStoreSkuList := []*ActStoreSkuParam{
|
||||
&ActStoreSkuParam{
|
||||
ActStoreSku: model.ActStoreSku{
|
||||
StoreID: 100884,
|
||||
SkuID: 22716,
|
||||
},
|
||||
},
|
||||
&ActStoreSkuParam{
|
||||
ActStoreSku: model.ActStoreSku{
|
||||
StoreID: 100884,
|
||||
SkuID: 22717,
|
||||
},
|
||||
},
|
||||
&ActStoreSkuParam{
|
||||
ActStoreSku: model.ActStoreSku{
|
||||
StoreID: 100920,
|
||||
SkuID: 22714,
|
||||
},
|
||||
},
|
||||
&ActStoreSkuParam{
|
||||
ActStoreSku: model.ActStoreSku{
|
||||
StoreID: 100920,
|
||||
SkuID: 22715,
|
||||
},
|
||||
},
|
||||
// &ActStoreSkuParam{
|
||||
// ActStoreSku: model.ActStoreSku{
|
||||
// StoreID: 100119,
|
||||
// SkuID: 26595,
|
||||
// },
|
||||
// },
|
||||
}
|
||||
// t.Log(utils.Format4Output(actStoreSkuList, true))
|
||||
actID, err := CreateAct(jxcontext.AdminCtx, &model.Act{
|
||||
Name: "测试活动",
|
||||
PricePercentage: 80,
|
||||
Type: model.ActSkuDirectDown,
|
||||
BeginAt: time.Now().Add(-24 * time.Hour),
|
||||
EndAt: time.Now().Add(10 * 24 * time.Hour),
|
||||
}, []int{model.VendorIDJD, model.VendorIDMTWM /*, model.VendorIDEBAI*/}, nil, actStoreSkuList, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
globals.SugarLogger.Debug(actID)
|
||||
}
|
||||
|
||||
func TestCancelAct(t *testing.T) {
|
||||
err := CancelAct(jxcontext.AdminCtx, 1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeleteActStoreBind(t *testing.T) {
|
||||
_, err := DeleteActStoreSkuBind(jxcontext.AdminCtx, dao.GetDB(), 1, []*ActStoreSkuParam{
|
||||
// &ActStoreSkuParam{
|
||||
// ActStoreSku: model.ActStoreSku{
|
||||
// StoreID: 100119,
|
||||
// SkuID: 30828,
|
||||
// },
|
||||
// },
|
||||
// &ActStoreSkuParam{
|
||||
// ActStoreSku: model.ActStoreSku{
|
||||
// StoreID: 100119,
|
||||
// SkuID: 30827,
|
||||
// },
|
||||
// },
|
||||
&ActStoreSkuParam{
|
||||
ActStoreSku: model.ActStoreSku{
|
||||
StoreID: 100884,
|
||||
SkuID: 22716,
|
||||
},
|
||||
},
|
||||
&ActStoreSkuParam{
|
||||
ActStoreSku: model.ActStoreSku{
|
||||
StoreID: 100884,
|
||||
SkuID: 22717,
|
||||
},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddActStoreBind(t *testing.T) {
|
||||
err := AddActStoreSkuBind(jxcontext.AdminCtx, dao.GetDB(), 1, []*ActStoreSkuParam{
|
||||
// &ActStoreSkuParam{
|
||||
// ActStoreSku: model.ActStoreSku{
|
||||
// StoreID: 100119,
|
||||
// SkuID: 30828,
|
||||
// },
|
||||
// },
|
||||
// &ActStoreSkuParam{
|
||||
// ActStoreSku: model.ActStoreSku{
|
||||
// StoreID: 100119,
|
||||
// SkuID: 30827,
|
||||
// },
|
||||
// },
|
||||
&ActStoreSkuParam{
|
||||
ActStoreSku: model.ActStoreSku{
|
||||
StoreID: 100884,
|
||||
SkuID: 22716,
|
||||
},
|
||||
},
|
||||
&ActStoreSkuParam{
|
||||
ActStoreSku: model.ActStoreSku{
|
||||
StoreID: 100884,
|
||||
SkuID: 22717,
|
||||
},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSyncAct(t *testing.T) {
|
||||
_, err := SyncAct(jxcontext.AdminCtx, nil, 1, nil, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestForceUpdateVendorPrice(t *testing.T) {
|
||||
hint, err := ForceUpdateVendorPrice(jxcontext.AdminCtx, model.VendorIDJD, model.ActSkuDirectDown, []*ActStoreSkuParam{
|
||||
&ActStoreSkuParam{
|
||||
ActStoreSku: model.ActStoreSku{
|
||||
StoreID: 100118,
|
||||
SkuID: 22509,
|
||||
ActPrice: 9900,
|
||||
},
|
||||
VendorPrice: 19900,
|
||||
},
|
||||
}, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(hint)
|
||||
}
|
||||
467
business/jxstore/cms/api_print.go
Normal file
467
business/jxstore/cms/api_print.go
Normal file
@@ -0,0 +1,467 @@
|
||||
package cms
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxstore/event"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"net"
|
||||
"regexp"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
sounda = "sounda" //提示音a
|
||||
soundb = "soundb" //提示音b
|
||||
soundc = "soundc" //提示音c
|
||||
soundd = "soundd" //提示音d
|
||||
sounde = "sounde" //报警音e
|
||||
soundf = "soundf" //报警音f
|
||||
soundg = "soundg" //报警音g
|
||||
)
|
||||
|
||||
type PrintInfo struct {
|
||||
PrintNo string
|
||||
AppID int
|
||||
}
|
||||
|
||||
var (
|
||||
regexpMobile = regexp.MustCompile("^1(3[0-9]|4[01456879]|5[0-35-9]|6[2567]|7[0-8]|8[0-9]|9[0-35-9])\\d{8}$")
|
||||
soundMap = map[string]string{
|
||||
"sounda": "sounda",
|
||||
"soundb": "soundb",
|
||||
"soundc": "soundc",
|
||||
"soundd": "soundd",
|
||||
"sounde": "sounde",
|
||||
"soundf": "soundf",
|
||||
"soundg": "soundg",
|
||||
}
|
||||
)
|
||||
|
||||
func AddPrinter(appID int, printers []*model.AddPrinterParam) (err error) {
|
||||
var (
|
||||
db = dao.GetDB()
|
||||
errs []error
|
||||
)
|
||||
if len(printers) > 50 {
|
||||
return fmt.Errorf("一次最多只能绑定50台!")
|
||||
}
|
||||
for _, v := range printers {
|
||||
if printers2, _ := dao.GetPrinters(db, appID, v.PrintNo, 0, 0); len(printers2) > 0 {
|
||||
// 代表打印机已经在小程序注册了,查询打印机授权门店
|
||||
bindStoreList, err := dao.QueryPrintBindStore(v.PrintNo)
|
||||
if err != nil {
|
||||
errs = append(errs, fmt.Errorf("QueryPrintBindStore err : %v ", err))
|
||||
continue
|
||||
}
|
||||
if len(bindStoreList) >= 5 {
|
||||
errs = append(errs, fmt.Errorf("当前打印机绑定门店数据超过五个,无法继续绑定"))
|
||||
continue
|
||||
}
|
||||
have := false
|
||||
userId := ""
|
||||
for _, bsl := range bindStoreList {
|
||||
if bsl.StoreID == v.StoreId {
|
||||
have = true
|
||||
userId = bsl.UserId
|
||||
}
|
||||
}
|
||||
if !have {
|
||||
if err := dao.BindStoreList(printers[0], userId); err != nil {
|
||||
errs = append(errs, fmt.Errorf("BindStoreList err : %v ", err))
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
//验证
|
||||
if err = checkPrinterInfo(v.PrintNo, v.Name, "", "", 0); err != nil {
|
||||
errs = append(errs, err)
|
||||
continue
|
||||
}
|
||||
// 检查心跳
|
||||
exits, err := dao.CheckHeard(v.PrintNo)
|
||||
if err != nil {
|
||||
errs = append(errs, fmt.Errorf("CheckHeard err : %v ", err))
|
||||
continue
|
||||
}
|
||||
if !exits {
|
||||
errs = append(errs, fmt.Errorf("打印机未激活,请激活后在绑定"))
|
||||
continue
|
||||
}
|
||||
|
||||
printer := &model.Printer{
|
||||
AppID: appID,
|
||||
PrintNo: v.PrintNo,
|
||||
Name: v.Name,
|
||||
IccID: "",
|
||||
Status: model.PrinterStatusOffline,
|
||||
Sound: "sounda",
|
||||
PrintKey: v.SIM,
|
||||
IsOnline: 0,
|
||||
Volume: 1,
|
||||
FlowFlag: 0,
|
||||
OfflineCount: 0,
|
||||
UserId: "system_user",
|
||||
}
|
||||
|
||||
// 创建打印机
|
||||
if err := InitPrint(printer, v); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if len(errs) > 0 {
|
||||
err = jxutils.BuildErr(errs)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func InitPrint(printer *model.Printer, printParam *model.AddPrinterParam) error {
|
||||
txDb, _ := dao.Begin(dao.GetDB())
|
||||
// 创建打印机
|
||||
dao.WrapAddIDCULDEntity(printer, "")
|
||||
if err := dao.CreateEntityTx(txDb, printer); err != nil {
|
||||
txDb.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
// 赋予打印机默认配置
|
||||
day := time.Now()
|
||||
param, err := MarshalJson2String(&model.PrintSetting{
|
||||
CreatedAt: day,
|
||||
UpdatedAt: day,
|
||||
DeletedAt: utils.DefaultTimeValue,
|
||||
PrintNo: printer.PrintNo,
|
||||
CallNameSetting: 64, // 老板
|
||||
BusinessOffLineVoice: 1, // 离线开关
|
||||
BalanceNotEnoughVoice: 1, // 余额不足
|
||||
EveryDayGreetVoice: 1, // 问好
|
||||
BusinessPrintNum: 1, // 商户侧打印次数
|
||||
CustomerPrintNum: 1, // 用户侧打印次数
|
||||
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := dao.CreateEntityTx(txDb, param); err != nil {
|
||||
txDb.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
// 初始化打印机账户
|
||||
if err := dao.CreateEntityTx(txDb, &model.PrintBill{
|
||||
CreatedAt: time.Now(),
|
||||
UpdatedAt: time.Now(),
|
||||
PrintNo: param.PrintNo,
|
||||
PrintBalance: 20000,
|
||||
UserId: "system",
|
||||
}); err != nil {
|
||||
txDb.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
// 初始化绑定信息
|
||||
if err := dao.BindStoreList(printParam, ""); err != nil {
|
||||
txDb.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
defer txDb.Commit()
|
||||
return err
|
||||
}
|
||||
|
||||
// MarshalJson2String 工具类
|
||||
func MarshalJson2String(param *model.PrintSetting) (*model.PrintSetting, error) {
|
||||
// 语音设置
|
||||
voiceSetting := &model.VoiceSettingDetail{
|
||||
WaitOrderVoice: model.SettingOpen,
|
||||
RiderTakeOrderVoice: model.SettingOpen,
|
||||
ApplyUserOrderCancelVoice: model.SettingOpen,
|
||||
ApplyRefundOrderVoice: model.SettingOpen,
|
||||
ApplyRefundGoodsVoice: model.SettingOpen,
|
||||
RefundGoodsVoice: model.SettingOpen,
|
||||
ConfirmGoodsVoice: model.SettingOpen,
|
||||
SuccessGoodsVoice: model.SettingOpen,
|
||||
ConsultingPrint: model.SettingOpen,
|
||||
ReminderVoice: model.SettingOpen,
|
||||
CustomerRejectionVoice: model.SettingOpen,
|
||||
CusterRefundVoice: model.SettingOpen,
|
||||
LoseAuthorization: model.SettingOpen,
|
||||
}
|
||||
customerVoiceSettingByte, err := json.Marshal(voiceSetting)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
param.VoiceSetting = string(customerVoiceSettingByte)
|
||||
|
||||
// 打印设置
|
||||
printSetting := &model.PrintSettingDetail{
|
||||
UserOrderCancel: model.SettingOpen,
|
||||
RefundOrder: model.SettingOpen,
|
||||
BusinessOrderCancel: model.SettingOpen,
|
||||
RiderTakeOrder: model.SettingOpen,
|
||||
CusterRefundPrint: model.SettingOpen,
|
||||
WaitOrderPrint: model.SettingOpen,
|
||||
ApplyUserCancelOrder: model.SettingOpen,
|
||||
ApplyUserRefund: model.SettingOpen,
|
||||
OrderCancelSuccess: model.SettingOpen,
|
||||
}
|
||||
pickingSettingByte, err := json.Marshal(printSetting)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
param.PrintSetting = string(pickingSettingByte)
|
||||
return param, nil
|
||||
}
|
||||
|
||||
func checkPrinterInfo(printNo, name, sound, sim string, volume int) (err error) {
|
||||
if printNo != "" {
|
||||
|
||||
}
|
||||
if sim != "" {
|
||||
//if regexpMobile.FindString(sim) == "" {
|
||||
return fmt.Errorf("暂不支持修改sim卡号码!print_no : %v ", printNo)
|
||||
//}
|
||||
}
|
||||
if volume != 0 {
|
||||
if volume <= 0 || volume > 5 {
|
||||
return fmt.Errorf("请输入正确的音量1-5!print_no : %v ", printNo)
|
||||
}
|
||||
}
|
||||
if sound != "" {
|
||||
if soundMap[sound] == "" {
|
||||
return fmt.Errorf("请输入正确的提示音!print_no : %v ", printNo)
|
||||
}
|
||||
}
|
||||
if name != "" {
|
||||
if len(name) > 255 {
|
||||
return fmt.Errorf("打印机备注不能超过255个字符!print_no : %v ", printNo)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func DelPrinter(appID int, printNos []string, storeId string) (err error) {
|
||||
var (
|
||||
db = dao.GetDB()
|
||||
errs []error
|
||||
)
|
||||
for _, v := range printNos {
|
||||
if printers, _ := dao.GetPrinters(db, appID, v, 0, 0); len(printers) == 0 {
|
||||
errs = append(errs, fmt.Errorf("该应用下未找到该打印机!print_no : %v ", v))
|
||||
continue
|
||||
} else {
|
||||
if err := dao.DeleteStoreList(printers[0].PrintNo, storeId); err != nil {
|
||||
errs = append(errs, err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(errs) > 0 {
|
||||
err = jxutils.BuildErr(errs)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func QueryPrintList(printNo, printKey string, status, isOnline int64, page, size int64) ([]*model.Printer, int, error) {
|
||||
prints, count, err := dao.QueryPrintList(dao.GetDB(), printNo, printKey, status, isOnline, page, size)
|
||||
return prints, count, err
|
||||
}
|
||||
func UpdatePrinter(appID int, printNo string, name, sim, sound *string, volume *int) (err error) {
|
||||
var (
|
||||
db = dao.GetDB()
|
||||
fields []string
|
||||
)
|
||||
//看有没有
|
||||
if printers, _ := dao.GetPrinters(db, appID, printNo, 0, 0); len(printers) == 0 {
|
||||
return fmt.Errorf("该应用下未找到该打印机!print_no : %v", printNo)
|
||||
} else {
|
||||
if name != nil {
|
||||
if *name != "" {
|
||||
if len(*name) > 20 {
|
||||
return fmt.Errorf("打印机备注不能超过20个字符!print_no : %v ", printNo)
|
||||
}
|
||||
}
|
||||
if printers[0].Name != *name {
|
||||
printers[0].Name = *name
|
||||
fields = append(fields, "name")
|
||||
}
|
||||
}
|
||||
if sim != nil {
|
||||
if *sim != "" {
|
||||
//if regexpMobile.FindString(*sim) == "" {
|
||||
return fmt.Errorf("暂不支持修改sim卡号码!print_no : %v ", printNo)
|
||||
//}
|
||||
}
|
||||
//if printers[0].SIM != *sim {
|
||||
// printers[0].SIM = *sim
|
||||
// fields = append(fields, "sim")
|
||||
//}
|
||||
}
|
||||
if sound != nil {
|
||||
if *sound != "" {
|
||||
if soundMap[*sound] == "" {
|
||||
return fmt.Errorf("请输入正确的提示音!print_no : %v ", printNo)
|
||||
}
|
||||
}
|
||||
if printers[0].Sound != *sound {
|
||||
printers[0].Sound = *sound
|
||||
fields = append(fields, "sound")
|
||||
}
|
||||
}
|
||||
if volume != nil {
|
||||
if *volume <= 0 || *volume > 5 {
|
||||
return fmt.Errorf("请输入正确的音量 1-5!print_no : %v ", printNo)
|
||||
}
|
||||
if printers[0].Volume != *volume {
|
||||
printers[0].Volume = *volume
|
||||
fields = append(fields, "volume")
|
||||
}
|
||||
}
|
||||
if _, err = dao.UpdateEntity(db, printers[0], fields...); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func DelPrinterSeq(appID int, printNo string) (err error) {
|
||||
var (
|
||||
db = dao.GetDB()
|
||||
)
|
||||
//看有没有
|
||||
if printers, _ := dao.GetPrinters(db, appID, printNo, 0, 0); len(printers) == 0 {
|
||||
return fmt.Errorf("该应用下未找到该打印机!print_no : %v", printNo)
|
||||
} else {
|
||||
printMsgs, _ := dao.GetPrintMsgs2(db, printNo, "", model.PrintMsgAll, model.PrintMsgSuccess)
|
||||
for _, v := range printMsgs {
|
||||
v.DeletedAt = time.Now()
|
||||
if _, err = dao.UpdateEntity(db, v, "DeletedAt"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 简历连接
|
||||
conn, err := net.Dial("tcp", "www.jxcs.net:8000")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
clearPrint := fmt.Sprintf(`{"print_no_clear":%s}`, printNo)
|
||||
// 发送数据
|
||||
if _, err := conn.Write([]byte(clearPrint)); err != nil {
|
||||
return err
|
||||
}
|
||||
// 等待数据
|
||||
buf := make([]byte, 1024)
|
||||
n, err := conn.Read(buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if string(buf[:n]) != "ok" {
|
||||
return errors.New("缓存清理失败")
|
||||
}
|
||||
defer conn.Close()
|
||||
return err
|
||||
}
|
||||
|
||||
func DoPrintMsg(appID int, msgID, printNo, content string, orderNo string) (err error) {
|
||||
var (
|
||||
db = dao.GetDB()
|
||||
)
|
||||
//打印机必须绑定在该应用下才能打印
|
||||
if printers, _ := dao.GetPrinters(db, appID, printNo, 0, 0); len(printers) == 0 {
|
||||
return fmt.Errorf("未在该应用下获取到此打印机!print_no %v", printNo)
|
||||
}
|
||||
printMsg := &model.PrintMsg{
|
||||
PrintNo: printNo,
|
||||
Content: content,
|
||||
OrderNo: orderNo,
|
||||
MsgID: msgID,
|
||||
Status: event.PrintMsgWait,
|
||||
}
|
||||
|
||||
t, ok := event.PrintObject.GetPrintObj(printNo)
|
||||
if ok {
|
||||
t.Lock()
|
||||
defer t.Unlock()
|
||||
t.MsgMap[printNo] <- printMsg
|
||||
printMsg.Status = event.PrintMsgAlreadyLoad
|
||||
} /*else {
|
||||
t = event.NewTcpClient()
|
||||
event.BuildAllMap(t, printNo)
|
||||
event.PrintObject[printNo] = t
|
||||
|
||||
t.Lock()
|
||||
defer t.Unlock()
|
||||
t.MsgMap[printNo] <- printMsg
|
||||
printMsg.Status = event.PrintMsgAlreadyLoad
|
||||
}*/
|
||||
dao.WrapAddIDCULDEntity(printMsg, "")
|
||||
if err = dao.CreateEntity(db, printMsg); err != nil {
|
||||
return err
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
type GetPrintMsgResult struct {
|
||||
MsgID string `json:"msg_id"` //消息ID
|
||||
PrintNo string `json:"print_no"` //打印机编号
|
||||
OrderNo string `json:"order_no"` //订单序号
|
||||
Content string `json:"content"` //订单内容
|
||||
Status int `json:"status"` //打印状态
|
||||
Comment string `json:"comment"` //失败原因
|
||||
}
|
||||
|
||||
func GetPrintMsg(appID int, msgID string) (printMsg *GetPrintMsgResult, err error) {
|
||||
var (
|
||||
db = dao.GetDB()
|
||||
)
|
||||
if printMsgs, _ := dao.GetPrintMsgs2(db, "", msgID, model.PrintMsgAll, model.PrintMsgAll); len(printMsgs) > 0 {
|
||||
result := printMsgs[0]
|
||||
printMsg = &GetPrintMsgResult{
|
||||
MsgID: result.MsgID,
|
||||
PrintNo: result.PrintNo,
|
||||
OrderNo: result.OrderNo,
|
||||
Content: result.Content,
|
||||
Status: result.Status,
|
||||
Comment: result.Comment,
|
||||
}
|
||||
return printMsg, err
|
||||
} else {
|
||||
return printMsg, fmt.Errorf("未找到该消息!msg_id :%v", msgID)
|
||||
}
|
||||
}
|
||||
|
||||
func GetPrinterStatus(appID int, printNo string) (status int, err error) {
|
||||
var (
|
||||
db = dao.GetDB()
|
||||
)
|
||||
//看有没有
|
||||
printers, _ := dao.GetPrinters(db, appID, printNo, 0, 0)
|
||||
if len(printers) == 0 {
|
||||
return status, fmt.Errorf("该应用下未找到该打印机!print_no : %v", printNo)
|
||||
} else {
|
||||
return printers[0].Status + printers[0].IsOnline, nil // 当两个值都唯一时->在线正常
|
||||
//server := "print.jxcs.net:8000"
|
||||
//tcpAddr, err := net.ResolveTCPAddr("tcp4", server)
|
||||
//if err != nil {
|
||||
// //os.Exit(1)
|
||||
// return status, err
|
||||
//}
|
||||
//conn, err := net.DialTCP("tcp", nil, tcpAddr)
|
||||
//if err != nil {
|
||||
// return status, err
|
||||
//}
|
||||
//status = connHandler(conn, &PrintInfo{
|
||||
// PrintNo: printNo,
|
||||
// AppID: appID,
|
||||
//})
|
||||
//return status, nil
|
||||
}
|
||||
}
|
||||
@@ -71,7 +71,7 @@ func TransferLegacyWeixins(mobile string) (err error) {
|
||||
if user.Name == "" {
|
||||
user.Name = user.GetMobile()
|
||||
}
|
||||
userList, _, err2 := dao.GetUsers(db, 0, "", nil, nil, []string{v.Tel}, 0, -1)
|
||||
userList, _, err2 := dao.GetUsers(db, 0, "", "", nil, nil, []string{v.Tel}, 0, -1)
|
||||
if err = err2; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
package cms
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/globals/api2"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/authz/autils"
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/ebai"
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/elm"
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/jd"
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/mtwm"
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/weimob/wsc"
|
||||
)
|
||||
|
||||
func TestTransferLegacyWeixins(t *testing.T) {
|
||||
err := TransferLegacyWeixins("")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCasbin(t *testing.T) {
|
||||
userList, err := api2.RoleMan.GetRoleUserList(autils.NewStoreBossRole(100324))
|
||||
t.Log(utils.Format4Output(userList, false))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
@@ -1,26 +1,24 @@
|
||||
package cms
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"git.rosy.net.cn/baseapi/platformapi/mtunionapi"
|
||||
"git.rosy.net.cn/baseapi/platformapi/tbunionapi"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/ejyapi"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils/errlist"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/globals/api2"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/dingdingapi"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/auth2/authprovider/mobile"
|
||||
"git.rosy.net.cn/jx-callback/business/authz/autils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/ddmsg"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
@@ -41,61 +39,8 @@ type SysConfigLimit struct {
|
||||
}
|
||||
|
||||
var (
|
||||
serviceInfo map[string]interface{}
|
||||
allowUpdatePlaceFieldsMap = map[string]bool{
|
||||
"name": true,
|
||||
"enabled": true,
|
||||
"mtpsPrice": true,
|
||||
}
|
||||
|
||||
serviceInfo map[string]interface{}
|
||||
regexpMsgContentOpID = regexp.MustCompile(`"openid":"(.*?)"`)
|
||||
|
||||
receiveMsgUsersMap = map[string][]string{
|
||||
SendMsgTypeOpenStoreRequest: []string{
|
||||
"石锋",
|
||||
// "x",
|
||||
// "周扬",
|
||||
},
|
||||
SendMsgTypeSuggestRequest: []string{
|
||||
"石锋",
|
||||
// "x",
|
||||
// "周扬",
|
||||
// "苏尹岚",
|
||||
},
|
||||
}
|
||||
needConfirmRequestMap = map[string]int{
|
||||
SendMsgTypeOpenStoreRequest: 1,
|
||||
}
|
||||
|
||||
SysConfigLimitMap = map[string]*SysConfigLimit{
|
||||
model.ConfigSysEbaiBoxFee: &SysConfigLimit{
|
||||
ValueType: reflect.Int,
|
||||
MinValue: 0,
|
||||
MaxValue: 500,
|
||||
AfterChanged: func() (err error) {
|
||||
_, err = dao.SetStoreMapSyncStatus(dao.GetDB(), []int{model.VendorIDEBAI}, nil, model.SyncFlagModifiedMask)
|
||||
return err
|
||||
},
|
||||
},
|
||||
model.ConfigSysMtwmBoxFee: &SysConfigLimit{
|
||||
ValueType: reflect.Int,
|
||||
MinValue: 0,
|
||||
MaxValue: 500,
|
||||
AfterChanged: func() (err error) {
|
||||
_, err = dao.SetStoreMapSyncStatus(dao.GetDB(), []int{model.VendorIDMTWM}, nil, model.SyncFlagModifiedMask)
|
||||
return err
|
||||
},
|
||||
},
|
||||
model.ConfigSysMtwmSkuBoxFee: &SysConfigLimit{
|
||||
ValueType: reflect.Int,
|
||||
MinValue: 0,
|
||||
MaxValue: 50,
|
||||
AfterChanged: func() (err error) {
|
||||
_, err = dao.SetStoreSkuSyncStatus(dao.GetDB(), model.VendorIDMTWM, nil, nil, model.SyncFlagModifiedMask)
|
||||
return err
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
func InitServiceInfo(version string, buildTime time.Time, gitCommit string) {
|
||||
@@ -109,46 +54,65 @@ func InitServiceInfo(version string, buildTime time.Time, gitCommit string) {
|
||||
"buildTime": buildTimeStr,
|
||||
"gitCommit": gitCommit,
|
||||
"metaData": map[string]interface{}{
|
||||
"skuNamePrefix": model.SkuNamePrefixNames,
|
||||
"skuNameUnit": model.UnitNames,
|
||||
"skuSpecUnit": model.SpecUnitNames,
|
||||
"skuStatus": model.SkuStatusName,
|
||||
"storeDeliveryRangeType": model.DeliveryRangeTypeName,
|
||||
"storeDeliveryType": model.DeliveryTypeName,
|
||||
"storeStatus": model.StoreStatusName,
|
||||
"categoryType": model.CategoryTypeName,
|
||||
"vendorTypeName": model.VendorTypeName,
|
||||
"vendorName": model.VendorChineseNames,
|
||||
"vendorImg": model.VendorImg,
|
||||
"vendorColors": model.VendorColors,
|
||||
"orderStatus": model.OrderStatusName,
|
||||
"waybillStatus": model.WaybillStatusName,
|
||||
"orderTypeName": model.OrderTypeName,
|
||||
"taskStatusName": tasksch.TaskStatusName,
|
||||
"opRequestTypeName": model.RequestTypeName,
|
||||
"opRequestStatusName": model.RequestStatusName,
|
||||
"storeMsgSendStatusName": model.StoreMsgSendStatusName,
|
||||
"shopChineseNames": model.ShopChineseNames,
|
||||
"printerVendorInfo": model.PrinterVendorInfo,
|
||||
"printerStatusName": partner.PrinterStatusName,
|
||||
"purchaseVendorInfo": model.PurchaseVendorInfo,
|
||||
"afsReasonTypeName": model.AfsReasonTypeName,
|
||||
"afsAppealTypeName": model.AfsAppealTypeName,
|
||||
"actTypeName": model.ActTypeName,
|
||||
"actStatusName": model.ActStatusName,
|
||||
"actCreateTypeName": model.ActCreateTypeName,
|
||||
"storeAuditStatusName": model.StoreAuditStatusName,
|
||||
"configTypeName": model.ConfigTypeName,
|
||||
"autoSaleAt": AutoSaleAtStr,
|
||||
"userTypeName": model.UserTypeName,
|
||||
"storePriceTypeName": model.StorePriceTypeName,
|
||||
"payStatusName": model.PayStatusName,
|
||||
"refundStatusName": model.RefundStatusName,
|
||||
"autoReplyTypeName": model.AutoReplyTypeName,
|
||||
"complaintReasons": model.ComplaintReasons,
|
||||
"supplementType": model.SupplementTypeName,
|
||||
"operateType": model.OperateTypeName,
|
||||
"thingType": model.ThingTypeName,
|
||||
"apiFunctionName": model.ApiFunctionName,
|
||||
"vendorStatus": model.VendorStatus,
|
||||
"jobLimitCountType": `[{
|
||||
"id":` + utils.Int2Str(model.JobLimitCountTypePO) +
|
||||
`,"value": "每人一次"
|
||||
},{
|
||||
"id":` + utils.Int2Str(model.JobLimitCountTypePDO) +
|
||||
`,"value": "每人每天一次"
|
||||
},{
|
||||
"id":` + utils.Int2Str(model.JobLimitCountTypePWO) +
|
||||
`,"value": "每人每周一次"
|
||||
},{
|
||||
"id":` + utils.Int2Str(model.JobLimitCountTypeNoLimit) +
|
||||
`,"value": "不限次"
|
||||
}]`,
|
||||
"billTypeNames": model.BillTypeNames,
|
||||
"deliveryStatusName": model.DeliveryStatusName,
|
||||
"cashbackName": model.CashbackName,
|
||||
"consumeName": model.ConsumeName,
|
||||
"txWaybillNames": model.TxWaybillNames,
|
||||
"unionActTypeNames": map[int]map[int]interface{}{
|
||||
model.VendorIDMTWM: map[int]interface{}{
|
||||
mtunionapi.ActTypeQB: "券包推广",
|
||||
},
|
||||
model.VendorIDTB: map[int]interface{}{
|
||||
tbunionapi.TbElmActTypeBDH: "本地化",
|
||||
},
|
||||
model.VendorIDPDD: map[int]interface{}{
|
||||
1: "进行中的活动",
|
||||
},
|
||||
model.VendorIDJDShop: map[int]interface{}{
|
||||
2: "进行中",
|
||||
},
|
||||
},
|
||||
"unionOrderStatusName": model.UnionOrderStatusName,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -190,34 +154,6 @@ func GetPlaces(ctx *jxcontext.Context, keyword string, includeDisabled bool, par
|
||||
return places, dao.GetRows(nil, &places, sql, sqlParams)
|
||||
}
|
||||
|
||||
func UpdatePlaces(ctx *jxcontext.Context, places []map[string]interface{}, userName string) (num int64, err error) {
|
||||
if len(places) == 0 {
|
||||
return 0, ErrMissingInput
|
||||
}
|
||||
updateFields := []string{}
|
||||
for k := range places[0] {
|
||||
if allowUpdatePlaceFieldsMap[k] {
|
||||
updateFields = append(updateFields, k)
|
||||
}
|
||||
}
|
||||
for _, place := range places {
|
||||
if place["code"] == nil {
|
||||
return 0, ErrMissingInput
|
||||
}
|
||||
placeid := &model.Place{}
|
||||
valid := dao.NormalMakeMapByFieldList(place, updateFields, userName)
|
||||
if num, err = dao.UpdateEntityLogically(nil, placeid, valid, userName, utils.Params2Map("Code", place["code"])); err != nil {
|
||||
return num, err
|
||||
}
|
||||
}
|
||||
return num, err
|
||||
}
|
||||
|
||||
func UpdatePlace(ctx *jxcontext.Context, placeCode int, payload map[string]interface{}, userName string) (num int64, err error) {
|
||||
payload["code"] = placeCode
|
||||
return UpdatePlaces(ctx, []map[string]interface{}{payload}, userName)
|
||||
}
|
||||
|
||||
func GetCoordinateDistrictCode(ctx *jxcontext.Context, lng, lat float64) (code int, err error) {
|
||||
return api.AutonaviAPI.GetCoordinateDistrictCode(lng, lat), nil
|
||||
}
|
||||
@@ -228,175 +164,14 @@ func GetCoordinateCityInfo(ctx *jxcontext.Context, lng, lat float64) (name strin
|
||||
}
|
||||
|
||||
func SendMsg2Somebody(ctx *jxcontext.Context, mobileNum, verifyCode, msgType, msgContent string) (err error) {
|
||||
if needConfirmRequestMap[msgType] == 1 {
|
||||
if _, err = mobile.AutherObj.VerifySecret(mobileNum, verifyCode); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
db := dao.GetDB()
|
||||
//获取门店信息
|
||||
var (
|
||||
stores []*model.Store
|
||||
authBinds []*model.AuthBind
|
||||
order *model.GoodsOrder
|
||||
storeName string
|
||||
storeID int
|
||||
vendorOrderID string
|
||||
)
|
||||
if mobileNum != "" {
|
||||
sql := `
|
||||
SELECT * FROM store WHERE (tel1 = ? OR tel2 = ?) AND deleted_at = ?
|
||||
`
|
||||
sqlParams := []interface{}{mobileNum, mobileNum, utils.DefaultTimeValue}
|
||||
err = dao.GetRows(db, &stores, sql, sqlParams)
|
||||
if len(stores) > 0 {
|
||||
storeName = stores[0].Name
|
||||
storeID = stores[0].ID
|
||||
}
|
||||
if storeID == 0 {
|
||||
results := regexpMsgContentOpID.FindStringSubmatch(msgContent)
|
||||
if len(results) > 0 {
|
||||
sql3 := `
|
||||
SELECT * FROM auth_bind WHERE auth_id = ? OR auth_id2 = ?
|
||||
`
|
||||
sqlParams3 := []interface{}{results[1], results[1]}
|
||||
err = dao.GetRows(db, &authBinds, sql3, sqlParams3)
|
||||
if len(authBinds) > 0 {
|
||||
user, _ := dao.GetUserByID(db, "user_id", authBinds[0].UserID)
|
||||
mobileNum = *user.Mobile
|
||||
sqlParams4 := []interface{}{mobileNum, mobileNum, utils.DefaultTimeValue}
|
||||
err = dao.GetRows(db, &stores, sql, sqlParams4)
|
||||
if len(stores) > 0 {
|
||||
storeName = stores[0].Name
|
||||
storeID = stores[0].ID
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
results := regexpMsgContentOpID.FindStringSubmatch(msgContent)
|
||||
if len(results) > 0 {
|
||||
sql3 := `
|
||||
SELECT * FROM auth_bind WHERE auth_id = ? OR auth_id2 = ?
|
||||
`
|
||||
sqlParams3 := []interface{}{results[1], results[1]}
|
||||
err = dao.GetRows(db, &authBinds, sql3, sqlParams3)
|
||||
if len(authBinds) > 0 {
|
||||
user, _ := dao.GetUserByID(db, "user_id", authBinds[0].UserID)
|
||||
mobileNum = *user.Mobile
|
||||
sql4 := `
|
||||
SELECT * FROM store WHERE (tel1 = ? OR tel2 = ?) AND deleted_at = ?
|
||||
`
|
||||
sqlParams4 := []interface{}{mobileNum, mobileNum, utils.DefaultTimeValue}
|
||||
err = dao.GetRows(db, &stores, sql4, sqlParams4)
|
||||
if len(stores) > 0 {
|
||||
storeName = stores[0].Name
|
||||
storeID = stores[0].ID
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
sql2 := `
|
||||
SELECT *
|
||||
FROM goods_order
|
||||
WHERE IF(store_id <> '', store_id, jx_store_id) = ?
|
||||
ORDER BY order_created_at DESC
|
||||
LIMIT 1
|
||||
`
|
||||
sqlParams2 := []interface{}{storeID}
|
||||
err = dao.GetRow(db, &order, sql2, sqlParams2)
|
||||
if order != nil {
|
||||
vendorOrderID = order.VendorOrderID
|
||||
}
|
||||
if storeID == 0 {
|
||||
vendorOrderID = ""
|
||||
}
|
||||
msgContent = msgContent + " 门店名称:" + storeName + " 门店ID:" + utils.Int2Str(storeID) + " 最新订单号:" + vendorOrderID
|
||||
for _, v := range receiveMsgUsersMap[msgType] {
|
||||
user, err2 := dao.GetUserByID(db, "name", v)
|
||||
if err2 == nil {
|
||||
ddmsg.SendUserMessage(dingdingapi.MsgTyeText, user.GetID(), msgType, msgContent)
|
||||
} else if err == nil {
|
||||
err = err2
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func checkSysConfig(key, value string) (err error) {
|
||||
if limit := SysConfigLimitMap[key]; limit != nil {
|
||||
if limit.ValueType == reflect.Int {
|
||||
int64Value, err2 := strconv.ParseInt(value, 10, 64)
|
||||
if err = err2; err == nil {
|
||||
if int64Value < limit.MinValue || int64Value > limit.MaxValue {
|
||||
err = fmt.Errorf("配置%s,值%s超范围[%d,%d]", key, value, limit.MinValue, limit.MaxValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func onSysConfigChanged(key, value string) (err error) {
|
||||
if limit := SysConfigLimitMap[key]; limit != nil && limit.AfterChanged != nil {
|
||||
err = limit.AfterChanged()
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func checkConfig(opFlag int, configType, key, value string) (err error) {
|
||||
switch configType {
|
||||
case model.ConfigTypePricePack:
|
||||
if value != "" {
|
||||
pricePack := dao.PricePercentagePack2Obj(value)
|
||||
if pricePack == nil {
|
||||
err = fmt.Errorf("配置:%s不合法", value)
|
||||
}
|
||||
}
|
||||
case model.ConfigTypeFreightPack:
|
||||
if value != "" {
|
||||
freightPack := dao.FreightDeductionPack2Obj(value)
|
||||
if freightPack == nil {
|
||||
err = fmt.Errorf("配置:%s不合法", value)
|
||||
} else {
|
||||
var lastStage *model.FreightDeductionItem
|
||||
for _, v := range freightPack.FreightDeductionList {
|
||||
if lastStage != nil && lastStage.DeductFreight > v.DeductFreight {
|
||||
err = fmt.Errorf("免运设置不合理:门槛:%s,免运金额:%s,门槛:%s,免运金额:%s",
|
||||
jxutils.IntPrice2StandardString(int64(lastStage.BeginPrice)), jxutils.IntPrice2StandardString(int64(lastStage.DeductFreight)),
|
||||
jxutils.IntPrice2StandardString(int64(v.BeginPrice)), jxutils.IntPrice2StandardString(int64(v.DeductFreight)))
|
||||
return err
|
||||
}
|
||||
lastStage = v
|
||||
}
|
||||
}
|
||||
}
|
||||
case model.ConfigTypeBank:
|
||||
if value != "" {
|
||||
if model.BankName[key] == "" {
|
||||
err = fmt.Errorf("此银行代码:%s不支持,请联系开发", value)
|
||||
}
|
||||
}
|
||||
case model.ConfigTypeRole:
|
||||
case model.ConfigTypeSys:
|
||||
if opFlag&( /*model.SyncFlagNewMask|*/ model.SyncFlagDeletedMask) != 0 {
|
||||
err = fmt.Errorf("系统参数只支持修改或添加,不支持删除")
|
||||
} else {
|
||||
err = checkSysConfig(key, value)
|
||||
}
|
||||
case model.ConfigTypeJxStore:
|
||||
case model.ConfigTypeCookie:
|
||||
case model.ConfigTypeDiscountCard:
|
||||
default:
|
||||
err = fmt.Errorf("当前只支持配置:%s, 传入的配置类型:%s", utils.Format4Output(model.ConfigTypeName, true), configType)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func AddConfig(ctx *jxcontext.Context, key, configType, value string) (err error) {
|
||||
if err = checkConfig(model.SyncFlagNewMask, configType, key, value); err != nil {
|
||||
return err
|
||||
}
|
||||
// if err = checkConfig(model.SyncFlagNewMask, configType, key, value); err != nil {
|
||||
// return err
|
||||
// }
|
||||
|
||||
db := dao.GetDB()
|
||||
conf := &model.NewConfig{
|
||||
@@ -407,41 +182,21 @@ func AddConfig(ctx *jxcontext.Context, key, configType, value string) (err error
|
||||
dao.WrapAddIDCULDEntity(conf, ctx.GetUserName())
|
||||
err = dao.CreateEntity(db, conf)
|
||||
if configType == model.ConfigTypeSys && err == nil {
|
||||
err = onSysConfigChanged(key, value)
|
||||
// err = onSysConfigChanged(key, value)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func DeleteConfig(ctx *jxcontext.Context, key, configType string) (err error) {
|
||||
if err = checkConfig(model.SyncFlagDeletedMask, configType, key, ""); err != nil {
|
||||
return err
|
||||
}
|
||||
// if err = checkConfig(model.SyncFlagDeletedMask, configType, key, ""); err != nil {
|
||||
// return err
|
||||
// }
|
||||
db := dao.GetDB()
|
||||
switch configType {
|
||||
case model.ConfigTypePricePack:
|
||||
storeMapList, err2 := dao.GetStoresMapList(db, nil, nil, nil, model.StoreStatusAll, model.StoreIsSyncYes, key, "")
|
||||
if err = err2; err == nil {
|
||||
var storeInfo []string
|
||||
for _, v := range storeMapList {
|
||||
storeInfo = append(storeInfo, fmt.Sprintf("门店:%d, 平台:%s", v.StoreID, model.VendorChineseNames[v.VendorID]))
|
||||
}
|
||||
if len(storeInfo) > 0 {
|
||||
err = fmt.Errorf("还有门店在使用价格包:%s,门店信息:%s", key, strings.Join(storeInfo, ","))
|
||||
}
|
||||
}
|
||||
|
||||
case model.ConfigTypeFreightPack:
|
||||
storeMapList, err2 := dao.GetStoresMapList(db, nil, nil, nil, model.StoreStatusAll, model.StoreIsSyncYes, "", "")
|
||||
if err = err2; err == nil {
|
||||
var storeInfo []string
|
||||
for _, v := range storeMapList {
|
||||
if v.FreightDeductionPack == key {
|
||||
storeInfo = append(storeInfo, fmt.Sprintf("门店:%d, 平台:%s", v.StoreID, model.VendorChineseNames[v.VendorID]))
|
||||
}
|
||||
}
|
||||
if len(storeInfo) > 0 {
|
||||
err = fmt.Errorf("还有门店在使用价格包:%s,门店信息:%s", key, strings.Join(storeInfo, ","))
|
||||
}
|
||||
}
|
||||
|
||||
case model.ConfigTypeBank:
|
||||
//todo
|
||||
return fmt.Errorf("暂不支持删除银行")
|
||||
@@ -449,7 +204,7 @@ func DeleteConfig(ctx *jxcontext.Context, key, configType string) (err error) {
|
||||
errList := errlist.New()
|
||||
userIDs, err2 := api2.RoleMan.GetRoleUserList(autils.NewRole(key, 0))
|
||||
if err = err2; err == nil && len(userIDs) > 0 {
|
||||
userList, totalCount, err2 := dao.GetUsers(dao.GetDB(), 0, "", userIDs, nil, nil, 0, -1)
|
||||
userList, totalCount, err2 := dao.GetUsers(dao.GetDB(), 0, "", "", userIDs, nil, nil, 0, -1)
|
||||
if err = err2; err == nil && totalCount > 0 {
|
||||
// todo
|
||||
// err = fmt.Errorf("还有人员在使用角色:%s,人员信息:%s", key, utils.MustMarshal(utils.Struct2Map(userList, "compact")))
|
||||
@@ -457,14 +212,7 @@ func DeleteConfig(ctx *jxcontext.Context, key, configType string) (err error) {
|
||||
}
|
||||
}
|
||||
errList.AddErr(err)
|
||||
storeList, err2 := dao.GetStoreList(db, nil, nil, nil, nil, key)
|
||||
if err = err2; err == nil && len(storeList) > 0 {
|
||||
storeIDs := make([]int, len(storeList))
|
||||
for k, v := range storeList {
|
||||
storeIDs[k] = v.ID
|
||||
}
|
||||
err = fmt.Errorf("还有门店在使用角色:%s,门店信息:%s", key, utils.MustMarshal(storeIDs))
|
||||
}
|
||||
|
||||
errList.AddErr(err)
|
||||
err = errList.GetErrListAsOne()
|
||||
}
|
||||
@@ -475,7 +223,7 @@ func DeleteConfig(ctx *jxcontext.Context, key, configType string) (err error) {
|
||||
})
|
||||
}
|
||||
if configType == model.ConfigTypeSys && err == nil {
|
||||
err = onSysConfigChanged(key, "")
|
||||
// err = onSysConfigChanged(key, "")
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -484,80 +232,35 @@ func UpdateConfig(ctx *jxcontext.Context, key, configType, value string) (hint s
|
||||
if key == "" {
|
||||
return "", fmt.Errorf("修改配置必须给定key")
|
||||
}
|
||||
if err = checkConfig(model.SyncFlagModifiedMask, configType, key, value); err != nil {
|
||||
return "", err
|
||||
}
|
||||
hint = "1"
|
||||
|
||||
db := dao.GetDB()
|
||||
dao.Begin(db)
|
||||
txDB, _ := dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
dao.Rollback(db)
|
||||
dao.Rollback(db, txDB)
|
||||
panic(r)
|
||||
}
|
||||
}()
|
||||
configList, err := dao.QueryConfigs(db, key, configType, "")
|
||||
if err != nil {
|
||||
dao.Rollback(db)
|
||||
dao.Rollback(db, txDB)
|
||||
return "", err
|
||||
}
|
||||
if _, err = dao.UpdateEntityLogically(db, configList[0], map[string]interface{}{
|
||||
"Value": value,
|
||||
}, ctx.GetUserName(), nil); err != nil {
|
||||
dao.Rollback(db)
|
||||
dao.Rollback(db, txDB)
|
||||
return "", err
|
||||
}
|
||||
switch configType {
|
||||
case model.ConfigTypePricePack:
|
||||
storeMapList, err := dao.GetStoresMapList(db, nil, nil, nil, model.StoreStatusAll, model.StoreIsSyncYes, key, "")
|
||||
if err != nil {
|
||||
dao.Rollback(db)
|
||||
return "", err
|
||||
}
|
||||
dao.Commit(db)
|
||||
vendorStoreMap := make(map[int][]int)
|
||||
for _, v := range storeMapList {
|
||||
vendorStoreMap[v.VendorID] = append(vendorStoreMap[v.VendorID], v.StoreID)
|
||||
}
|
||||
for vendorID, storeIDs := range vendorStoreMap {
|
||||
if vendorID != model.VendorIDJX {
|
||||
dao.SetStoreSkuSyncStatus(db, vendorID, storeIDs, nil, model.SyncFlagPriceMask)
|
||||
} else {
|
||||
hint, err = ReCalculateJxPrice(db, ctx, storeIDs)
|
||||
}
|
||||
}
|
||||
case model.ConfigTypeFreightPack:
|
||||
dao.Commit(db)
|
||||
storeMapList, err := dao.GetStoresMapList(db, nil, nil, nil, model.StoreStatusAll, model.StoreIsSyncYes, "", "")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
for _, v := range storeMapList {
|
||||
var storeMapList2 []*model.StoreMap
|
||||
if v.FreightDeductionPack == key {
|
||||
storeMapList2 = append(storeMapList2, v)
|
||||
}
|
||||
if len(storeMapList2) > 0 {
|
||||
task := tasksch.NewParallelTask("同步门店配送免运", tasksch.NewParallelConfig().SetIsContinueWhenError(true), ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
storeMap := batchItemList[0].(*model.StoreMap)
|
||||
_, err = CurVendorSync.SyncStore(ctx, db, storeMap.VendorID, storeMap.StoreID, false, ctx.GetUserName())
|
||||
return retVal, err
|
||||
}, storeMapList2)
|
||||
tasksch.HandleTask(task, nil, true).Run()
|
||||
if len(storeMapList2) < 5 {
|
||||
_, err = task.GetResult(0)
|
||||
} else {
|
||||
hint = task.GetID()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
dao.Commit(db)
|
||||
dao.Commit(db, txDB)
|
||||
}
|
||||
if configType == model.ConfigTypeSys && err == nil {
|
||||
err = onSysConfigChanged(key, value)
|
||||
// err = onSysConfigChanged(key, value)
|
||||
}
|
||||
return hint, err
|
||||
}
|
||||
@@ -566,16 +269,105 @@ func QueryConfigs(key, configType, keyword string) (configList []*model.NewConfi
|
||||
return dao.QueryConfigs(dao.GetDB(), key, configType, keyword)
|
||||
}
|
||||
|
||||
func GetCityBankBranches(ctx *jxcontext.Context, cityCode int, bankCode string) (info map[int]map[string][]string, err error) {
|
||||
list, err := dao.GetCityBankBranches(dao.GetDB(), cityCode, bankCode)
|
||||
if err == nil && len(list) > 0 {
|
||||
info = make(map[int]map[string][]string)
|
||||
for _, v := range list {
|
||||
if info[v.CityCode] == nil {
|
||||
info[v.CityCode] = make(map[string][]string)
|
||||
}
|
||||
info[v.CityCode][v.PayeeBankCode] = append(info[v.CityCode][v.PayeeBankCode], v.PayeeBankBranchName)
|
||||
func InitStation(ctx *jxcontext.Context) (err error) {
|
||||
var (
|
||||
db = dao.GetDB()
|
||||
stationMap = make(map[string]*model.StationInfo)
|
||||
stationEjyMap = make(map[string]*ejyapi.GetStationListResult)
|
||||
addList []*model.StationInfo
|
||||
updateList []*model.StationInfo
|
||||
deleteList []*model.StationInfo
|
||||
)
|
||||
api.EjyAPI.SetTimestamp(time.Now().Unix())
|
||||
if stations, err := dao.GetStationList(db); len(stations) > 0 && err == nil {
|
||||
for _, v := range stations {
|
||||
stationMap[v.StationID] = v
|
||||
}
|
||||
}
|
||||
return info, err
|
||||
if getStationListResult, err := api.EjyAPI.GetStationList(); len(getStationListResult) > 0 && err == nil {
|
||||
for _, v := range getStationListResult {
|
||||
stationEjyMap[v.StationID] = v
|
||||
if stationMap[v.StationID] == nil {
|
||||
addList = append(addList, EjyStationToStationInfo(v))
|
||||
} else {
|
||||
updateList = append(updateList, stationMap[v.StationID])
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, v := range stationMap {
|
||||
if stationEjyMap[v.StationID] == nil {
|
||||
deleteList = append(deleteList, v)
|
||||
}
|
||||
}
|
||||
task := tasksch.NewParallelTask("InitStation", tasksch.NewParallelConfig().SetParallelCount(1).SetIsContinueWhenError(true), ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
step := batchItemList[0].(int)
|
||||
switch step {
|
||||
case 0:
|
||||
if len(addList) > 0 {
|
||||
err = dao.CreateMultiEntities(db, addList)
|
||||
}
|
||||
case 1:
|
||||
if len(updateList) > 0 {
|
||||
task := tasksch.NewParallelTask("updateList", tasksch.NewParallelConfig().SetParallelCount(1).SetIsContinueWhenError(true), ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
station := batchItemList[0].(*model.StationInfo)
|
||||
dao.UpdateEntity(db, station)
|
||||
return retVal, err
|
||||
}, updateList)
|
||||
tasksch.HandleTask(task, nil, true).Run()
|
||||
_, err = task.GetResult(0)
|
||||
}
|
||||
case 2:
|
||||
if len(deleteList) > 0 {
|
||||
task := tasksch.NewParallelTask("deleteList", tasksch.NewParallelConfig().SetParallelCount(1).SetIsContinueWhenError(true), ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
station := batchItemList[0].(*model.StationInfo)
|
||||
dao.DeleteEntity(db, station)
|
||||
return retVal, err
|
||||
}, deleteList)
|
||||
tasksch.HandleTask(task, nil, true).Run()
|
||||
_, err = task.GetResult(0)
|
||||
}
|
||||
}
|
||||
return retVal, err
|
||||
}, []int{0, 1, 2})
|
||||
tasksch.HandleTask(task, nil, true).Run()
|
||||
_, err = task.GetResult(0)
|
||||
return err
|
||||
}
|
||||
|
||||
func EjyStationToStationInfo(station *ejyapi.GetStationListResult) (stationInfo *model.StationInfo) {
|
||||
stationInfo = &model.StationInfo{
|
||||
StationID: station.StationID,
|
||||
StationName: station.StationName,
|
||||
ProvinceName: station.ProvinceName,
|
||||
ProvinceID: station.ProvinceID,
|
||||
CityName: station.CityName,
|
||||
Latitude: utils.Str2Float64(station.Latitude),
|
||||
Longitude: utils.Str2Float64(station.Longitude),
|
||||
Location: station.Location,
|
||||
StarNum: station.StarNum,
|
||||
Phone: station.Phone,
|
||||
StationPic: station.StationPic,
|
||||
StationBannerPic: station.StationBannerPic,
|
||||
District: station.District,
|
||||
CityID: station.CityID,
|
||||
StationType: station.StationType,
|
||||
}
|
||||
if station.Prices != nil {
|
||||
if data, err := json.Marshal(station.Prices); err == nil {
|
||||
stationInfo.Prices = string(data)
|
||||
}
|
||||
}
|
||||
if station.Adverts != nil {
|
||||
if data, err := json.Marshal(station.Adverts); err == nil {
|
||||
stationInfo.Adverts = string(data)
|
||||
}
|
||||
}
|
||||
return stationInfo
|
||||
}
|
||||
|
||||
func GetStationList(ctx *jxcontext.Context, stationName string, cityCode int, lat, lng float64, oilCode string, sortType, offset, pageSize int) (pageInfo *model.PagedInfo, err error) {
|
||||
return dao.GetStationInfoList(dao.GetDB(), stationName, cityCode, lat, lng, oilCode, sortType, offset, pageSize)
|
||||
}
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
package cms
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/jx-callback/globals/api2"
|
||||
"git.rosy.net.cn/jx-callback/globals/testinit"
|
||||
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/ebai"
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/elm"
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/jd"
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/mtwm"
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/weimob/wsc"
|
||||
)
|
||||
|
||||
func init() {
|
||||
testinit.Init()
|
||||
api2.Init()
|
||||
}
|
||||
2303
business/jxstore/cms/job.go
Normal file
2303
business/jxstore/cms/job.go
Normal file
File diff suppressed because it is too large
Load Diff
@@ -65,13 +65,13 @@ func GetStoreMessages(ctx *jxcontext.Context, msgIDs, storeIDs, types []int, fro
|
||||
pageSize = jxutils.FormalizePageSize(pageSize)
|
||||
sqlParams = append(sqlParams, pageSize, offset)
|
||||
db := dao.GetDB()
|
||||
dao.Begin(db)
|
||||
defer dao.Commit(db)
|
||||
txDB, _ := dao.Begin(db)
|
||||
defer dao.Commit(db, txDB)
|
||||
var msgList []*model.Message
|
||||
// globals.SugarLogger.Debug(sql)
|
||||
if err = dao.GetRows(db, &msgList, sql, sqlParams...); err == nil {
|
||||
if err = dao.GetRowsTx(txDB, &msgList, sql, sqlParams...); err == nil {
|
||||
pagedInfo = &model.PagedInfo{
|
||||
TotalCount: dao.GetLastTotalRowCount(db),
|
||||
TotalCount: dao.GetLastTotalRowCountTx(txDB),
|
||||
Data: msgList,
|
||||
}
|
||||
}
|
||||
@@ -120,14 +120,14 @@ func GetStoreMessageStatuses(ctx *jxcontext.Context, msgIDs, storeIDs []int, fro
|
||||
sql += " LIMIT ? OFFSET ?"
|
||||
sqlParams = append(sqlParams, jxutils.FormalizePageSize(pageSize), offset)
|
||||
db := dao.GetDB()
|
||||
dao.Begin(db)
|
||||
defer dao.Commit(db)
|
||||
txDB, _ := dao.Begin(db)
|
||||
defer dao.Commit(db, txDB)
|
||||
var msgStatusList []*MessageStatusExt
|
||||
// globals.SugarLogger.Debug(sql)
|
||||
// globals.SugarLogger.Debug(utils.Format4Output(sqlParams, false))
|
||||
if err = dao.GetRows(db, &msgStatusList, sql, sqlParams...); err == nil {
|
||||
if err = dao.GetRowsTx(txDB, &msgStatusList, sql, sqlParams...); err == nil {
|
||||
pagedInfo = &model.PagedInfo{
|
||||
TotalCount: dao.GetLastTotalRowCount(db),
|
||||
TotalCount: dao.GetLastTotalRowCountTx(txDB),
|
||||
Data: msgStatusList,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
package cms
|
||||
519
business/jxstore/cms/order.go
Normal file
519
business/jxstore/cms/order.go
Normal 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)
|
||||
}
|
||||
@@ -31,16 +31,16 @@ func AddMenu(ctx *jxcontext.Context, menu *model.Menu) (err error) {
|
||||
if len(menus) > 0 {
|
||||
return fmt.Errorf("添加失败!已存在相同名称的 menu name : %v", menu.Name)
|
||||
}
|
||||
dao.Begin(db)
|
||||
txDB, _ := dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
dao.Rollback(db)
|
||||
dao.Rollback(db, txDB)
|
||||
panic(r)
|
||||
}
|
||||
}()
|
||||
dao.WrapAddIDCULDEntity(menu, ctx.GetUserName())
|
||||
err = dao.CreateEntity(db, menu)
|
||||
dao.Commit(db)
|
||||
dao.Commit(db, txDB)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -54,10 +54,10 @@ func UpdateMenu(ctx *jxcontext.Context, menuID int, payload map[string]interface
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
dao.Begin(db)
|
||||
txDB, _ := dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
dao.Rollback(db)
|
||||
dao.Rollback(db, txDB)
|
||||
panic(r)
|
||||
}
|
||||
}()
|
||||
@@ -65,7 +65,7 @@ func UpdateMenu(ctx *jxcontext.Context, menuID int, payload map[string]interface
|
||||
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)
|
||||
dao.Rollback(db, txDB)
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
@@ -73,7 +73,7 @@ func UpdateMenu(ctx *jxcontext.Context, menuID int, payload map[string]interface
|
||||
menu.DeletedAt = time.Now()
|
||||
num, err = dao.UpdateEntity(db, menu, "DeletedAt")
|
||||
}
|
||||
dao.Commit(db)
|
||||
dao.Commit(db, txDB)
|
||||
return num, err
|
||||
}
|
||||
|
||||
@@ -92,16 +92,16 @@ func AddRole(ctx *jxcontext.Context, name string) (err error) {
|
||||
role := &model.Role{
|
||||
Name: name,
|
||||
}
|
||||
dao.Begin(db)
|
||||
txDB, _ := dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
dao.Rollback(db)
|
||||
dao.Rollback(db, txDB)
|
||||
panic(r)
|
||||
}
|
||||
}()
|
||||
dao.WrapAddIDCULDEntity(role, ctx.GetUserName())
|
||||
err = dao.CreateEntity(db, role)
|
||||
dao.Commit(db)
|
||||
dao.Commit(db, txDB)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -118,10 +118,10 @@ func UpdateRole(ctx *jxcontext.Context, roleID int, name string, isDelete bool)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
dao.Begin(db)
|
||||
txDB, _ := dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
dao.Rollback(db)
|
||||
dao.Rollback(db, txDB)
|
||||
panic(r)
|
||||
}
|
||||
}()
|
||||
@@ -134,7 +134,7 @@ func UpdateRole(ctx *jxcontext.Context, roleID int, name string, isDelete bool)
|
||||
role.DeletedAt = time.Now()
|
||||
num, err = dao.UpdateEntity(db, role, "DeletedAt")
|
||||
}
|
||||
dao.Commit(db)
|
||||
dao.Commit(db, txDB)
|
||||
return num, err
|
||||
}
|
||||
|
||||
@@ -177,10 +177,10 @@ func UpdateUserRole(ctx *jxcontext.Context, userIDs []string, roleIDs []int) (er
|
||||
}
|
||||
}
|
||||
}
|
||||
dao.Begin(db)
|
||||
txDB, _ := dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
dao.Rollback(db)
|
||||
dao.Rollback(db, txDB)
|
||||
panic(r)
|
||||
}
|
||||
}()
|
||||
@@ -208,7 +208,7 @@ func UpdateUserRole(ctx *jxcontext.Context, userIDs []string, roleIDs []int) (er
|
||||
}
|
||||
}
|
||||
}
|
||||
dao.Commit(db)
|
||||
dao.Commit(db, txDB)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -251,10 +251,10 @@ func UpdateRoleMenu(ctx *jxcontext.Context, roleIDs, menuIDs []int) (err error)
|
||||
}
|
||||
}
|
||||
}
|
||||
dao.Begin(db)
|
||||
txDB, _ := dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
dao.Rollback(db)
|
||||
dao.Rollback(db, txDB)
|
||||
panic(r)
|
||||
}
|
||||
}()
|
||||
@@ -282,6 +282,6 @@ func UpdateRoleMenu(ctx *jxcontext.Context, roleIDs, menuIDs []int) (err error)
|
||||
}
|
||||
}
|
||||
}
|
||||
dao.Commit(db)
|
||||
dao.Commit(db, txDB)
|
||||
return err
|
||||
}
|
||||
|
||||
50
business/jxstore/cms/recharge_server.go
Normal file
50
business/jxstore/cms/recharge_server.go
Normal file
@@ -0,0 +1,50 @@
|
||||
package cms
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"git.rosy.net.cn/baseapi/platformapi/recharge_phone_bill"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
"time"
|
||||
)
|
||||
|
||||
// QueryUserRecharge 用户查询充值列表
|
||||
func QueryUserRecharge(userId []string, mobile, orderId string, page, pageSize int, startTime, endTime string, rechargeStatus int) ([]*model.RechargeUserModelData, int, error) {
|
||||
if page == 0 {
|
||||
page = 1
|
||||
}
|
||||
if pageSize == 0 {
|
||||
pageSize = 10
|
||||
}
|
||||
var start time.Time
|
||||
var end time.Time
|
||||
if startTime != "" {
|
||||
start = utils.Str2Time(startTime)
|
||||
}
|
||||
if endTime != "" {
|
||||
end = utils.Str2Time(endTime)
|
||||
}
|
||||
|
||||
return dao.QueryRechargeRecommend(userId, mobile, orderId, page, pageSize, start, end, rechargeStatus)
|
||||
}
|
||||
|
||||
// QueryUserOrderDetail 用户查询订单详情
|
||||
func QueryUserOrderDetail(orderId, mobile string) ([]recharge_phone_bill.QueryOrderDetailResList, error) {
|
||||
data, err := api.TelephoneAPI.QueryOrderDetail("", orderId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
have := false
|
||||
for _, v := range data {
|
||||
if v.Mobile == mobile {
|
||||
have = true
|
||||
}
|
||||
}
|
||||
|
||||
if have {
|
||||
return data, err
|
||||
}
|
||||
return nil, errors.New("参数电话号码异常")
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,35 +0,0 @@
|
||||
package cms
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
)
|
||||
|
||||
func TestGetStoresVendorSnapshot(t *testing.T) {
|
||||
result, err := GetStoresVendorSnapshot(jxcontext.AdminCtx, nil, []int{model.VendorIDEBAI}, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(utils.Format4Output(result, false))
|
||||
t.Log(len(result))
|
||||
}
|
||||
|
||||
func TestSendAlarmVendorSnapshot(t *testing.T) {
|
||||
db := dao.GetDB()
|
||||
prevSnapshotList, _ := dao.GetVendorStoreSnapshot(db, utils.Str2Time("2019-09-19 11:00:00"))
|
||||
curSnapshotList, _ := dao.GetVendorStoreSnapshot(db, utils.Str2Time("2019-09-19 15:00:00"))
|
||||
err := SendAlarmVendorSnapshot(jxcontext.AdminCtx, nil, prevSnapshotList, curSnapshotList)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateVendorStoreStatusBySnapshot(t *testing.T) {
|
||||
db := dao.GetDB()
|
||||
curSnapshotList, _ := dao.GetVendorStoreSnapshot(db, utils.Str2Time("2019-07-30 08:00:00"))
|
||||
updateVendorStoreStatusBySnapshot(db, curSnapshotList)
|
||||
}
|
||||
@@ -1,127 +0,0 @@
|
||||
package cms
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
)
|
||||
|
||||
type StoreManager struct {
|
||||
}
|
||||
|
||||
var (
|
||||
FixedStoreManager *StoreManager
|
||||
)
|
||||
|
||||
func init() {
|
||||
FixedStoreManager = &StoreManager{}
|
||||
partner.InitStoreManager(FixedStoreManager)
|
||||
}
|
||||
|
||||
func (s *StoreManager) OnStoreStatusChanged(vendorStoreID string, vendorID int, storeStatus int) (err error) {
|
||||
return err
|
||||
globals.SugarLogger.Debugf("OnStoreStatusChanged venvendorStoreID:%s, storeStatus:%d", vendorStoreID, storeStatus)
|
||||
db := dao.GetDB()
|
||||
storeDetail, err := dao.GetStoreDetailByVendorStoreID(db, vendorStoreID, vendorID)
|
||||
if err == nil {
|
||||
var storeKV, storeMapKV map[string]interface{}
|
||||
if storeStatus == model.StoreStatusOpened {
|
||||
if storeDetail.Status != model.StoreStatusOpened {
|
||||
storeKV = map[string]interface{}{
|
||||
"Status": model.StoreStatusOpened,
|
||||
}
|
||||
}
|
||||
if storeDetail.VendorStatus != model.StoreStatusOpened {
|
||||
storeMapKV = map[string]interface{}{
|
||||
"Status": model.StoreStatusOpened,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if storeDetail.Status == model.StoreStatusOpened {
|
||||
if storeDetail.VendorStatus != storeStatus {
|
||||
storeMapKV = map[string]interface{}{
|
||||
"Status": storeStatus,
|
||||
}
|
||||
}
|
||||
} else if storeDetail.Status <= storeStatus {
|
||||
if storeDetail.VendorStatus != model.StoreStatusOpened {
|
||||
storeMapKV = map[string]interface{}{
|
||||
"Status": model.StoreStatusOpened,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if err == nil && (storeKV != nil || storeMapKV != nil) {
|
||||
dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil || err != nil {
|
||||
dao.Rollback(db)
|
||||
if r != nil {
|
||||
panic(r)
|
||||
}
|
||||
}
|
||||
}()
|
||||
if storeKV != nil {
|
||||
globals.SugarLogger.Debugf("OnStoreStatusChanged venvendorStoreID:%s, storeKV:%s", vendorStoreID, utils.Format4Output(storeKV, true))
|
||||
store := &model.Store{}
|
||||
store.ID = storeDetail.Store.ID
|
||||
if err = utils.CallFuncLogError(func() error {
|
||||
_, err = dao.UpdateEntityLogically(db, store, storeKV, model.AdminName, nil)
|
||||
return err
|
||||
}, "OnStoreStatusChanged Update Store venvendorStoreID:%s", vendorStoreID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if storeMapKV != nil {
|
||||
globals.SugarLogger.Debugf("OnStoreStatusChanged venvendorStoreID:%s, storeMapKV:%s", vendorStoreID, utils.Format4Output(storeMapKV, true))
|
||||
if err = utils.CallFuncLogError(func() error {
|
||||
_, err = dao.UpdateEntityLogically(db, &model.StoreMap{}, storeMapKV, model.AdminName, map[string]interface{}{
|
||||
model.FieldStoreID: storeDetail.Store.ID,
|
||||
model.FieldVendorID: vendorID,
|
||||
model.FieldDeletedAt: utils.DefaultTimeValue,
|
||||
})
|
||||
return err
|
||||
}, "OnStoreStatusChanged Update StoreMap venvendorStoreID:%s", vendorStoreID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if storeStatus != model.StoreStatusOpened {
|
||||
// 因为storeStatus != model.StoreStatusOpened不会修改京西门店的状态,所以直接用storeDetail.Status是合适的
|
||||
if err = utils.CallFuncLogError(func() error {
|
||||
return dao.FormalizeStoreStatus(db, storeDetail.Store.ID, storeDetail.Status)
|
||||
}, "OnStoreStatusChanged FormalizeStoreStatus venvendorStoreID:%s", vendorStoreID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
dao.Commit(db)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *StoreManager) OnCourierStoreStatusChanged(ctx *jxcontext.Context, vendorStoreID string, vendorID int, auditStatus int) (err error) {
|
||||
if vendorStoreID != "" {
|
||||
db := dao.GetDB()
|
||||
_, err2 := dao.GetStoreDetail2(db, 0, vendorStoreID, vendorID)
|
||||
if err = err2; err == nil {
|
||||
status := model.StoreStatusOpened
|
||||
if auditStatus != model.StoreAuditStatusOnline {
|
||||
status = model.StoreStatusDisabled
|
||||
}
|
||||
_, err = dao.UpdateEntityLogically(db, &model.StoreCourierMap{}, map[string]interface{}{
|
||||
model.FieldStatus: status,
|
||||
"AuditStatus": auditStatus,
|
||||
}, ctx.GetUserName(), map[string]interface{}{
|
||||
model.FieldVendorStoreID: vendorStoreID,
|
||||
model.FieldVendorID: vendorID,
|
||||
})
|
||||
} else if dao.IsNoRowsError(err) {
|
||||
err = nil
|
||||
}
|
||||
}
|
||||
globals.SugarLogger.Debugf("OnCourierStoreStatusChanged vendorStoreID:%s, auditStatus:%d, err:%v", vendorStoreID, auditStatus, err)
|
||||
return err
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,604 +0,0 @@
|
||||
package cms
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/baseapi/utils/errlist"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/business/partner/putils"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
)
|
||||
|
||||
type MultiStoreVendorInfo struct {
|
||||
VendorID int
|
||||
OrgCode string
|
||||
}
|
||||
|
||||
func CombineVendorIDAndOrgCode(vendorID int, orgCode string) string {
|
||||
return fmt.Sprintf("%d-%s", vendorID, orgCode)
|
||||
}
|
||||
|
||||
func getMultiStoreVendorInfoList() (list []*MultiStoreVendorInfo) {
|
||||
vendorIDs := partner.GetMultiStoreVendorIDs()
|
||||
for _, vendorID := range vendorIDs {
|
||||
orgCodeList := partner.CurAPIManager.GetAppOrgCodeList(vendorID)
|
||||
for _, v := range orgCodeList {
|
||||
list = append(list, &MultiStoreVendorInfo{
|
||||
VendorID: vendorID,
|
||||
OrgCode: v,
|
||||
})
|
||||
}
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
func syncCategories(ctx *jxcontext.Context, db *dao.DaoDB, parentTask tasksch.ITask, catList []*dao.SkuStoreCatInfo, isAsync bool) (hint string, err error) {
|
||||
if len(catList) > 0 {
|
||||
// todo 按vendorID orgCode合并操作
|
||||
task := tasksch.NewParallelTask(fmt.Sprintf("同步分类2:%d", len(catList)), tasksch.NewParallelConfig().SetIsContinueWhenError(true), ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
catVendorInfo := batchItemList[0].(*dao.SkuStoreCatInfo)
|
||||
if catVendorInfo.Level != 1 && catVendorInfo.ParentVendorCatID == "" {
|
||||
return nil, fmt.Errorf("%d的父目录%d没有同步", catVendorInfo.ID, catVendorInfo.ParentID)
|
||||
}
|
||||
if catVendorInfo.MapID == 0 {
|
||||
return nil, fmt.Errorf("分类:%d的数据异常", catVendorInfo.ID)
|
||||
}
|
||||
if multiStoresHandler, ok := partner.GetPurchasePlatformFromVendorID(catVendorInfo.VendorID).(partner.IMultipleStoresHandler); ok {
|
||||
if model.IsSyncStatusDelete(catVendorInfo.CatSyncStatus) { //删除
|
||||
if !dao.IsVendorThingIDEmpty(catVendorInfo.VendorCatID) &&
|
||||
model.IsSyncStatusNeedDelete(catVendorInfo.CatSyncStatus) {
|
||||
err = multiStoresHandler.DeleteCategory2(ctx, catVendorInfo.VendorOrgCode, catVendorInfo.VendorCatID)
|
||||
}
|
||||
} else if model.IsSyncStatusNew(catVendorInfo.CatSyncStatus) { // 新增
|
||||
err = multiStoresHandler.CreateCategory2(ctx, catVendorInfo)
|
||||
} else if model.IsSyncStatusUpdate(catVendorInfo.CatSyncStatus) { // 修改
|
||||
err = multiStoresHandler.UpdateCategory2(ctx, catVendorInfo)
|
||||
}
|
||||
} else {
|
||||
err = fmt.Errorf("平台:%d不合法", catVendorInfo.VendorID)
|
||||
}
|
||||
if err = OnThingSync(ctx, dao.GetDB(), SkuCategoryVendor2ThingMap(catVendorInfo), err); err == nil {
|
||||
retVal = []int{1}
|
||||
}
|
||||
return retVal, err
|
||||
}, catList)
|
||||
tasksch.HandleTask(task, parentTask, len(catList) == 0 || len(catList) > 10).Run()
|
||||
if isAsync {
|
||||
hint = task.GetID()
|
||||
} else {
|
||||
resultList, err2 := task.GetResult(0)
|
||||
if err = err2; err == nil {
|
||||
hint = utils.Int2Str(len(resultList))
|
||||
}
|
||||
}
|
||||
}
|
||||
return hint, err
|
||||
}
|
||||
|
||||
func SyncCategories(ctx *jxcontext.Context, parentTask tasksch.ITask, vendorIDs []int, appOrgCodes []string, catIDs []int, isAsync bool) (hint string, err error) {
|
||||
globals.SugarLogger.Debugf("SyncCategories vendorIDs:%v, appOrgCodes:%v, catIDs:%v", vendorIDs, appOrgCodes, catIDs)
|
||||
db := dao.GetDB()
|
||||
catList, err := dao.GetSkuCategoryWithVendor(db, vendorIDs, appOrgCodes, -1, catIDs, true)
|
||||
if err == nil && len(catList) > 0 {
|
||||
// TODO 同一平台不同账号会有影响needSyncParentIDs,暂不处理
|
||||
var needSyncParentIDs []int
|
||||
for _, cat := range catList {
|
||||
if cat.Level == 2 && cat.ParentVendorCatID == "" && cat.IsExdSpec == model.NO {
|
||||
needSyncParentIDs = append(needSyncParentIDs, cat.ParentID)
|
||||
}
|
||||
}
|
||||
if len(needSyncParentIDs) > 0 {
|
||||
task := tasksch.NewSeqTask(fmt.Sprintf("同步分类1:%v", catIDs), ctx,
|
||||
func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
|
||||
switch step {
|
||||
case 0:
|
||||
catList2, err := dao.GetSkuCategoryWithVendor(db, vendorIDs, appOrgCodes, -1, needSyncParentIDs, true)
|
||||
if err == nil {
|
||||
_, err = syncCategories(ctx, db, task, catList2, false)
|
||||
}
|
||||
case 1:
|
||||
catList2, err := dao.GetSkuCategoryWithVendor(db, vendorIDs, appOrgCodes, -1, catIDs, true)
|
||||
if err == nil {
|
||||
_, err = syncCategories(ctx, db, task, catList2, false)
|
||||
}
|
||||
}
|
||||
return result, err
|
||||
}, 2)
|
||||
tasksch.HandleTask(task, parentTask, len(catIDs) == 0 || len(catIDs) > 10).Run()
|
||||
if isAsync {
|
||||
hint = task.GetID()
|
||||
} else {
|
||||
resultList, err2 := task.GetResult(0)
|
||||
if err = err2; err == nil {
|
||||
hint = utils.Int2Str(len(resultList))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
hint, err = syncCategories(ctx, db, parentTask, catList, false)
|
||||
}
|
||||
}
|
||||
return hint, err
|
||||
}
|
||||
|
||||
func SyncSkus(ctx *jxcontext.Context, parentTask tasksch.ITask, vendorIDs []int, appOrgCodes []string, nameIDs, skuIDs []int, isAsync bool) (hint string, err error) {
|
||||
globals.SugarLogger.Debugf("SyncSkus vendorIDs:%v, appOrgCodes:%v, nameIDs:%v, skuIDs:%v", vendorIDs, appOrgCodes, nameIDs, skuIDs)
|
||||
db := dao.GetDB()
|
||||
skuList, err := dao.GetSkusWithVendor(db, vendorIDs, appOrgCodes, nameIDs, skuIDs, true)
|
||||
if err == nil && len(skuList) > 0 {
|
||||
// todo 按vendorID orgCode合并操作
|
||||
task := tasksch.NewParallelTask(fmt.Sprintf("同步商品:%v,%v", nameIDs, skuIDs), tasksch.NewParallelConfig().SetIsContinueWhenError(true), ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
skuVendorInfo := batchItemList[0].(*dao.StoreSkuSyncInfo)
|
||||
var failedList []*partner.StoreSkuInfoWithErr
|
||||
if skuVendorInfo.VendorCatID == "" {
|
||||
return nil, fmt.Errorf("商品:%d的商家分类没有同步", skuVendorInfo.SkuID)
|
||||
}
|
||||
if skuVendorInfo.BindID == 0 {
|
||||
return nil, fmt.Errorf("商品:%d的数据异常", skuVendorInfo.SkuID)
|
||||
}
|
||||
if skuVendorInfo.ExdSkuID != "" {
|
||||
return nil, err
|
||||
}
|
||||
if skuVendorInfo.SkuVendorMapCatID != "" {
|
||||
skuVendorInfo.VendorVendorCatID = utils.Str2Int64(skuVendorInfo.SkuVendorMapCatID)
|
||||
}
|
||||
skuVendorInfo.SkuName = jxutils.ComposeSkuNameSync(skuVendorInfo.Prefix, skuVendorInfo.Name, skuVendorInfo.Comment, skuVendorInfo.Unit, skuVendorInfo.SpecQuality, skuVendorInfo.SpecUnit, 0, skuVendorInfo.ExPrefix, skuVendorInfo.ExPrefixBegin, skuVendorInfo.ExPrefixEnd)
|
||||
skuVendorInfo.SkuNameOrigin = jxutils.ComposeSkuNameOriginal(skuVendorInfo.Prefix, skuVendorInfo.Name, skuVendorInfo.Comment, skuVendorInfo.Unit, skuVendorInfo.SpecQuality, skuVendorInfo.SpecUnit, 0)
|
||||
if skuVendorInfo.ImgWatermark != "" {
|
||||
downLoad, _ := uploadImgStandard(skuVendorInfo.ImgWatermark)
|
||||
skuVendorInfo.ImgMix = jxutils.MixWatermarkImg(downLoad, skuVendorInfo.Img, skuVendorInfo.ExPrefixBegin, skuVendorInfo.ExPrefixEnd)
|
||||
}
|
||||
skuVendorInfo.MergedStatus = jxutils.MergeSkuStatus(skuVendorInfo.Status, skuVendorInfo.NameStatus)
|
||||
if multiStoresHandler, ok := partner.GetPurchasePlatformFromVendorID(skuVendorInfo.VendorID).(partner.IMultipleStoresHandler); ok {
|
||||
if model.IsSyncStatusDelete(skuVendorInfo.SkuSyncStatus) { //删除
|
||||
if !dao.IsVendorThingIDEmpty(skuVendorInfo.VendorSkuID) &&
|
||||
model.IsSyncStatusNeedDelete(skuVendorInfo.SkuSyncStatus) {
|
||||
err = multiStoresHandler.DeleteSku2(ctx, skuVendorInfo.VendorOrgCode, storeSkuSyncInfo2Bare(skuVendorInfo))
|
||||
if err != nil {
|
||||
failedList = putils.GetErrMsg2FailedSingleList(skuVendorInfo, err, 0, model.VendorChineseNames[skuVendorInfo.VendorID], "删除商品")
|
||||
}
|
||||
}
|
||||
} else if model.IsSyncStatusNew(skuVendorInfo.SkuSyncStatus) { // 新增
|
||||
err = multiStoresHandler.CreateSku2(ctx, skuVendorInfo)
|
||||
if err != nil {
|
||||
failedList = putils.GetErrMsg2FailedSingleList(skuVendorInfo, err, 0, model.VendorChineseNames[skuVendorInfo.VendorID], "新增商品")
|
||||
}
|
||||
} else if model.IsSyncStatusUpdate(skuVendorInfo.SkuSyncStatus) { // 修改
|
||||
err = multiStoresHandler.UpdateSku2(ctx, skuVendorInfo)
|
||||
if err != nil {
|
||||
failedList = putils.GetErrMsg2FailedSingleList(skuVendorInfo, err, 0, model.VendorChineseNames[skuVendorInfo.VendorID], "修改商品")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
err = fmt.Errorf("平台:%d不合法", skuVendorInfo.VendorID)
|
||||
}
|
||||
if len(failedList) > 0 {
|
||||
task.AddFailedList(failedList)
|
||||
}
|
||||
if err = OnThingSync(ctx, dao.GetDB(), SkuVendor2ThingMap(skuVendorInfo), err); err == nil {
|
||||
retVal = []int{1}
|
||||
}
|
||||
return retVal, err
|
||||
}, skuList)
|
||||
if isAsync {
|
||||
buildSetFinishHook(task, ctx)
|
||||
}
|
||||
tasksch.HandleTask(task, parentTask, len(skuList) == 0 || len(skuList) > 10).Run()
|
||||
if isAsync {
|
||||
hint = task.GetID()
|
||||
} else {
|
||||
resultList, err2 := task.GetResult(0)
|
||||
if len(task.GetFailedList()) > 0 {
|
||||
err2 = buildErrMsg(task)
|
||||
err2 = makeSyncError(err2)
|
||||
}
|
||||
if err = err2; err == nil {
|
||||
hint = utils.Int2Str(len(resultList))
|
||||
}
|
||||
}
|
||||
}
|
||||
return hint, err
|
||||
}
|
||||
|
||||
func SyncReorderCategories(ctx *jxcontext.Context, parentCatID int, isAsync bool) (hint string, err error) {
|
||||
globals.SugarLogger.Debugf("SyncReorderCategories parentCatID:%d", parentCatID)
|
||||
db := dao.GetDB()
|
||||
hint, err = CurVendorSync.LoopMultiStoresVendors(ctx, db, fmt.Sprintf("分类重排序:%d", parentCatID), isAsync, false,
|
||||
func(t *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
vendorInfo := batchItemList[0].(*MultiStoreVendorInfo)
|
||||
multiStoresHandler := CurVendorSync.GetMultiStoreHandler(vendorInfo.VendorID)
|
||||
if multiStoresHandler != nil {
|
||||
catList, err2 := dao.GetSkuCategoryWithVendor(db, []int{vendorInfo.VendorID}, []string{vendorInfo.OrgCode}, parentCatID, nil, false)
|
||||
if err = err2; err == nil {
|
||||
var vendorCatIDList []string
|
||||
for _, v := range catList {
|
||||
if v.VendorCatID != "" {
|
||||
vendorCatIDList = append(vendorCatIDList, v.VendorCatID)
|
||||
}
|
||||
}
|
||||
if len(vendorCatIDList) > 0 {
|
||||
if err = multiStoresHandler.ReorderCategories2(ctx, vendorInfo.OrgCode, catList[0].ParentVendorCatID, vendorCatIDList); err == nil {
|
||||
retVal = []int{len(vendorCatIDList)}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
err = fmt.Errorf("非法平台:%d", vendorInfo.VendorID)
|
||||
}
|
||||
return retVal, err
|
||||
})
|
||||
return hint, err
|
||||
}
|
||||
|
||||
func getThingMap(db *dao.DaoDB, thingMap *model.ThingMap) (err error) {
|
||||
return dao.GetEntity(db, thingMap, "ThingID", "ThingType", "VendorID", "VendorOrgCode", model.FieldDeletedAt)
|
||||
}
|
||||
|
||||
func OnCreateThing(ctx *jxcontext.Context, db *dao.DaoDB, vendorInfoList []*MultiStoreVendorInfo, thingID int64, thingType int8) (err error) {
|
||||
if thingType == model.ThingTypeSkuName {
|
||||
return nil
|
||||
}
|
||||
if len(vendorInfoList) == 0 {
|
||||
vendorInfoList = getMultiStoreVendorInfoList()
|
||||
}
|
||||
errList := errlist.New()
|
||||
for _, v := range vendorInfoList {
|
||||
thingMap := &model.ThingMap{
|
||||
ThingID: thingID,
|
||||
ThingType: thingType,
|
||||
VendorID: v.VendorID,
|
||||
VendorOrgCode: v.OrgCode,
|
||||
SyncStatus: model.SyncFlagNewMask,
|
||||
}
|
||||
dao.WrapAddIDCULDEntity(thingMap, ctx.GetUserName())
|
||||
if err2 := dao.CreateEntity(db, thingMap); err2 != nil {
|
||||
if dao.IsDuplicateError(err2) {
|
||||
errList.AddErr(onUpdateThing(ctx, db, vendorInfoList, thingID, thingType, model.SyncFlagNewMask))
|
||||
} else {
|
||||
errList.AddErr(err2)
|
||||
}
|
||||
}
|
||||
updateThingMapEntity(db, thingMap)
|
||||
}
|
||||
err = errList.GetErrListAsOne()
|
||||
return err
|
||||
}
|
||||
|
||||
func onUpdateThing(ctx *jxcontext.Context, db *dao.DaoDB, vendorInfoList []*MultiStoreVendorInfo, thingID int64, thingType int8, syncStatus int8) (err error) {
|
||||
if thingType == model.ThingTypeSkuName {
|
||||
return nil
|
||||
}
|
||||
if len(vendorInfoList) == 0 {
|
||||
vendorInfoList = getMultiStoreVendorInfoList()
|
||||
}
|
||||
errList := errlist.New()
|
||||
for _, v := range vendorInfoList {
|
||||
thingMap := &model.ThingMap{
|
||||
ThingID: thingID,
|
||||
ThingType: thingType,
|
||||
VendorID: v.VendorID,
|
||||
VendorOrgCode: v.OrgCode,
|
||||
}
|
||||
thingMap.DeletedAt = utils.DefaultTimeValue
|
||||
if err2 := getThingMap(db, thingMap); err2 == nil {
|
||||
thingMap.SyncStatus |= syncStatus
|
||||
thingMap.LastOperator = ctx.GetUserName()
|
||||
_, err2 = dao.UpdateEntity(db, thingMap)
|
||||
errList.AddErr(err2)
|
||||
|
||||
updateThingMapEntity(db, thingMap)
|
||||
} else {
|
||||
errList.AddErr(err2)
|
||||
}
|
||||
}
|
||||
err = errList.GetErrListAsOne()
|
||||
return err
|
||||
}
|
||||
|
||||
func OnUpdateThing(ctx *jxcontext.Context, db *dao.DaoDB, vendorInfoList []*MultiStoreVendorInfo, thingID int64, thingType int8) (err error) {
|
||||
return onUpdateThing(ctx, db, vendorInfoList, thingID, thingType, model.SyncFlagModifiedMask)
|
||||
}
|
||||
|
||||
func OnDeleteThing(ctx *jxcontext.Context, db *dao.DaoDB, vendorInfoList []*MultiStoreVendorInfo, thingID int64, thingType int8) (err error) {
|
||||
if thingType == model.ThingTypeSkuName {
|
||||
return nil
|
||||
}
|
||||
if len(vendorInfoList) == 0 {
|
||||
vendorInfoList = getMultiStoreVendorInfoList()
|
||||
}
|
||||
errList := errlist.New()
|
||||
for _, v := range vendorInfoList {
|
||||
thingMap := &model.ThingMap{
|
||||
ThingID: thingID,
|
||||
ThingType: thingType,
|
||||
VendorID: v.VendorID,
|
||||
VendorOrgCode: v.OrgCode,
|
||||
}
|
||||
thingMap.DeletedAt = utils.DefaultTimeValue
|
||||
if err2 := getThingMap(db, thingMap); err2 == nil {
|
||||
if model.IsSyncStatusNew(thingMap.SyncStatus) {
|
||||
thingMap.SyncStatus = 0
|
||||
thingMap.DeletedAt = time.Now()
|
||||
} else {
|
||||
thingMap.SyncStatus |= model.SyncFlagDeletedMask
|
||||
}
|
||||
thingMap.LastOperator = ctx.GetUserName()
|
||||
_, err2 = dao.UpdateEntity(db, thingMap)
|
||||
errList.AddErr(err2)
|
||||
|
||||
updateThingMapEntity(db, thingMap)
|
||||
} else if !dao.IsNoRowsError(err2) {
|
||||
errList.AddErr(err2)
|
||||
}
|
||||
}
|
||||
err = errList.GetErrListAsOne()
|
||||
return err
|
||||
}
|
||||
|
||||
func SkuCategoryVendor2ThingMap(cat *dao.SkuStoreCatInfo) (thingMap *model.ThingMap) {
|
||||
thingMap = &model.ThingMap{
|
||||
ThingID: int64(cat.ID),
|
||||
ThingType: model.ThingTypeCategory,
|
||||
VendorID: cat.VendorID,
|
||||
VendorOrgCode: cat.VendorOrgCode,
|
||||
|
||||
SyncStatus: cat.CatSyncStatus,
|
||||
VendorThingID: cat.VendorCatID,
|
||||
}
|
||||
thingMap.ID = cat.MapID // 一定要赋值
|
||||
return thingMap
|
||||
}
|
||||
|
||||
func SkuVendor2ThingMap(sku *dao.StoreSkuSyncInfo) (thingMap *model.ThingMap) {
|
||||
thingMap = &model.ThingMap{
|
||||
ThingID: int64(sku.SkuID),
|
||||
ThingType: model.ThingTypeSku,
|
||||
VendorID: sku.VendorID,
|
||||
VendorOrgCode: sku.VendorOrgCode,
|
||||
|
||||
SyncStatus: sku.SkuSyncStatus,
|
||||
VendorThingID: sku.VendorSkuID,
|
||||
}
|
||||
thingMap.DeletedAt = utils.DefaultTimeValue
|
||||
thingMap.ID = sku.BindID // 一定要赋值
|
||||
return thingMap
|
||||
}
|
||||
|
||||
func OnThingSync(ctx *jxcontext.Context, db *dao.DaoDB, thingMap *model.ThingMap, syncErr error) (err error) {
|
||||
globals.SugarLogger.Debugf("OnThingSync thingMap:%s", utils.Format4Output(thingMap, true))
|
||||
if syncErr != nil {
|
||||
err = syncErr
|
||||
thingMap.Remark = utils.LimitUTF8StringLen(err.Error(), 255)
|
||||
dao.UpdateEntity(db, thingMap, "Remark")
|
||||
} else {
|
||||
updateFields := []string{
|
||||
model.FieldSyncStatus,
|
||||
model.FieldUpdatedAt,
|
||||
model.FieldLastOperator,
|
||||
"Remark",
|
||||
}
|
||||
if model.IsSyncStatusDelete(thingMap.SyncStatus) { //删除
|
||||
thingMap.DeletedAt = time.Now()
|
||||
thingMap.VendorThingID = ""
|
||||
updateFields = append(updateFields, "VendorThingID", model.FieldDeletedAt)
|
||||
} else if model.IsSyncStatusNew(thingMap.SyncStatus) { // 新增
|
||||
updateFields = append(updateFields, "VendorThingID")
|
||||
}
|
||||
thingMap.SyncStatus = 0
|
||||
thingMap.LastOperator = ctx.GetUserName()
|
||||
thingMap.UpdatedAt = time.Now()
|
||||
thingMap.Remark = ""
|
||||
_, err = dao.UpdateEntity(db, thingMap, updateFields...)
|
||||
|
||||
updateThingMapEntity(db, thingMap)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func updateThingMapEntity(db *dao.DaoDB, thingMap *model.ThingMap) {
|
||||
// if thingMap.VendorOrgCode == globals.JdOrgCode {
|
||||
// if thingMap.ThingType == model.ThingTypeCategory {
|
||||
// cat := &model.SkuCategory{
|
||||
// JdID: utils.Str2Int64WithDefault(thingMap.VendorThingID, 0),
|
||||
// JdSyncStatus: thingMap.SyncStatus,
|
||||
// }
|
||||
// cat.ID = int(thingMap.ThingID)
|
||||
// dao.UpdateEntity(db, cat, "JdID", "JdSyncStatus")
|
||||
// } else if thingMap.ThingType == model.ThingTypeSku {
|
||||
// sku := &model.Sku{
|
||||
// JdID: utils.Str2Int64WithDefault(thingMap.VendorThingID, 0),
|
||||
// JdSyncStatus: thingMap.SyncStatus,
|
||||
// }
|
||||
// sku.ID = int(thingMap.ThingID)
|
||||
// dao.UpdateEntity(db, sku, "JdID", "JdSyncStatus")
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
func amendAndPruneVendorStuff(ctx *jxcontext.Context, parentTask tasksch.ITask, vendorID int, vendorOrgCode string, isAsync, isContinueWhenError bool, opType int, isForceUpdate bool) (hint string, err error) {
|
||||
handler, _ := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.IMultipleStoresHandler)
|
||||
if handler == nil {
|
||||
return "", fmt.Errorf("平台:%s不支持此操作", model.VendorChineseNames[vendorID])
|
||||
}
|
||||
db := dao.GetDB()
|
||||
vendorInfo := []*MultiStoreVendorInfo{
|
||||
&MultiStoreVendorInfo{
|
||||
VendorID: vendorID,
|
||||
OrgCode: vendorOrgCode,
|
||||
},
|
||||
}
|
||||
var sku2Delete []*partner.StoreSkuInfo
|
||||
var cat2Delete []*partner.BareCategoryInfo
|
||||
task := tasksch.NewParallelTask(fmt.Sprintf("平台:%s,账号:%s上的商品与商家分类", model.VendorChineseNames[vendorID], vendorOrgCode),
|
||||
tasksch.NewParallelConfig().SetParallelCount(1).SetIsContinueWhenError(isContinueWhenError), ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
step := batchItemList[0].(int)
|
||||
switch step {
|
||||
case 0:
|
||||
localSkuList, err := dao.GetSkusWithVendor(db, []int{vendorID}, []string{vendorOrgCode}, nil, nil, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
localSkuMap := make(map[string]*dao.StoreSkuSyncInfo)
|
||||
for _, v := range localSkuList {
|
||||
if v.VendorSkuID != "" {
|
||||
localSkuMap[v.VendorSkuID] = v
|
||||
}
|
||||
}
|
||||
|
||||
remoteSkuList, err2 := handler.GetSkus(ctx, vendorOrgCode, 0, "")
|
||||
if err = err2; err == nil {
|
||||
remoteSkuMap := make(map[string]int)
|
||||
for _, v := range remoteSkuList {
|
||||
if vendorSkuID := v.SkuList[0].VendorSkuID; vendorSkuID != "" {
|
||||
if localSkuMap[vendorSkuID] == nil {
|
||||
sku2Delete = append(sku2Delete, &partner.StoreSkuInfo{
|
||||
SkuID: v.SkuList[0].SkuID,
|
||||
VendorSkuID: vendorSkuID,
|
||||
})
|
||||
} else {
|
||||
remoteSkuMap[vendorSkuID] = 1
|
||||
}
|
||||
} else if v.VendorNameID != "" {
|
||||
sku2Delete = append(sku2Delete, &partner.StoreSkuInfo{
|
||||
SkuID: v.NameID,
|
||||
VendorSkuID: v.VendorNameID,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if opType == AmendPruneOnlyAmend || opType == AmendPruneAll {
|
||||
for _, v := range localSkuList {
|
||||
if v.ExdSkuID == "" {
|
||||
if v.BindID != 0 {
|
||||
if !model.IsSyncStatusDelete(v.SkuSyncStatus) {
|
||||
if remoteSkuMap[v.VendorSkuID] == 0 {
|
||||
if !model.IsSyncStatusNew(v.SkuSyncStatus) {
|
||||
OnCreateThing(ctx, db, vendorInfo, int64(v.SkuID), model.ThingTypeSku)
|
||||
}
|
||||
} else if isForceUpdate {
|
||||
OnUpdateThing(ctx, db, vendorInfo, int64(v.SkuID), model.ThingTypeSku)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
OnCreateThing(ctx, db, vendorInfo, int64(v.SkuID), model.ThingTypeSku)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
case 1:
|
||||
if (opType == AmendPruneOnlyPrune || opType == AmendPruneAll) && len(sku2Delete) > 0 {
|
||||
_, err = putils.FreeBatchStoreSkuInfo("删除商品", func(task tasksch.ITask, batchedStoreSkuList []*partner.StoreSkuInfo) (result interface{}, successCount int, err error) {
|
||||
if err = handler.DeleteSku2(ctx, vendorOrgCode, batchedStoreSkuList[0]); err == nil {
|
||||
successCount = 1
|
||||
}
|
||||
return nil, successCount, err
|
||||
}, ctx, task, sku2Delete, 1, isContinueWhenError)
|
||||
}
|
||||
sku2Delete = nil
|
||||
case 2:
|
||||
localCatList, err := dao.GetSkuCategoryWithVendor(db, []int{vendorID}, []string{vendorOrgCode}, -1, nil, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
localCatMap := make(map[string]*dao.SkuStoreCatInfo)
|
||||
for _, v := range localCatList {
|
||||
localCatMap[v.VendorCatID] = v
|
||||
localCatMap[v.Name] = v
|
||||
localCatMap[utils.Int2Str(v.ID)] = v
|
||||
}
|
||||
|
||||
remoteCatList, err2 := handler.GetAllCategories(ctx, vendorOrgCode)
|
||||
if err = err2; err == nil {
|
||||
remoteCatMap := make(map[string]int)
|
||||
cat2Delete = checkRemoteCatExist(remoteCatMap, localCatMap, remoteCatList)
|
||||
|
||||
for _, v := range localCatList {
|
||||
if v.IsExdSpec == model.NO {
|
||||
if v.MapID != 0 {
|
||||
if !model.IsSyncStatusDelete(v.CatSyncStatus) {
|
||||
if remoteCatMap[v.VendorCatID] == 0 {
|
||||
if !model.IsSyncStatusNew(v.CatSyncStatus) {
|
||||
OnCreateThing(ctx, db, vendorInfo, int64(v.ID), model.ThingTypeCategory)
|
||||
}
|
||||
} else if isForceUpdate && !model.IsSyncStatusUpdate(v.CatSyncStatus) {
|
||||
OnUpdateThing(ctx, db, vendorInfo, int64(v.ID), model.ThingTypeCategory)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
OnCreateThing(ctx, db, vendorInfo, int64(v.ID), model.ThingTypeCategory)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
case 3:
|
||||
if (opType == AmendPruneOnlyPrune || opType == AmendPruneAll) && len(cat2Delete) > 0 {
|
||||
for i := 0; i < 2; i++ {
|
||||
level := 2 - i
|
||||
var levelCat2Delete []*partner.BareCategoryInfo
|
||||
for _, v := range cat2Delete {
|
||||
if v.Level == level {
|
||||
levelCat2Delete = append(levelCat2Delete, v)
|
||||
}
|
||||
}
|
||||
if len(levelCat2Delete) > 0 {
|
||||
task4Delete := tasksch.NewParallelTask(fmt.Sprintf("删除商家分类,level:%d", level), tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError), ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
cat := batchItemList[0].(*partner.BareCategoryInfo)
|
||||
err = handler.DeleteCategory2(ctx, vendorOrgCode, cat.VendorCatID)
|
||||
return nil, err
|
||||
}, levelCat2Delete)
|
||||
tasksch.HandleTask(task4Delete, task, true).Run()
|
||||
_, err = task4Delete.GetResult(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
cat2Delete = nil
|
||||
}
|
||||
return nil, err
|
||||
}, []int{0, 1, 2, 3})
|
||||
tasksch.HandleTask(task, parentTask, true).Run()
|
||||
if !isAsync {
|
||||
_, err = task.GetResult(0)
|
||||
hint = "1"
|
||||
} else {
|
||||
hint = task.ID
|
||||
}
|
||||
return hint, err
|
||||
}
|
||||
|
||||
func FullSyncVendorStuff(ctx *jxcontext.Context, parentTask tasksch.ITask, vendorID int, vendorOrgCode string, isAsync, isContinueWhenError bool) (hint string, err error) {
|
||||
multiStoreHandler, _ := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.IMultipleStoresHandler)
|
||||
if multiStoreHandler == nil {
|
||||
return "", fmt.Errorf("vendorID:%d不是多门店平台", vendorID)
|
||||
}
|
||||
task := tasksch.NewParallelTask("FullSyncStoreSkuNew", tasksch.NewParallelConfig().SetParallelCount(1).SetIsContinueWhenError(false), ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
step := batchItemList[0].(int)
|
||||
switch step {
|
||||
case 0:
|
||||
_, err = amendAndPruneVendorStuff(ctx, task, vendorID, vendorOrgCode, false, isContinueWhenError, AmendPruneAll, false)
|
||||
case 1:
|
||||
_, err = SyncCategories(ctx, task, []int{vendorID}, []string{vendorOrgCode}, nil, false)
|
||||
case 2:
|
||||
_, err = SyncSkus(ctx, task, []int{vendorID}, []string{vendorOrgCode}, nil, nil, false)
|
||||
}
|
||||
return retVal, err
|
||||
}, []int{0, 1, 2})
|
||||
tasksch.HandleTask(task, parentTask, true).Run()
|
||||
if !isAsync {
|
||||
_, err = task.GetResult(0)
|
||||
} else {
|
||||
hint = task.GetID()
|
||||
}
|
||||
return hint, err
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
package cms
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
)
|
||||
|
||||
// 如果京西门为打开,打开状态为非营业的平台门店
|
||||
func OpenRemoteStoreByJxStatus(ctx *jxcontext.Context, vendorIDs, storeIDs []int, isForce, isAsync, isContinueWhenError bool) (hint string, err error) {
|
||||
db := dao.GetDB()
|
||||
status := model.StoreStatusAll
|
||||
if !isForce {
|
||||
status = model.StoreStatusClosed
|
||||
}
|
||||
storeMapList, err := dao.GetStoresMapList(db, vendorIDs, storeIDs, nil, status, model.StoreIsSyncYes, "", "")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
vendorIDMap := make(map[int]int)
|
||||
if len(vendorIDs) == 0 {
|
||||
for k := range partner.PurchasePlatformHandlers {
|
||||
vendorIDMap[k] = 1
|
||||
}
|
||||
} else {
|
||||
for _, v := range vendorIDs {
|
||||
vendorIDMap[v] = 1
|
||||
}
|
||||
}
|
||||
task := tasksch.NewParallelTask("OpenRemoteStoreByJxStatus", tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError), ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
storeMap := batchItemList[0].(*model.StoreMap)
|
||||
if handler, _ := partner.GetPurchasePlatformFromVendorID(storeMap.VendorID).(partner.IStoreHandler); handler != nil {
|
||||
storeDetail, err := dao.GetStoreDetail(db, storeMap.StoreID, storeMap.VendorID)
|
||||
if err == nil && storeDetail.Status == model.StoreStatusOpened {
|
||||
if err = handler.UpdateStoreStatus(ctx, storeMap.VendorOrgCode, storeMap.StoreID, storeMap.VendorStoreID, model.StoreStatusOpened); err == nil {
|
||||
storeMap.Status = model.StoreStatusOpened
|
||||
dao.UpdateEntity(db, storeMap, model.FieldStatus)
|
||||
retVal = []int{1}
|
||||
}
|
||||
}
|
||||
}
|
||||
return retVal, err
|
||||
}, storeMapList)
|
||||
tasksch.HandleTask(task, nil, true).Run()
|
||||
|
||||
if isAsync {
|
||||
hint = task.GetID()
|
||||
} else {
|
||||
resultList, err2 := task.GetResult(0)
|
||||
if err = err2; err == nil {
|
||||
hint = utils.Int2Str(len(resultList))
|
||||
}
|
||||
}
|
||||
return hint, err
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,329 +0,0 @@
|
||||
package cms
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/business/partner/putils"
|
||||
"git.rosy.net.cn/jx-callback/globals/api/apimanager"
|
||||
"github.com/360EntSecGroup-Skylar/excelize"
|
||||
)
|
||||
|
||||
func storeOrSkuMap2List(intStrMap map[int]string) (ids []int) {
|
||||
for k, v := range intStrMap {
|
||||
if v != "" {
|
||||
ids = append(ids, k)
|
||||
}
|
||||
}
|
||||
return ids
|
||||
}
|
||||
|
||||
func getStoreSkus(db *dao.DaoDB, storeID int, skuIDs []int) (skus []*dao.StoreSkuSyncInfo, err error) {
|
||||
sql := `
|
||||
SELECT
|
||||
t1.id bind_id, t1.sku_id, t1.price, t1.unit_price, t1.status store_sku_status,
|
||||
t1.jd_sync_status sku_sync_status, t1.jd_price vendor_price, t1.jd_lock_time lock_time,
|
||||
t1.store_id, t1.deleted_at bind_deleted_at,t1.status_sale_begin,t1.status_sale_end,
|
||||
t2.*,
|
||||
t3.id name_id, t3.prefix, t3.name, t3.unit, t3.upc, t3.status name_status, t3.ex_prefix, t3.ex_prefix_begin, t3.ex_prefix_end
|
||||
FROM store_sku_bind t1
|
||||
LEFT JOIN sku t2 ON t1.sku_id = t2.id AND t2.deleted_at = ?/* AND t2.status = ?*/
|
||||
LEFT JOIN sku_name t3 ON t2.name_id = t3.id AND t3.deleted_at = ?/* AND t3.status = ?*/
|
||||
WHERE 1 = 1
|
||||
AND t1.store_id = ?
|
||||
AND t1.deleted_at = ?
|
||||
AND t1.sku_id IN ( ` + dao.GenQuestionMarks(len(skuIDs)) + `)
|
||||
ORDER BY t1.price`
|
||||
sqlParams := []interface{}{
|
||||
utils.DefaultTimeValue,
|
||||
utils.DefaultTimeValue,
|
||||
storeID,
|
||||
utils.DefaultTimeValue,
|
||||
skuIDs,
|
||||
}
|
||||
if err = dao.GetRows(db, &skus, sql, sqlParams...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return skus, err
|
||||
}
|
||||
|
||||
func SyncStoreSku4FakeJD(ctx *jxcontext.Context, parentTask tasksch.ITask, storeID int, vendorStoreID string, inSkuMap map[int]string, isContinueWhenError bool) (err error) {
|
||||
vendorID := model.VendorIDJD
|
||||
db := dao.GetDB()
|
||||
storeDetail, err := dao.GetStoreDetail(db, storeID, vendorID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
storeDetail.VendorOrgCode = apimanager.FakeJdOrgCode
|
||||
skuIDs := storeOrSkuMap2List(inSkuMap)
|
||||
skus, err := getStoreSkus(db, storeID, skuIDs)
|
||||
if err != nil || len(skus) == 0 {
|
||||
return err
|
||||
}
|
||||
formalizeStoreSkuList(skus)
|
||||
storeSkuHandler := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.IPurchasePlatformStoreSkuHandler)
|
||||
|
||||
var (
|
||||
stockList, onlineList, offlineList, priceList []*partner.StoreSkuInfo
|
||||
)
|
||||
skuMap := make(map[*partner.StoreSkuInfo]*dao.StoreSkuSyncInfo)
|
||||
now := jxutils.OperationTime2HourMinuteFormat(time.Now())
|
||||
var failedList []*partner.StoreSkuInfoWithErr
|
||||
for _, sku := range skus {
|
||||
sku.SkuSyncStatus = model.SyncFlagSaleMask | model.SyncFlagPriceMask | model.SyncFlagStockMask
|
||||
sku.VendorSkuID = inSkuMap[sku.SkuID]
|
||||
sku.SkuID = int(utils.Str2Int64(sku.VendorSkuID)) // skuID与vendorID一样
|
||||
sku.VendorOrgCode = apimanager.FakeJdOrgCode
|
||||
|
||||
sku.VendorPrice = 0
|
||||
sku.MergedStatus = MergeSkuSaleStatusWithStoreOpTime(sku, storeDetail, now)
|
||||
var bareSku *partner.StoreSkuInfo
|
||||
if isStoreSkuSyncNeedDelete(sku) {
|
||||
if !dao.IsVendorThingIDEmpty(sku.VendorSkuID) {
|
||||
bareSku = storeSkuSyncInfo2Bare(sku)
|
||||
stockList = append(stockList, bareSku)
|
||||
} else {
|
||||
// updateItems = append(updateItems, sku2Update(vendorID, sku, model.SyncFlagDeletedMask))
|
||||
}
|
||||
} else if model.IsSyncStatusNew(sku.SkuSyncStatus) {
|
||||
calVendorPrice4StoreSku(sku, storeDetail.PricePercentagePackObj, int(storeDetail.PricePercentage))
|
||||
if dao.IsVendorThingIDEmpty(sku.VendorSkuID) {
|
||||
// todo 多平台商品库没有正常创建,直接跳过
|
||||
} else {
|
||||
sku.SkuSyncStatus |= model.SyncFlagSaleMask | model.SyncFlagPriceMask
|
||||
bareSku = storeSkuSyncInfo2Bare(sku)
|
||||
stockList = append(stockList, bareSku)
|
||||
priceList = append(priceList, bareSku)
|
||||
if sku.MergedStatus == model.SkuStatusNormal {
|
||||
onlineList = append(onlineList, bareSku)
|
||||
} else {
|
||||
offlineList = append(offlineList, bareSku)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if dao.IsVendorThingIDEmpty(sku.VendorSkuID) {
|
||||
// err = fmt.Errorf("门店:%d,修改没有创建的商品:%d", storeID, sku.SkuID)
|
||||
err = utils.NewErrorCode(fmt.Sprintf("门店:%d,修改没有创建的商品:%d", storeID, sku.SkuID), "-1", 0)
|
||||
failedList = putils.GetErrMsg2FailedSingleList(nil, err, storeID, model.VendorChineseNames[vendorID], "异常同步错误")
|
||||
if parentTask == nil {
|
||||
return err
|
||||
}
|
||||
parentTask.AddBatchErr(err)
|
||||
parentTask.AddFailedList(failedList)
|
||||
} else {
|
||||
isAdded2Update := false
|
||||
if model.IsSyncStatusPrice(sku.SkuSyncStatus) {
|
||||
bareSku = storeSkuSyncInfo2Bare(calVendorPrice4StoreSku(sku, storeDetail.PricePercentagePackObj, int(storeDetail.PricePercentage)))
|
||||
priceList = append(priceList, bareSku)
|
||||
}
|
||||
if !isAdded2Update {
|
||||
if model.IsSyncStatusSale(sku.SkuSyncStatus) {
|
||||
if bareSku == nil {
|
||||
bareSku = storeSkuSyncInfo2Bare(sku)
|
||||
}
|
||||
if sku.MergedStatus == model.SkuStatusNormal {
|
||||
onlineList = append(onlineList, bareSku)
|
||||
stockList = append(stockList, bareSku)
|
||||
} else {
|
||||
offlineList = append(offlineList, bareSku)
|
||||
// 因为京东平台以是否有库存表示是否关注,所以不论是否可售,都要设置库存
|
||||
stockList = append(stockList, bareSku)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if bareSku != nil {
|
||||
skuMap[bareSku] = sku
|
||||
}
|
||||
}
|
||||
bareSku2Sync := func(bareSkuList []*partner.StoreSkuInfo) (skuList []*dao.StoreSkuSyncInfo) {
|
||||
if len(bareSkuList) > 0 {
|
||||
skuList = make([]*dao.StoreSkuSyncInfo, len(bareSkuList))
|
||||
for k, v := range bareSkuList {
|
||||
skuList[k] = skuMap[v]
|
||||
}
|
||||
}
|
||||
return skuList
|
||||
}
|
||||
isContinueWhenError2 := true
|
||||
realStoreID := int(utils.Str2Int64(vendorStoreID))
|
||||
task := tasksch.NewParallelTask("SyncStoreSku4FakeJD", tasksch.NewParallelConfig().SetParallelCount(1).SetIsContinueWhenError(isContinueWhenError2), ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
step := batchItemList[0].(int)
|
||||
// globals.SugarLogger.Debugf("step:%d", step)
|
||||
switch step {
|
||||
case 0:
|
||||
for k, list := range [][]*partner.StoreSkuInfo{stockList /*, onlineList*/} {
|
||||
if len(list) > 0 {
|
||||
_, err = putils.FreeBatchStoreSkuInfo("更新门店商品库存", func(task tasksch.ITask, batchedStoreSkuList []*partner.StoreSkuInfo) (result interface{}, successCount int, err error) {
|
||||
var failedList []*partner.StoreSkuInfoWithErr
|
||||
failedList, err = storeSkuHandler.UpdateStoreSkusStock(ctx, storeDetail.VendorOrgCode, realStoreID, vendorStoreID, batchedStoreSkuList)
|
||||
if len(failedList) > 0 {
|
||||
task.AddFailedList(failedList)
|
||||
}
|
||||
successList := putils.UnselectStoreSkuListByVendorSkuIDs(batchedStoreSkuList, GetVendorSkuIDList(failedList))
|
||||
if k == 0 && len(successList) > 0 {
|
||||
updateStoreSku(dao.GetDB(), vendorID, bareSku2Sync(successList), model.SyncFlagStockMask)
|
||||
}
|
||||
return nil, len(successList), err
|
||||
}, ctx, task, list, storeSkuHandler.GetStoreSkusBatchSize(partner.FuncUpdateStoreSkusStock), isContinueWhenError2)
|
||||
}
|
||||
}
|
||||
case 1, 2:
|
||||
statusList := onlineList
|
||||
status := model.SkuStatusNormal
|
||||
name := "可售门店商品"
|
||||
if step == 2 {
|
||||
statusList = offlineList
|
||||
status = model.SkuStatusDontSale
|
||||
name = "不可售门店商品"
|
||||
}
|
||||
if len(statusList) > 0 {
|
||||
_, err = putils.FreeBatchStoreSkuInfo(name, func(task tasksch.ITask, batchedStoreSkuList []*partner.StoreSkuInfo) (result interface{}, successCount int, err error) {
|
||||
var failedList []*partner.StoreSkuInfoWithErr
|
||||
failedList, err = storeSkuHandler.UpdateStoreSkusStatus(ctx, storeDetail.VendorOrgCode, realStoreID, vendorStoreID, batchedStoreSkuList, status)
|
||||
if len(failedList) > 0 {
|
||||
task.AddFailedList(failedList)
|
||||
}
|
||||
successList := putils.UnselectStoreSkuListByVendorSkuIDs(batchedStoreSkuList, GetVendorSkuIDList(failedList))
|
||||
if len(successList) > 0 {
|
||||
updateStoreSku(dao.GetDB(), vendorID, bareSku2Sync(successList), model.SyncFlagSaleMask)
|
||||
}
|
||||
return nil, len(successList), err
|
||||
}, ctx, task, statusList, storeSkuHandler.GetStoreSkusBatchSize(partner.FuncUpdateStoreSkusStatus), isContinueWhenError2)
|
||||
}
|
||||
case 3:
|
||||
if len(priceList) > 0 {
|
||||
_, err = putils.FreeBatchStoreSkuInfo("更新门店商品价格", func(task tasksch.ITask, batchedStoreSkuList []*partner.StoreSkuInfo) (result interface{}, successCount int, err error) {
|
||||
var failedList []*partner.StoreSkuInfoWithErr
|
||||
failedList, err = storeSkuHandler.UpdateStoreSkusPrice(ctx, storeDetail.VendorOrgCode, realStoreID, vendorStoreID, batchedStoreSkuList)
|
||||
if len(failedList) > 0 {
|
||||
task.AddFailedList(failedList)
|
||||
}
|
||||
successList := putils.UnselectStoreSkuListByVendorSkuIDs(batchedStoreSkuList, GetVendorSkuIDList(failedList))
|
||||
if len(successList) > 0 {
|
||||
updateStoreSku(dao.GetDB(), vendorID, bareSku2Sync(successList), model.SyncFlagPriceMask)
|
||||
}
|
||||
return nil, len(successList), err
|
||||
}, ctx, task, priceList, storeSkuHandler.GetStoreSkusBatchSize(partner.FuncUpdateStoreSkusPrice), isContinueWhenError2)
|
||||
}
|
||||
}
|
||||
return retVal, err
|
||||
}, []int{0, 1, 2, 3})
|
||||
tasksch.HandleTask(task, parentTask, true).Run()
|
||||
_, err = task.GetResult(0)
|
||||
return err
|
||||
}
|
||||
|
||||
func SyncFakeJdStoreSku(ctx *jxcontext.Context, parentTask tasksch.ITask, storeMap, skuMap map[int]string, isAsync, isContinueWhenError bool) (hint string, err error) {
|
||||
storeIDs := storeOrSkuMap2List(storeMap)
|
||||
task := tasksch.NewParallelTask("同步假京东", nil, ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
storeID := batchItemList[0].(int)
|
||||
err = SyncStoreSku4FakeJD(ctx, task, storeID, storeMap[storeID], skuMap, isContinueWhenError)
|
||||
return retVal, err
|
||||
}, storeIDs)
|
||||
tasksch.HandleTask(task, parentTask, true).Run()
|
||||
if isAsync {
|
||||
hint = task.GetID()
|
||||
} else {
|
||||
_, err = task.GetResult(0)
|
||||
hint = utils.Int2Str(len(storeIDs))
|
||||
}
|
||||
return hint, err
|
||||
}
|
||||
|
||||
func excel2FakeJdThingMap(ctx *jxcontext.Context, reader io.Reader) (thingMapList []*model.FakeJdThingMap, err error) {
|
||||
xlsx, err := excelize.OpenReader(reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for sheetIndex := 0; sheetIndex < xlsx.SheetCount; sheetIndex++ {
|
||||
rows, err2 := xlsx.GetRows(xlsx.GetSheetName(sheetIndex + 1))
|
||||
if err2 != nil {
|
||||
return nil, err2
|
||||
}
|
||||
for rowNum, row := range rows {
|
||||
thingMap := &model.FakeJdThingMap{
|
||||
JxID: int(utils.Str2Int64WithDefault(row[0], 0)),
|
||||
JdID: utils.Str2Int64WithDefault(row[1], 0),
|
||||
}
|
||||
if thingMap.JxID == 0 || thingMap.JdID == 0 {
|
||||
if rowNum == 0 {
|
||||
continue
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
if sheetIndex == 0 {
|
||||
thingMap.ThingType = model.ThingTypeStore
|
||||
} else {
|
||||
thingMap.ThingType = model.ThingTypeSku
|
||||
}
|
||||
dao.WrapAddIDCULEntity(thingMap, ctx.GetUserName())
|
||||
thingMapList = append(thingMapList, thingMap)
|
||||
}
|
||||
}
|
||||
return thingMapList, err
|
||||
}
|
||||
|
||||
func getFakeThingMap(ctx *jxcontext.Context, db *dao.DaoDB) (storeMap, skuMap map[int]string, err error) {
|
||||
var thingMapList []*model.FakeJdThingMap
|
||||
err = dao.GetRows(db, &thingMapList, "SELECT t1.* FROM fake_jd_thing_map t1")
|
||||
if err == nil {
|
||||
storeMap, skuMap = make(map[int]string), make(map[int]string)
|
||||
for _, v := range thingMapList {
|
||||
if v.ThingType == model.ThingTypeStore {
|
||||
storeMap[v.JxID] = utils.Int64ToStr(v.JdID)
|
||||
} else {
|
||||
skuMap[v.JxID] = utils.Int64ToStr(v.JdID)
|
||||
}
|
||||
}
|
||||
}
|
||||
return storeMap, skuMap, err
|
||||
}
|
||||
|
||||
func UploadFakeJdThingMap(ctx *jxcontext.Context, reader io.Reader, isSyncNow, isAsync, isContinueWhenError bool) (hint string, err error) {
|
||||
thingMapList, err := excel2FakeJdThingMap(ctx, reader)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
db := dao.GetDB()
|
||||
dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
dao.Rollback(db)
|
||||
panic(r)
|
||||
}
|
||||
}()
|
||||
_, err = dao.ExecuteSQL(db, "DELETE t1 FROM fake_jd_thing_map t1")
|
||||
if err != nil {
|
||||
dao.Rollback(db)
|
||||
return "", err
|
||||
}
|
||||
err = dao.CreateMultiEntities(db, thingMapList)
|
||||
if err != nil {
|
||||
dao.Rollback(db)
|
||||
return "", err
|
||||
}
|
||||
dao.Commit(db)
|
||||
|
||||
if isSyncNow {
|
||||
if storeMap, skuMap, err2 := getFakeThingMap(ctx, db); err2 == nil {
|
||||
hint, err = SyncFakeJdStoreSku(ctx, nil, storeMap, skuMap, isAsync, isContinueWhenError)
|
||||
}
|
||||
} else {
|
||||
hint = utils.Int2Str(len(thingMapList))
|
||||
}
|
||||
return hint, err
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
package cms
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
)
|
||||
|
||||
func TestSyncStoreSku4FakeJD(t *testing.T) {
|
||||
skuMap := map[int]string{
|
||||
22509: "2029937911",
|
||||
}
|
||||
err := SyncStoreSku4FakeJD(jxcontext.AdminCtx, nil, 100118, "11943257", skuMap, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUploadFakeJdThingMap(t *testing.T) {
|
||||
file, err := os.Open("到家菜市门店与商品映射信息(1).xlsx")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
hint, err := UploadFakeJdThingMap(jxcontext.AdminCtx, file, true, false, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(hint)
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
package cms
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/business/partner/putils"
|
||||
)
|
||||
|
||||
func TestFreeBatchStoreSkuInfo(t *testing.T) {
|
||||
var sku2Delete []*partner.StoreSkuInfo
|
||||
for i := 0; i < 123; i++ {
|
||||
sku2Delete = append(sku2Delete, &partner.StoreSkuInfo{
|
||||
SkuID: i + 1,
|
||||
})
|
||||
}
|
||||
|
||||
ctx := jxcontext.AdminCtx
|
||||
var parentTask tasksch.ITask
|
||||
isContinueWhenError := true
|
||||
handler, _ := partner.GetPurchasePlatformFromVendorID(model.VendorIDEBAI).(partner.ISingleStoreStoreSkuHandler)
|
||||
_, err := putils.FreeBatchStoreSkuInfo("删除门店商品", func(task tasksch.ITask, batchedStoreSkuList []*partner.StoreSkuInfo) (result interface{}, successCount int, err error) {
|
||||
t.Log(len(batchedStoreSkuList))
|
||||
return nil, 0, err
|
||||
}, ctx, parentTask, sku2Delete, handler.GetStoreSkusBatchSize(partner.FuncDeleteStoreSkus), isContinueWhenError)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetTimeMixByInt(t *testing.T) {
|
||||
const (
|
||||
time1 = 1100
|
||||
time2 = 2300
|
||||
time3 = 1200
|
||||
time4 = 2400
|
||||
)
|
||||
a, b := GetTimeMixByInt(time1, time2, time3, time4)
|
||||
fmt.Println(a, b)
|
||||
}
|
||||
77
business/jxstore/cms/temp.go
Normal file
77
business/jxstore/cms/temp.go
Normal 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
|
||||
}
|
||||
@@ -1,210 +0,0 @@
|
||||
package cms
|
||||
|
||||
// var (
|
||||
// LoginTypeFieldMap = map[string]string{
|
||||
// mobile.LoginType: "tel",
|
||||
// weixin.LoginType: "openid",
|
||||
// weixin.LoginTypeMiniProgram: "openid_mini",
|
||||
// }
|
||||
// )
|
||||
|
||||
// func GetStoreUsers(ctx *jxcontext.Context, storeID int) (storeUserInfos []*dao.StoreUserInfo, err error) {
|
||||
// sql := `
|
||||
// SELECT t1.id, t1.jxstoreid, t1.openid, t1.tel, t1.nickname, t1.parentid, t3.tel parent_mobile,
|
||||
// CONCAT("[", GROUP_CONCAT(CONCAT('{"id":', t2.id, ',"parentID":', t2.parentid, ',"tel":"', t2.tel, '","nickname":"', IF(t2.nickname IS NULL, "", t2.nickname), '"}')), "]") members_str
|
||||
// FROM weixins t1
|
||||
// LEFT JOIN weixins t2 ON t2.parentid = t1.id
|
||||
// LEFT JOIN weixins t3 ON t1.parentid = t3.id
|
||||
// WHERE t1.parentid = -1 AND t1.jxstoreid = ?
|
||||
// GROUP BY 1,2,3,4,5,6,7;
|
||||
// `
|
||||
// // globals.SugarLogger.Debug(sql)
|
||||
// if err = dao.GetRows(nil, &storeUserInfos, sql, storeID); err == nil {
|
||||
// for _, storeUserInfo := range storeUserInfos {
|
||||
// if storeUserInfo.MembersStr != "" {
|
||||
// err = utils.UnmarshalUseNumber([]byte(storeUserInfo.MembersStr), &storeUserInfo.Members)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return storeUserInfos, err
|
||||
// }
|
||||
|
||||
// func GetUserInfo(ctx *jxcontext.Context, mobile string) (storeUserInfo *dao.StoreUserInfo, err error) {
|
||||
// storeUserInfo, err = dao.GetUserStoreInfo(dao.GetDB(), "tel", mobile)
|
||||
// globals.SugarLogger.Debugf("GetUserInfo:%s, token:%s, mobile:%s, storeUserInfo:%s, err:%v", ctx.GetTrackInfo(), ctx.GetToken(), mobile, utils.Format4Output(storeUserInfo, true), err)
|
||||
// return storeUserInfo, err
|
||||
// }
|
||||
|
||||
// func GetSelfInfo(ctx *jxcontext.Context) (storeUserInfo *dao.StoreUserInfo, err error) {
|
||||
// loginInfo := ctx.GetLoginInfo()
|
||||
// if loginInfo == nil {
|
||||
// return nil, auth.ErrAPINeedRealLogin
|
||||
// }
|
||||
// fieldName := LoginTypeFieldMap[loginInfo.GetAuthType()]
|
||||
// if fieldName == "" {
|
||||
// return nil, auth.ErrIllegalLoginType
|
||||
// }
|
||||
// storeUserInfo, err = dao.GetUserStoreInfo(dao.GetDB(), fieldName, loginInfo.GetAuthID())
|
||||
// globals.SugarLogger.Debugf("GetSelfInfo:%s, token:%s, storeUserInfo:%s, err:%v", ctx.GetTrackInfo(), ctx.GetToken(), utils.Format4Output(storeUserInfo, true), err)
|
||||
// return storeUserInfo, err
|
||||
// }
|
||||
|
||||
// func GetMyStoreList(ctx *jxcontext.Context) (storeList []*dao.StoreWithCityName, err error) {
|
||||
// mobileNum, _ := ctx.GetMobileAndUserID()
|
||||
// if mobileNum == "" {
|
||||
// return nil, fmt.Errorf("不能得到用户手机号")
|
||||
// }
|
||||
// storeList, err = dao.GetStoreListByMobile(dao.GetDB(), mobileNum)
|
||||
// return storeList, err
|
||||
// }
|
||||
|
||||
// func UnbindMobile(ctx *jxcontext.Context, mobile string) (num int64, err error) {
|
||||
// db := dao.GetDB()
|
||||
// num, err = dao.UpdateEntityByKV(db, &legacymodel.WeiXins{}, map[string]interface{}{
|
||||
// "JxStoreID": 0,
|
||||
// "ParentID": -1,
|
||||
// }, map[string]interface{}{
|
||||
// "Tel": mobile,
|
||||
// })
|
||||
// if err == nil {
|
||||
// jxutils.HandleUserWXRemark(db, mobile, false)
|
||||
// TransferLegacyWeixins(mobile)
|
||||
// }
|
||||
// return num, err
|
||||
// }
|
||||
|
||||
// func BindMobile2Store(ctx *jxcontext.Context, mobile string, storeID int) (num int64, err error) {
|
||||
// db := dao.GetDB()
|
||||
// user, err2 := verifyMobileIsBlank(db, mobile)
|
||||
// if err = err2; err == nil || err == orm.ErrNoRows {
|
||||
// user.JxStoreID = storeID
|
||||
// if err == nil {
|
||||
// dao.Begin(db)
|
||||
// defer func() {
|
||||
// if r := recover(); r != nil {
|
||||
// dao.Rollback(db)
|
||||
// panic(r)
|
||||
// }
|
||||
// }()
|
||||
// if num, err = dao.UpdateEntity(db, user, "JxStoreID"); err == nil {
|
||||
// err = dao.SetWeiXinsEmpty2Null(db, user)
|
||||
// }
|
||||
// if err != nil {
|
||||
// dao.Rollback(db)
|
||||
// } else {
|
||||
// dao.Commit(db)
|
||||
// }
|
||||
// } else {
|
||||
// // globals.SugarLogger.Debug(utils.Format4Output(user, false))
|
||||
// dao.WrapAddIDCULEntity(user, ctx.GetUserName())
|
||||
// user.ParentID = -1
|
||||
// if err = dao.CreateWeiXins(db, user); err == nil {
|
||||
// num = 1
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// if err == nil {
|
||||
// jxutils.HandleUserWXRemark(db, mobile, false)
|
||||
// TransferLegacyWeixins(mobile)
|
||||
// }
|
||||
// return num, err
|
||||
// }
|
||||
|
||||
// func AddMobile2Mobile(ctx *jxcontext.Context, parentMobile, mobile string) (num int64, err error) {
|
||||
// db := dao.GetDB()
|
||||
// parentUser := &legacymodel.WeiXins{}
|
||||
// parentUser.Tel = parentMobile
|
||||
// if err = dao.GetEntity(db, parentUser, "Tel"); err == nil {
|
||||
// if parentUser.ParentID == -1 {
|
||||
// globals.SugarLogger.Debug(parentUser)
|
||||
// if err = verifyMobileHasNoMembers(db, mobile); err == nil {
|
||||
// user, err2 := verifyMobileIsBlank(db, mobile)
|
||||
// if err = err2; err == nil || err == orm.ErrNoRows {
|
||||
// user.ParentID = parentUser.ID
|
||||
// if err == nil {
|
||||
// // todo transaction
|
||||
// if num, err = dao.UpdateEntity(db, user, "ParentID"); err == nil {
|
||||
// err = dao.SetWeiXinsEmpty2Null(db, user)
|
||||
// }
|
||||
// } else {
|
||||
// dao.WrapAddIDCULEntity(user, ctx.GetUserName())
|
||||
// if err = dao.CreateWeiXins(db, user); err == nil {
|
||||
// num = 1
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// } else {
|
||||
// err = fmt.Errorf("%s本身是成员", parentMobile)
|
||||
// }
|
||||
// }
|
||||
// if err == nil {
|
||||
// jxutils.HandleUserWXRemark(db, mobile, false)
|
||||
// TransferLegacyWeixins(mobile)
|
||||
// }
|
||||
// return num, err
|
||||
// }
|
||||
|
||||
// func ChangeMobile(ctx *jxcontext.Context, curMobile, expectedMobile string) (num int64, err error) {
|
||||
// num, err = dao.UpdateEntityByKV(nil, &legacymodel.WeiXins{}, map[string]interface{}{
|
||||
// "Tel": expectedMobile,
|
||||
// }, map[string]interface{}{
|
||||
// "Tel": curMobile,
|
||||
// })
|
||||
// if err == nil {
|
||||
// TransferLegacyWeixins(curMobile)
|
||||
// TransferLegacyWeixins(expectedMobile)
|
||||
// }
|
||||
// return num, err
|
||||
// }
|
||||
|
||||
// func verifyMobileIsBlank(db *dao.DaoDB, mobile string) (user *legacymodel.WeiXins, err error) {
|
||||
// if !jxutils.IsStringLikeMobile(mobile) {
|
||||
// return nil, fmt.Errorf("%s看起来不像是一个手机号", mobile)
|
||||
// }
|
||||
// user = &legacymodel.WeiXins{
|
||||
// Tel: mobile,
|
||||
// }
|
||||
// if err = dao.GetEntity(db, user, "Tel"); err == nil {
|
||||
// if user.ParentID != -1 && user.ParentID != 0 {
|
||||
// userParent := &legacymodel.WeiXins{
|
||||
// ID: user.ParentID,
|
||||
// }
|
||||
// if err = dao.GetEntity(db, userParent); err != nil && err != orm.ErrNoRows {
|
||||
// return nil, err
|
||||
// }
|
||||
// if err != orm.ErrNoRows {
|
||||
// err = fmt.Errorf("%s已经是组长:%s,门店:%d的小组成员", mobile, userParent.Tel, userParent.JxStoreID)
|
||||
// } else {
|
||||
// err = nil
|
||||
// }
|
||||
// } else if user.JxStoreID != 0 {
|
||||
// store := &model.Store{}
|
||||
// store.ID = user.JxStoreID
|
||||
// if err = dao.GetEntity(db, store); err == nil {
|
||||
// err = fmt.Errorf("%s本身已经是门店:%d的组长", mobile, user.JxStoreID)
|
||||
// } else if dao.IsNoRowsError(err) {
|
||||
// err = nil
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return user, err
|
||||
// }
|
||||
|
||||
// func verifyMobileHasNoMembers(db *dao.DaoDB, mobile string) (err error) {
|
||||
// countInfo := &struct{ Ct int }{}
|
||||
// if err = dao.GetRow(db, countInfo, `
|
||||
// SELECT COUNT(*) ct
|
||||
// FROM weixins t1
|
||||
// JOIN weixins t2 ON t1.parentid = t2.id AND t2.tel = ?
|
||||
// `, mobile); err == nil {
|
||||
// if countInfo.Ct > 0 {
|
||||
// user := &legacymodel.WeiXins{
|
||||
// Tel: mobile,
|
||||
// }
|
||||
// dao.GetEntity(db, user, "Tel")
|
||||
// err = fmt.Errorf("%s本身已经是门店:%d组长", mobile, user.JxStoreID)
|
||||
// }
|
||||
// }
|
||||
// return err
|
||||
// }
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,23 +0,0 @@
|
||||
package cms
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
|
||||
_ "git.rosy.net.cn/jx-callback/globals/api/apimanager"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
)
|
||||
|
||||
func TestTryAddStoreBossRole4User(t *testing.T) {
|
||||
err := TryAddStoreBossRole4User(jxcontext.AdminCtx, &model.User{
|
||||
Type: model.UserTypeStoreBoss,
|
||||
UserID: "24058800CD3711E991B2525400E86DC0",
|
||||
Mobile: utils.String2Pointer("91112345678"),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
package cms
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"gopkg.in/go-playground/validator.v9"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
)
|
||||
|
||||
var (
|
||||
unitNamesMap map[string]int
|
||||
specUnitNamesMap map[string]int
|
||||
validate = validator.New()
|
||||
)
|
||||
|
||||
func init() {
|
||||
unitNamesMap = jxutils.MakeValidationMapFromSlice(model.UnitNames, 1)
|
||||
specUnitNamesMap = jxutils.MakeValidationMapFromSlice(model.SpecUnitNames, 1)
|
||||
}
|
||||
|
||||
func validateStringInMap(name string, value interface{}, flagMap map[string]int) (err error) {
|
||||
if strValue, ok := value.(string); ok {
|
||||
if flagMap[strValue] == 1 {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return fmt.Errorf("属性%s类型或取值不合法,要求string", name)
|
||||
}
|
||||
|
||||
func ValidateUnit(value interface{}) (err error) {
|
||||
return validateStringInMap("Unit", value, unitNamesMap)
|
||||
}
|
||||
|
||||
func ValidateSpecUnit(value interface{}) (err error) {
|
||||
return validateStringInMap("SpecUnit", value, specUnitNamesMap)
|
||||
}
|
||||
|
||||
func ValidateStruct(value interface{}) (err error) {
|
||||
return validate.Struct(value)
|
||||
}
|
||||
|
||||
func ValidateVar(value interface{}, tag string) (err error) {
|
||||
return validate.Var(value, tag)
|
||||
}
|
||||
|
||||
func ValidateStructPartial(value interface{}, fields ...string) (err error) {
|
||||
return validate.StructPartial(value, fields...)
|
||||
}
|
||||
@@ -1,16 +1,7 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/autonavi"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
)
|
||||
|
||||
type Store4User struct {
|
||||
@@ -62,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
|
||||
//}
|
||||
|
||||
@@ -4,29 +4,179 @@ import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxstore/financial"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
"github.com/gorilla/websocket"
|
||||
)
|
||||
|
||||
var (
|
||||
NoUseEventMap = map[string]string{
|
||||
"CreateQrOrBarCode": "CreateQrOrBarCode",
|
||||
"StatisticsReportForOrders": "StatisticsReportForOrders",
|
||||
"UpdateUser": "UpdateUser",
|
||||
}
|
||||
regexpToken = regexp.MustCompile(`,"token":".*"`)
|
||||
wsClient = &WSClient{}
|
||||
//广播频道(通道)
|
||||
broadcast = make(chan *model.ImMessageRecord)
|
||||
)
|
||||
|
||||
type CheckCookie struct {
|
||||
VendorID int `json:"vendorID"`
|
||||
VendorOrgCode string `json:"vendorOrgCode"`
|
||||
Status string `json:"status"`
|
||||
const (
|
||||
sysMessageTitle = ""
|
||||
)
|
||||
|
||||
//连接的客户端,吧每个客户端都放进来
|
||||
type WSClient struct {
|
||||
Clients map[int]map[string]*websocket.Conn
|
||||
ClientsHeart map[string]*websocket.Conn
|
||||
s *sync.RWMutex
|
||||
}
|
||||
|
||||
func init() {
|
||||
clients := make(map[int]map[string]*websocket.Conn)
|
||||
clientsHeart := make(map[string]*websocket.Conn)
|
||||
wsClient.Clients = clients
|
||||
wsClient.ClientsHeart = clientsHeart
|
||||
wsClient.s = new(sync.RWMutex)
|
||||
go handleMessages()
|
||||
}
|
||||
|
||||
//广播推送消息
|
||||
func handleMessages() {
|
||||
for {
|
||||
//读取通道中的消息
|
||||
msg := <-broadcast
|
||||
if msg.GroupID == 0 {
|
||||
// globals.SugarLogger.Debugf("heart %v", utils.Format4Output(msg, false))
|
||||
if wsClient.ClientsHeart[msg.UserID] != nil {
|
||||
if err := wsClient.ClientsHeart[msg.UserID].WriteJSON(&model.ImMessageRecord{
|
||||
Key: "pang",
|
||||
}); err != nil {
|
||||
globals.SugarLogger.Debugf("heart client.WriteJSON error: %v", err)
|
||||
wsClient.ClientsHeart[msg.UserID].Close() //关闭
|
||||
delete(wsClient.ClientsHeart, msg.UserID)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
globals.SugarLogger.Debugf("clients len %v", len(wsClient.Clients))
|
||||
//循环map客户端
|
||||
for userID, client := range wsClient.Clients[msg.GroupID] {
|
||||
//把通道中的消息发送给客户端
|
||||
user, err := dao.GetUser(dao.GetDB(), msg.UserID)
|
||||
if err == nil {
|
||||
msg.UserInfo = user
|
||||
}
|
||||
globals.SugarLogger.Debugf("msg %v", utils.Format4Output(msg, false))
|
||||
if msg.CreatedAt == utils.ZeroTimeValue {
|
||||
msg.CreatedAt = time.Now()
|
||||
}
|
||||
err = client.WriteJSON(msg)
|
||||
if err != nil {
|
||||
globals.SugarLogger.Debugf("client.WriteJSON error: %v", err)
|
||||
client.Close() //关闭
|
||||
delete(wsClient.Clients[msg.GroupID], userID)
|
||||
// delete(clients, client) //删除map中的客户端
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ImMessage(userID string, ws *websocket.Conn) (err error) {
|
||||
var (
|
||||
clientUser = make(map[string]*websocket.Conn)
|
||||
db = dao.GetDB()
|
||||
)
|
||||
//将当前客户端放入map中
|
||||
messageGroups, _ := dao.GetUserMessageGroups(dao.GetDB(), userID)
|
||||
if len(messageGroups) == 0 {
|
||||
return
|
||||
}
|
||||
wsClient.s.Lock()
|
||||
clientUser[userID] = ws
|
||||
wsClient.ClientsHeart[userID] = ws
|
||||
for _, v := range messageGroups {
|
||||
if len(wsClient.Clients[v.GroupID]) > 0 {
|
||||
wsClient.Clients[v.GroupID][userID] = ws
|
||||
} else {
|
||||
wsClient.Clients[v.GroupID] = clientUser
|
||||
}
|
||||
}
|
||||
wsClient.s.Unlock()
|
||||
globals.SugarLogger.Debugf("userID :%v ,clients :%v", userID, utils.Format4Output(wsClient.Clients, false))
|
||||
|
||||
var s *model.ImMessageRecord
|
||||
for {
|
||||
//接收客户端的消息
|
||||
err := ws.ReadJSON(&s)
|
||||
if err != nil {
|
||||
globals.SugarLogger.Debugf("页面可能断开啦 ws.ReadJSON error: %v", err.Error())
|
||||
for k, _ := range wsClient.Clients {
|
||||
delete(wsClient.Clients[k], userID)
|
||||
}
|
||||
delete(wsClient.ClientsHeart, userID)
|
||||
// delete(clients, ws) //删除map中的客户端
|
||||
break //结束循环
|
||||
} else {
|
||||
//接受消息 业务逻辑
|
||||
broadcast <- s
|
||||
if s.GroupID != 0 {
|
||||
if s.GroupID != model.SysGroupID {
|
||||
//发聊天消息时,这个组所有的成员包括创建者都在userIDs里
|
||||
userIDs := []string{}
|
||||
if results, err := dao.GetMessageGroups(db, "", s.GroupID, 0, true, ""); err == nil {
|
||||
for _, v := range results {
|
||||
userIDs = append(userIDs, v.UserID)
|
||||
for _, vv := range v.MessageGroupMembers {
|
||||
userIDs = append(userIDs, vv.UserID)
|
||||
}
|
||||
}
|
||||
}
|
||||
//如果这些人不在这个组的ws池子里就打上未读标记
|
||||
for _, v := range userIDs {
|
||||
if wsClient.ClientsHeart[v] == nil {
|
||||
messageGroupReads, _ := dao.GetMessageGroupRead(db, v, s.GroupID)
|
||||
for _, vv := range messageGroupReads {
|
||||
vv.UnReadCount++
|
||||
dao.UpdateEntity(db, vv, "UnReadCount")
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if wsClient.ClientsHeart[s.ToUserID] == nil {
|
||||
messageGroupReads, _ := dao.GetMessageGroupRead(db, s.ToUserID, s.GroupID)
|
||||
for _, vv := range messageGroupReads {
|
||||
vv.UnReadCount++
|
||||
dao.UpdateEntity(db, vv, "UnReadCount")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
utils.CallFuncAsync(func() {
|
||||
if s.GroupID != 0 {
|
||||
dao.WrapAddIDCULDEntity(s, "")
|
||||
dao.CreateEntity(db, s)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
ws.Close()
|
||||
return err
|
||||
}
|
||||
|
||||
func GetOnlineUserCount() (count int) {
|
||||
wsClient.s.RLock()
|
||||
count = len(wsClient.ClientsHeart)
|
||||
wsClient.s.RUnlock()
|
||||
return count
|
||||
}
|
||||
|
||||
func AddOperateEvent(ctx *jxcontext.Context, accessUUID, jsonData string, errCode, errMsg string, useTime int, apiFunctionSpec string) (err error) {
|
||||
@@ -67,45 +217,45 @@ func AddOperateEvent(ctx *jxcontext.Context, accessUUID, jsonData string, errCod
|
||||
ErrMsg: errMsg,
|
||||
UseTime: useTime,
|
||||
}
|
||||
dao.Begin(db)
|
||||
txDB, _ := dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
dao.Rollback(db)
|
||||
dao.Rollback(db, txDB)
|
||||
panic(r)
|
||||
}
|
||||
}()
|
||||
err = dao.CreateEntity(db, event)
|
||||
dao.Commit(db)
|
||||
dao.Commit(db, txDB)
|
||||
return err
|
||||
}
|
||||
|
||||
func AddOperateEventDetail(db *dao.DaoDB, operateEventDetail *model.OperateEventDetail) (err error) {
|
||||
dao.Begin(db)
|
||||
txDB, _ := dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
dao.Rollback(db)
|
||||
dao.Rollback(db, txDB)
|
||||
panic(r)
|
||||
}
|
||||
}()
|
||||
operateEventDetail.BeforeData = utils.LimitUTF8StringLen(operateEventDetail.BeforeData, 3200)
|
||||
operateEventDetail.AfterData = utils.LimitUTF8StringLen(operateEventDetail.AfterData, 3200)
|
||||
err = dao.CreateEntity(db, operateEventDetail)
|
||||
dao.Commit(db)
|
||||
dao.Commit(db, txDB)
|
||||
return err
|
||||
}
|
||||
|
||||
func DeleteOperateEventAndDetail(ctx *jxcontext.Context, deleteTime time.Time) (err error) {
|
||||
db := dao.GetDB()
|
||||
dao.Begin(db)
|
||||
txDB, _ := dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
dao.Rollback(db)
|
||||
dao.Rollback(db, txDB)
|
||||
panic(r)
|
||||
}
|
||||
}()
|
||||
dao.DeleteOperateEventDetail(db, deleteTime)
|
||||
dao.DeleteOperateEvent(db, deleteTime)
|
||||
dao.Commit(db)
|
||||
dao.Commit(db, txDB)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -134,68 +284,505 @@ func GetOperateEvents(ctx *jxcontext.Context, name string, apiFunctions []string
|
||||
return pageInfo, err
|
||||
}
|
||||
|
||||
func GetCheckVendorCookie(ctx *jxcontext.Context, vendorIDs []int, isAuto bool) (ccList []*CheckCookie, err error) {
|
||||
func CreateMessageGroup(ctx *jxcontext.Context, userID, userID2, groupName string, dividePercentage, quitPrice int) (messageGroupResult *dao.GetMessageGroupsResult, err error) {
|
||||
var (
|
||||
ebaiOrderID = "1577329467196263592"
|
||||
ebaiErr = "return not json"
|
||||
ebaiErr2 = "系统错误"
|
||||
mtStoreID = "7388603"
|
||||
mtErr = "返回结果格式不正常"
|
||||
jdUpcCode = "6952395700895"
|
||||
jdErr = "请输入用户名"
|
||||
// mtpsErr = "用户未登录"
|
||||
errMsg = ""
|
||||
db = dao.GetDB()
|
||||
groupID int
|
||||
)
|
||||
for _, v := range vendorIDs {
|
||||
cc := &CheckCookie{}
|
||||
var flag = false
|
||||
switch v {
|
||||
case model.VendorIDEBAI:
|
||||
resultMap, err := api.EbaiAPI.GetStoreOrderInfo(ebaiOrderID)
|
||||
if len(resultMap) < 1 && err != nil {
|
||||
if strings.Contains(err.Error(), ebaiErr) || strings.Contains(err.Error(), ebaiErr2) {
|
||||
errMsg += fmt.Sprintf(" 饿百账号:[%v]的Cookie无效了!")
|
||||
flag = true
|
||||
}
|
||||
for {
|
||||
groupID = jxutils.GenRand6()
|
||||
temp := &model.MessageGroup{
|
||||
GroupID: groupID,
|
||||
}
|
||||
dao.GetEntity(db, temp, "GroupID")
|
||||
if temp.UserID == "" {
|
||||
break
|
||||
}
|
||||
}
|
||||
if userID2 != "" {
|
||||
messageGroups, err := dao.GetMessageGroups(db, userID, 0, model.GroupTypeSingle, true, userID2)
|
||||
if len(messageGroups) > 0 && len(messageGroups[0].MessageGroupMembers) > 0 {
|
||||
return messageGroups[0], err
|
||||
}
|
||||
user, err := dao.GetUserByID(db, "user_id", userID2)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if user == nil {
|
||||
return nil, fmt.Errorf("无法找到要联系的用户!")
|
||||
}
|
||||
messageGroup := &model.MessageGroup{
|
||||
GroupID: groupID,
|
||||
UserID: userID,
|
||||
// Name: user.Name,
|
||||
Type: model.GroupTypeSingle,
|
||||
MaxCount: 2,
|
||||
}
|
||||
messageGroupMember := &model.MessageGroupMember{
|
||||
GroupID: groupID,
|
||||
MemberUserID: userID2,
|
||||
Type: model.GroupMemberTypeNormal,
|
||||
}
|
||||
dao.WrapAddIDCULDEntity(messageGroup, ctx.GetUserName())
|
||||
dao.WrapAddIDCULDEntity(messageGroupMember, ctx.GetUserName())
|
||||
err = dao.CreateEntity(db, messageGroup)
|
||||
err = dao.CreateEntity(db, messageGroupMember)
|
||||
if err == nil {
|
||||
messageGroupRead := &model.MessageGroupRead{
|
||||
GroupID: groupID,
|
||||
UserID: userID,
|
||||
}
|
||||
case model.VendorIDMTWM:
|
||||
_, err := api.MtwmAPI.PackagePriceGet(mtStoreID)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), mtErr) {
|
||||
errMsg += fmt.Sprintf(" 美团账号:[%v]的Cookie无效了!")
|
||||
flag = true
|
||||
dao.WrapAddIDCULEntity(messageGroupRead, ctx.GetUserName())
|
||||
messageGroupRead2 := messageGroupRead
|
||||
messageGroupRead2.UserID = userID2
|
||||
dao.CreateEntity(db, messageGroupRead)
|
||||
if err = dao.CreateEntity(db, messageGroupRead2); err == nil {
|
||||
if messageGroupReads, err := dao.GetMessageGroupRead(db, userID2, model.SysGroupID); len(messageGroupReads) == 0 && err == nil {
|
||||
messageGroupRead := &model.MessageGroupRead{
|
||||
GroupID: model.SysGroupID,
|
||||
UserID: userID2,
|
||||
}
|
||||
dao.WrapAddIDCULEntity(messageGroupRead, ctx.GetUserName())
|
||||
dao.CreateEntity(db, messageGroupRead)
|
||||
}
|
||||
globals.SugarLogger.Debugf("cookieCheck", err)
|
||||
}
|
||||
case model.VendorIDJD:
|
||||
result, err := api.JdAPI.GetJdUpcCodeByName("", jdUpcCode, 1, 5)
|
||||
if len(result) < 1 && err != nil {
|
||||
if strings.Contains(err.Error(), jdErr) {
|
||||
errMsg += fmt.Sprintf(" 京东账号:[%v]的Cookie无效了!")
|
||||
flag = true
|
||||
}
|
||||
}
|
||||
case model.VendorIDJDShop:
|
||||
_, err := api.JdShopAPI.OrderDetail("124350112427")
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "登录") {
|
||||
errMsg += fmt.Sprintf("京东商城:[%v]的Cookie无效了!")
|
||||
flag = true
|
||||
}
|
||||
globals.SugarLogger.Debugf("cookieCheck", err)
|
||||
}
|
||||
}
|
||||
cc.VendorID = v
|
||||
cc.VendorOrgCode = ""
|
||||
if flag {
|
||||
cc.Status = "无效"
|
||||
} else {
|
||||
cc.Status = "有效"
|
||||
} else {
|
||||
userMembers, err := dao.GetUserMember(db, userID, model.MemberTypeNormal)
|
||||
messageGroupsResult, err := dao.GetMessageGroups(db, userID, 0, model.GroupTypeMulit, false, "")
|
||||
messageGroupMembers, err := dao.GetMessageGroupMembers(db, 0, model.GroupTypeMulit, userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(userMembers) == 0 {
|
||||
return nil, fmt.Errorf("抱歉,只有会员才能创建群聊!")
|
||||
}
|
||||
if len(messageGroupsResult) > 0 {
|
||||
return nil, fmt.Errorf("您已经有群组了,请勿重复创建!群号为:%d", messageGroupsResult[0].GroupID)
|
||||
}
|
||||
if len(messageGroupMembers) > 0 {
|
||||
return nil, fmt.Errorf("您已加入了[%v]群,请先退出后再创建!", messageGroupMembers[0].GroupID)
|
||||
}
|
||||
messageGroup := &model.MessageGroup{
|
||||
GroupID: groupID,
|
||||
UserID: userID,
|
||||
Name: groupName,
|
||||
Type: model.GroupTypeMulit,
|
||||
MaxCount: 2000,
|
||||
DividePercentage: dividePercentage,
|
||||
QuitPrice: quitPrice,
|
||||
}
|
||||
user, err := dao.GetUserByID(db, "user_id", userID)
|
||||
if groupName == "" {
|
||||
messageGroup.Name = user.Name + "的集团"
|
||||
}
|
||||
dao.WrapAddIDCULDEntity(messageGroup, ctx.GetUserName())
|
||||
if err = dao.CreateEntity(db, messageGroup); err == nil {
|
||||
messageGroupRead := &model.MessageGroupRead{
|
||||
GroupID: groupID,
|
||||
UserID: userID,
|
||||
}
|
||||
dao.WrapAddIDCULEntity(messageGroupRead, ctx.GetUserName())
|
||||
dao.CreateEntity(db, messageGroupRead)
|
||||
}
|
||||
ccList = append(ccList, cc)
|
||||
}
|
||||
if isAuto && errMsg != "" {
|
||||
globals.SugarLogger.Warnf("GetCheckVendorCookie:[%v]", errMsg)
|
||||
if err == nil {
|
||||
if messageGroupReads, err := dao.GetMessageGroupRead(db, userID, model.SysGroupID); len(messageGroupReads) == 0 && err == nil {
|
||||
messageGroupRead := &model.MessageGroupRead{
|
||||
GroupID: model.SysGroupID,
|
||||
UserID: userID,
|
||||
}
|
||||
dao.WrapAddIDCULEntity(messageGroupRead, ctx.GetUserName())
|
||||
dao.CreateEntity(db, messageGroupRead)
|
||||
}
|
||||
}
|
||||
return ccList, err
|
||||
return messageGroupResult, err
|
||||
}
|
||||
|
||||
func GetMessageGroupByUser(ctx *jxcontext.Context, userID string) (messageGroupResult []*dao.GetMessageGroupsResult, err error) {
|
||||
var (
|
||||
db = dao.GetDB()
|
||||
)
|
||||
messageGroups, err := dao.GetMessageGroups(db, "", model.SysGroupID, 0, false, "")
|
||||
messageGroups2, err := dao.GetMessageGroups(db, userID, 0, 0, true, "")
|
||||
messageGroups = append(messageGroups, messageGroups2...)
|
||||
messageGroupMembers, err := dao.GetMessageGroupMembers(db, 0, 0, userID)
|
||||
for _, v := range messageGroupMembers {
|
||||
if messageGroupList, err := dao.GetMessageGroups(db, "", v.GroupID, 0, false, ""); err == nil {
|
||||
messageGroups = append(messageGroups, messageGroupList...)
|
||||
}
|
||||
}
|
||||
for _, v := range messageGroups {
|
||||
//是这个人创建的群聊,如果是单聊就返回对方的头像
|
||||
if v.Type == model.GroupTypeSingle {
|
||||
var userID2 string
|
||||
if v.UserID == userID {
|
||||
userID2 = v.MessageGroupMembers[0].MemberUserID
|
||||
} else {
|
||||
userID2 = userID
|
||||
}
|
||||
if user, err := dao.GetUserByID(db, "user_id", userID2); err == nil {
|
||||
v.Avatar = user.Avatar
|
||||
v.Name = user.Name
|
||||
}
|
||||
}
|
||||
var (
|
||||
imMessageRecord *model.ImMessageRecord
|
||||
sql string
|
||||
sqlParams = []interface{}{}
|
||||
)
|
||||
if v.GroupID != model.SysGroupID {
|
||||
//最后一条记录和时间和人
|
||||
sql = `
|
||||
SELECT * FROM im_message_record WHERE group_id = ? ORDER BY created_at DESC LIMIT 1
|
||||
`
|
||||
sqlParams = append(sqlParams, v.GroupID)
|
||||
} else {
|
||||
//最后一条记录和时间和人
|
||||
sql = `
|
||||
SELECT * FROM im_message_record WHERE group_id = ? AND to_user_id = ? ORDER BY created_at DESC LIMIT 1
|
||||
`
|
||||
sqlParams = append(sqlParams, v.GroupID, userID)
|
||||
}
|
||||
if err = dao.GetRow(db, &imMessageRecord, sql, sqlParams); err == nil {
|
||||
v.LastTime = imMessageRecord.CreatedAt
|
||||
v.LastContent = imMessageRecord.Content
|
||||
v.LastMessageType = imMessageRecord.MessageType
|
||||
if user3, err := dao.GetUserByID(db, "user_id", imMessageRecord.UserID); err == nil {
|
||||
v.LastUserName = user3.Name
|
||||
}
|
||||
} else {
|
||||
err = nil
|
||||
}
|
||||
//该用户各组的未读消息数
|
||||
var unReadCount int
|
||||
if messageGroupReads, err := dao.GetMessageGroupRead(db, userID, v.GroupID); err == nil && len(messageGroupReads) > 0 {
|
||||
for _, vv := range messageGroupReads {
|
||||
unReadCount += vv.UnReadCount
|
||||
}
|
||||
}
|
||||
v.UnReadMessageCount = unReadCount
|
||||
}
|
||||
return messageGroups, err
|
||||
}
|
||||
|
||||
func AddMessageGroup(ctx *jxcontext.Context, groupID int, userID string) (err error) {
|
||||
var (
|
||||
db = dao.GetDB()
|
||||
)
|
||||
messageGroupMembers, err := dao.GetMessageGroupMembers(db, groupID, 0, userID)
|
||||
messageGroupMembers3, err := dao.GetMessageGroupMembers(db, 0, 0, userID)
|
||||
messageGroupsResult, err := dao.GetMessageGroups(db, userID, groupID, model.GroupTypeMulit, false, "")
|
||||
messageGroupsResult2, err := dao.GetMessageGroups(db, "", groupID, model.GroupTypeMulit, false, "")
|
||||
messageGroupsResult3, err := dao.GetMessageGroups(db, userID, 0, model.GroupTypeMulit, false, "")
|
||||
messageGroupMembers2, err := dao.GetMessageGroupMembers(db, groupID, 0, "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(messageGroupMembers) > 0 {
|
||||
return fmt.Errorf("此用户已经在该群组中了!")
|
||||
}
|
||||
if len(messageGroupMembers3) > 0 {
|
||||
return fmt.Errorf("您已经有群组[%v]了,不能申请加入其它群!", messageGroupMembers3[0].GroupID)
|
||||
}
|
||||
if len(messageGroupsResult) > 0 {
|
||||
return fmt.Errorf("请不要加入自己创建的群!")
|
||||
}
|
||||
if len(messageGroupsResult2) > 0 && len(messageGroupMembers2) > 0 {
|
||||
if len(messageGroupMembers2)+1 > messageGroupsResult2[0].MaxCount {
|
||||
return fmt.Errorf("抱歉该群组已经满员了!")
|
||||
}
|
||||
}
|
||||
if len(messageGroupsResult3) > 0 {
|
||||
return fmt.Errorf("您已经拥有[%v]群了,不能再加入其它群!", messageGroupsResult3[0].GroupID)
|
||||
}
|
||||
|
||||
messageGroupMember := &model.MessageGroupMember{
|
||||
GroupID: groupID,
|
||||
MemberUserID: userID,
|
||||
Type: model.GroupMemberTypeNormal,
|
||||
}
|
||||
dao.WrapAddIDCULDEntity(messageGroupMember, ctx.GetUserName())
|
||||
if err = dao.CreateEntity(db, messageGroupMember); err == nil {
|
||||
messageGroupRead := &model.MessageGroupRead{
|
||||
GroupID: groupID,
|
||||
UserID: userID,
|
||||
}
|
||||
dao.WrapAddIDCULEntity(messageGroupRead, ctx.GetUserName())
|
||||
if err = dao.CreateEntity(db, messageGroupRead); err == nil {
|
||||
if messageGroupReads, err := dao.GetMessageGroupRead(db, userID, model.SysGroupID); len(messageGroupReads) == 0 && err == nil {
|
||||
messageGroupRead := &model.MessageGroupRead{
|
||||
GroupID: model.SysGroupID,
|
||||
UserID: userID,
|
||||
}
|
||||
dao.WrapAddIDCULEntity(messageGroupRead, ctx.GetUserName())
|
||||
dao.CreateEntity(db, messageGroupRead)
|
||||
}
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func UpdateMessageGroup(ctx *jxcontext.Context, groupID int, payload map[string]interface{}) (num int64, err error) {
|
||||
var (
|
||||
db = dao.GetDB()
|
||||
messageGroup = &model.MessageGroup{
|
||||
GroupID: groupID,
|
||||
}
|
||||
)
|
||||
if err = dao.GetEntity(db, messageGroup, "GroupID"); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if messageGroup.UserID != ctx.GetUserID() {
|
||||
return 0, fmt.Errorf("只有群主才能修改群信息!")
|
||||
}
|
||||
valid := dao.StrictMakeMapByStructObject(payload, messageGroup, ctx.GetUserName())
|
||||
if len(valid) > 0 {
|
||||
txDB, _ := dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
dao.Rollback(db, txDB)
|
||||
panic(r)
|
||||
}
|
||||
}()
|
||||
if num, err = dao.UpdateEntityLogically(db, messageGroup, valid, ctx.GetUserName(), nil); err != nil {
|
||||
dao.Rollback(db, txDB)
|
||||
return 0, err
|
||||
}
|
||||
dao.Commit(db, txDB)
|
||||
}
|
||||
return num, err
|
||||
}
|
||||
|
||||
func DeleteMessageGroup(ctx *jxcontext.Context, groupID int, userID string, flag bool) (errCode string, err error) {
|
||||
var (
|
||||
db = dao.GetDB()
|
||||
messageGroup = &model.MessageGroup{
|
||||
GroupID: groupID,
|
||||
}
|
||||
)
|
||||
if err = dao.GetEntity(db, messageGroup, "GroupID"); err != nil {
|
||||
return errCode, err
|
||||
}
|
||||
//解散群
|
||||
if flag {
|
||||
if messageGroup.UserID != ctx.GetUserID() {
|
||||
return errCode, fmt.Errorf("只有群主才能解散群!")
|
||||
}
|
||||
messageGroup.DeletedAt = time.Now()
|
||||
messageGroup.LastOperator = ctx.GetUserName()
|
||||
dao.UpdateEntity(db, messageGroup, "DeletedAt", "LastOperator")
|
||||
messageGroupMembers, _ := dao.GetMessageGroupMembers(db, groupID, 0, "")
|
||||
for _, v := range messageGroupMembers {
|
||||
v.DeletedAt = time.Now()
|
||||
v.LastOperator = ctx.GetUserName()
|
||||
dao.UpdateEntity(db, v, "DeletedAt", "LastOperator")
|
||||
}
|
||||
} else {
|
||||
//token中用户与传入user不一致就判定为踢人
|
||||
if ctx.GetUserID() != userID {
|
||||
if messageGroup.UserID != ctx.GetUserID() {
|
||||
messageGroupMembers, err := dao.GetMessageGroupMembers(db, groupID, 0, ctx.GetUserID())
|
||||
if err != nil {
|
||||
return errCode, err
|
||||
}
|
||||
if messageGroupMembers[0].Type == model.GroupMemberTypeNormal {
|
||||
return errCode, fmt.Errorf("只有创建者和管理员才能踢人!")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
quitPrice := messageGroup.QuitPrice
|
||||
userBill, err := dao.GetUserBill(db, userID, "")
|
||||
userBillGroupMaster, err := dao.GetUserBill(db, messageGroup.UserID, "")
|
||||
if err != nil {
|
||||
return errCode, err
|
||||
}
|
||||
if userBill.AccountBalance < quitPrice {
|
||||
return model.ErrCodeAccountBalanceNotEnough, fmt.Errorf("用户余额不足,请充值!")
|
||||
}
|
||||
txDB, _ := dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
dao.Rollback(db, txDB)
|
||||
panic(r)
|
||||
}
|
||||
}()
|
||||
//账户支出
|
||||
if err = financial.AddExpendUpdateAccount(txDB, userBill, model.BillTypeQuitGroup, quitPrice, 0); err != nil {
|
||||
dao.Rollback(db, txDB)
|
||||
return errCode, err
|
||||
}
|
||||
//群主收到退团金额
|
||||
if err = financial.AddIncomeUpdateAccount(txDB, userBillGroupMaster, model.BillTypeQuitGroup, quitPrice, 0); err != nil {
|
||||
dao.Rollback(db, txDB)
|
||||
return errCode, err
|
||||
}
|
||||
dao.Commit(db, txDB)
|
||||
}
|
||||
messageGroupMembers, err := dao.GetMessageGroupMembers(db, groupID, 0, userID)
|
||||
if err != nil {
|
||||
return errCode, err
|
||||
}
|
||||
messageGroupMembers[0].DeletedAt = time.Now()
|
||||
messageGroupMembers[0].LastOperator = ctx.GetUserName()
|
||||
dao.UpdateEntity(db, messageGroupMembers[0], "DeletedAt", "LastOperator")
|
||||
}
|
||||
return errCode, err
|
||||
}
|
||||
|
||||
func TransferMessageGroupMaster(ctx *jxcontext.Context, groupID int, userID string) (err error) {
|
||||
var (
|
||||
db = dao.GetDB()
|
||||
messageGroup = &model.MessageGroup{
|
||||
GroupID: groupID,
|
||||
}
|
||||
)
|
||||
if err = dao.GetEntity(db, messageGroup, "GroupID"); err != nil {
|
||||
return err
|
||||
}
|
||||
if messageGroup.UserID != ctx.GetUserID() {
|
||||
return fmt.Errorf("只有群主才能转让群主!")
|
||||
}
|
||||
//群主换成选的那个人
|
||||
messageGroup.UserID = userID
|
||||
messageGroup.LastOperator = ctx.GetUserName()
|
||||
//之前那个群成员换成之前的群主
|
||||
messageGroupMembers, err := dao.GetMessageGroupMembers(db, groupID, 0, userID)
|
||||
if err != nil && len(messageGroupMembers) == 0 {
|
||||
return err
|
||||
}
|
||||
messageGroupMember := messageGroupMembers[0]
|
||||
messageGroupMember.MemberUserID = ctx.GetUserID()
|
||||
messageGroupMember.LastOperator = ctx.GetUserName()
|
||||
txDB, _ := dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
dao.Rollback(db, txDB)
|
||||
panic(r)
|
||||
}
|
||||
}()
|
||||
if _, err = dao.UpdateEntity(db, messageGroup, "UserID", "LastOperator"); err != nil {
|
||||
dao.Rollback(db, txDB)
|
||||
return err
|
||||
}
|
||||
if _, err = dao.UpdateEntity(db, messageGroupMember, "MemberUserID", "LastOperator"); err != nil {
|
||||
dao.Rollback(db, txDB)
|
||||
return err
|
||||
}
|
||||
dao.Commit(db, txDB)
|
||||
return err
|
||||
}
|
||||
|
||||
func SendSysMessageSimple(content, toUserID string) (err error) {
|
||||
return SendSysMessage(jxcontext.AdminCtx, &model.ImMessageRecord{
|
||||
Content: sysMessageTitle + " " + content,
|
||||
ToUserID: toUserID,
|
||||
GroupID: model.SysGroupID,
|
||||
MessageType: 1, // 普通文字消息
|
||||
})
|
||||
}
|
||||
|
||||
func SendSysMessage(ctx *jxcontext.Context, imMessageRecord *model.ImMessageRecord) (err error) {
|
||||
var (
|
||||
db = dao.GetDB()
|
||||
userID = imMessageRecord.ToUserID
|
||||
groupID = imMessageRecord.GroupID
|
||||
)
|
||||
if groupID != model.SysGroupID {
|
||||
return fmt.Errorf("只能给系统组发消息!")
|
||||
}
|
||||
imMessageRecord.CreatedAt = time.Now()
|
||||
imMessageRecord.LastOperator = ctx.GetUserName()
|
||||
imMessageRecord.DeletedAt = utils.DefaultTimeValue
|
||||
imMessageRecord.UpdatedAt = utils.DefaultTimeValue
|
||||
imMessageRecord.Seq = time.Now().Unix()
|
||||
err = dao.CreateEntity(db, imMessageRecord)
|
||||
if userID == "" {
|
||||
//循环map客户端
|
||||
for _, client := range wsClient.Clients[groupID] {
|
||||
globals.SugarLogger.Debugf("msg %v", utils.Format4Output(imMessageRecord, false))
|
||||
err = client.WriteJSON(imMessageRecord)
|
||||
if err != nil {
|
||||
globals.SugarLogger.Debugf("client.WriteJSON error: %v", err)
|
||||
client.Close() //关闭
|
||||
// delete(wsClient.Clients[msg.GroupID], userID)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
client := wsClient.Clients[groupID][userID]
|
||||
globals.SugarLogger.Debugf("msg %v", utils.Format4Output(imMessageRecord, false))
|
||||
if client == nil {
|
||||
return
|
||||
}
|
||||
err = client.WriteJSON(imMessageRecord)
|
||||
if err != nil {
|
||||
globals.SugarLogger.Debugf("client.WriteJSON error: %v", err)
|
||||
client.Close() //关闭
|
||||
// delete(wsClient.Clients[msg.GroupID], userID)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func DeleteMessageRecord(ctx *jxcontext.Context) (err error) {
|
||||
var (
|
||||
db = dao.GetDB()
|
||||
)
|
||||
sql := `
|
||||
DELETE FROM im_message_record WHERE created_at < ? AND group_id <> ?
|
||||
`
|
||||
sqlParams := []interface{}{
|
||||
time.Now().AddDate(0, 0, -3), model.SysGroupID,
|
||||
}
|
||||
_, err = dao.ExecuteSQL(db, sql, sqlParams)
|
||||
return err
|
||||
}
|
||||
|
||||
func UpdateUserMessageGroupRead(ctx *jxcontext.Context, reads []*model.MessageGroupRead) (err error) {
|
||||
var (
|
||||
db = dao.GetDB()
|
||||
userID = ctx.GetUserID()
|
||||
)
|
||||
for _, v := range reads {
|
||||
if messageReads, err := dao.GetMessageGroupRead(db, userID, v.GroupID); err == nil {
|
||||
if len(messageReads) > 0 {
|
||||
messageReads[0].UnReadCount += v.UnReadCount
|
||||
dao.UpdateEntity(db, messageReads[0], "UnReadCount")
|
||||
} else {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
type GetUserStatisticsResult struct {
|
||||
RegisterUserCount int `json:"registerUserCount"` //注册数
|
||||
OnlineUserCount int `json:"onlineUserCount"` //在线用户数
|
||||
ConsumeUserCount int `json:"consumeUserCount"` //消费用户数
|
||||
MemberUserCount int `json:"memberUserCount"` //会员用户数
|
||||
}
|
||||
|
||||
func GetUserStatistics(ctx *jxcontext.Context) (getUserStatisticsResult *GetUserStatisticsResult, err error) {
|
||||
var (
|
||||
db = dao.GetDB()
|
||||
)
|
||||
getUserStatisticsResult = &GetUserStatisticsResult{}
|
||||
sql := `
|
||||
SELECT a.member_user_count, b.consume_user_count FROM
|
||||
( SELECT DISTINCT COUNT(a.user_id) member_user_count
|
||||
FROM user a
|
||||
JOIN user_member b ON a.user_id = b.user_id AND b.deleted_at = ? )a,
|
||||
( SELECT DISTINCT COUNT(a.user_id) consume_user_count
|
||||
FROM user a
|
||||
JOIN ` + "`order`" + `b ON a.user_id = b.user_id AND b.status = ?)b
|
||||
`
|
||||
sqlParams := []interface{}{
|
||||
utils.DefaultTimeValue, model.OrderStatusFinished,
|
||||
}
|
||||
err = dao.GetRow(db, &getUserStatisticsResult, sql, sqlParams)
|
||||
paged, _ := dao.GetUsers2(db, "", "", 0, "", utils.ZeroTimeValue, utils.ZeroTimeValue, 0, nil, nil, 0, -1)
|
||||
getUserStatisticsResult.RegisterUserCount = paged.TotalCount
|
||||
getUserStatisticsResult.OnlineUserCount = GetOnlineUserCount()
|
||||
return getUserStatisticsResult, err
|
||||
}
|
||||
|
||||
97
business/jxstore/event/event_print.go
Normal file
97
business/jxstore/event/event_print.go
Normal 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)
|
||||
}
|
||||
373
business/jxstore/event/event_tcp.go
Normal file
373
business/jxstore/event/event_tcp.go
Normal 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
|
||||
}
|
||||
}
|
||||
687
business/jxstore/event/event_tcp_utils.go
Normal file
687
business/jxstore/event/event_tcp_utils.go
Normal 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)
|
||||
}
|
||||
117
business/jxstore/event/print_test.go
Normal file
117
business/jxstore/event/print_test.go
Normal 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)
|
||||
}
|
||||
104
business/jxstore/event/timing_task.go
Normal file
104
business/jxstore/event/timing_task.go
Normal 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()
|
||||
}
|
||||
243
business/jxstore/financial/bill.go
Normal file
243
business/jxstore/financial/bill.go
Normal 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
|
||||
}
|
||||
14
business/jxstore/financial/bill_test.go
Normal file
14
business/jxstore/financial/bill_test.go
Normal 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("微信购买会员失败")
|
||||
//}
|
||||
}
|
||||
@@ -1,119 +1,410 @@
|
||||
package financial
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"crypto/hmac"
|
||||
"crypto/md5"
|
||||
"crypto/sha256"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"mime/multipart"
|
||||
"path"
|
||||
"github.com/astaxie/beego/client/orm"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/tonglianpayapi"
|
||||
"git.rosy.net.cn/baseapi/platformapi/wxpayapi"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/weixinmsg"
|
||||
"git.rosy.net.cn/jx-callback/business/auth2/authprovider/weixin"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/model/legacymodel"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
"github.com/qiniu/api.v7/storage"
|
||||
)
|
||||
|
||||
type tUploadFileInfo struct {
|
||||
FileHeader *multipart.FileHeader
|
||||
StoreID int
|
||||
const (
|
||||
sigKey = "sign"
|
||||
sigTypeMd5 = "MD5"
|
||||
sigTypeSha256 = "HMAC-SHA256"
|
||||
)
|
||||
|
||||
var (
|
||||
payMap = map[string]*wxpayapi.API{
|
||||
"weixinapp": api.WxpayAPI,
|
||||
"weixinmini": api.WxpayAPI2,
|
||||
}
|
||||
)
|
||||
|
||||
func (p *PayHandler) CreatePay(txDB orm.TxOrmer, subAppID string) (err error) {
|
||||
switch p.PayType {
|
||||
case model.PayTypeTL:
|
||||
param := &tonglianpayapi.CreateUnitorderOrderParam{
|
||||
Trxamt: p.Order.PayPrice,
|
||||
NotifyUrl: globals.TLPayNotifyURL,
|
||||
Reqsn: p.Order.OrderID,
|
||||
PayType: p.VendorPayType,
|
||||
}
|
||||
//暂时做兼容处理
|
||||
if p.VendorPayType == "JSAPI" {
|
||||
param.PayType = tonglianpayapi.PayTypeWxXcx
|
||||
}
|
||||
if p.VendorPayType == tonglianpayapi.PayTypeWxXcx {
|
||||
param.SubAppID = subAppID
|
||||
authInfo, err := p.Ctx.GetV2AuthInfo()
|
||||
// 微信小程序支付
|
||||
if err == nil && authInfo.GetAuthType() == weixin.AuthTypeMini && authInfo.GetAuthTypeID() == subAppID {
|
||||
param.Acct = authInfo.GetAuthID()
|
||||
}
|
||||
}
|
||||
if p.VendorPayType == tonglianpayapi.PayTypeZfbJS || p.VendorPayType == tonglianpayapi.PayTypeZfbApp {
|
||||
if authInfo, err := p.Ctx.GetV2AuthInfo(); err == nil {
|
||||
param.Acct = authInfo.GetAuthID()
|
||||
}
|
||||
if param.Acct == "" {
|
||||
return fmt.Errorf("未找到用户的认证ID!")
|
||||
}
|
||||
}
|
||||
if p.VendorPayType == tonglianpayapi.PayTypeH5 {
|
||||
param2 := &tonglianpayapi.CreateH5UnitorderOrderParam{
|
||||
Trxamt: p.Order.PayPrice,
|
||||
NotifyUrl: globals.TLPayNotifyURL,
|
||||
Body: "冲天猴",
|
||||
Charset: "UTF-8",
|
||||
}
|
||||
err = api.TLpayAPI.CreateH5UnitorderOrder(param2)
|
||||
} else {
|
||||
result, err := api.TLpayAPI.CreateUnitorderOrder(param)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var result2 tonglianpayapi.PayInfo
|
||||
json.Unmarshal([]byte(result.PayInfo), &result2)
|
||||
p.Order.PrepayID = result2.Package[strings.LastIndex(result2.Package, "=")+1 : len(result2.Package)]
|
||||
p.Order.TransactionID = result.TrxID
|
||||
|
||||
if _, err = dao.UpdateEntityTx(txDB, p.Order, "PrepayID", "TransactionID"); err != nil {
|
||||
return err
|
||||
}
|
||||
wxPay := &WxPayParam{
|
||||
Prepayid: p.Order.PrepayID,
|
||||
Noncestr: result2.NonceStr,
|
||||
Timestamp: utils.Int64ToStr(utils.MustInterface2Int64(result2.TimeStamp)),
|
||||
Package: result2.Package,
|
||||
Partnerid: "", // 商户Id
|
||||
Appid: result2.AppID,
|
||||
Sign: result2.PaySign,
|
||||
}
|
||||
p.WxPayParam = wxPay
|
||||
}
|
||||
// 暂时不支持微信直接支付
|
||||
case model.PayTypeWX:
|
||||
param := &wxpayapi.CreateOrderParam{
|
||||
OutTradeNo: p.Order.OrderID,
|
||||
Body: "冲天猴儿App账户充值",
|
||||
NotifyURL: globals.WxpayNotifyURL,
|
||||
SpbillCreateIP: p.Ctx.GetRealRemoteIP(),
|
||||
TradeType: p.VendorPayType,
|
||||
TotalFee: p.Order.PayPrice,
|
||||
TimeStart: wxpayapi.Time2PayTime(time.Now()),
|
||||
// ProfitSharing: wxpayapi.OptYes,
|
||||
}
|
||||
authBinds, err := dao.GetUserBindAuthInfo(dao.GetDB(), p.Ctx.GetUserID(), model.AuthBindTypeAuth, []string{p.Order.Way}, "", "", "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(authBinds) == 0 {
|
||||
return fmt.Errorf("未绑定微信认证方式!")
|
||||
}
|
||||
param.OpenID = authBinds[0].AuthID
|
||||
result, err2 := payMap[p.Order.Way].CreateUnifiedOrder(param)
|
||||
if err2 == nil {
|
||||
param2 := make(map[string]interface{})
|
||||
param2["prepayid"] = result.PrepayID
|
||||
param2["noncestr"] = utils.GetUUID()
|
||||
param2["timestamp"] = time.Now().Unix()
|
||||
param2["package"] = "Sign=WXPay"
|
||||
param2["partnerid"] = result.MchID
|
||||
param2["appid"] = result.AppID
|
||||
sign := signParam(sigTypeMd5, param2)
|
||||
wxPay := &WxPayParam{
|
||||
Prepayid: param2["prepayid"].(string),
|
||||
Noncestr: param2["noncestr"].(string),
|
||||
Timestamp: utils.Int64ToStr(utils.MustInterface2Int64(param2["timestamp"])),
|
||||
Package: param2["package"].(string),
|
||||
Partnerid: param2["partnerid"].(string),
|
||||
Appid: param2["appid"].(string),
|
||||
Sign: sign,
|
||||
}
|
||||
p.WxPayParam = wxPay
|
||||
p.Order.PrepayID = result.PrepayID
|
||||
p.Order.Comment = result.CodeURL
|
||||
_, err = dao.UpdateEntityTx(txDB, p.Order, "PrepayID", "Comment")
|
||||
} else {
|
||||
return err2
|
||||
}
|
||||
default:
|
||||
err = fmt.Errorf("支付方式:%d当前不支持", p.PayType)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func SendFilesToStores(ctx *jxcontext.Context, files []*multipart.FileHeader, title, shopName string, isAsync bool, userName string) (hint string, err error) {
|
||||
globals.SugarLogger.Debugf("SendFilesToStores, fileCount:%d isAsync:%t, userName:%s", len(files), isAsync, userName)
|
||||
if len(files) == 0 {
|
||||
return "", errors.New("没有文件上传!")
|
||||
func signParam(signType string, params map[string]interface{}) (sig string) {
|
||||
var valueList []string
|
||||
for k, v := range params {
|
||||
if k != sigKey {
|
||||
if str := fmt.Sprint(v); str != "" {
|
||||
valueList = append(valueList, fmt.Sprintf("%s=%s", k, str))
|
||||
}
|
||||
}
|
||||
}
|
||||
sort.Sort(sort.StringSlice(valueList))
|
||||
valueList = append(valueList, fmt.Sprintf("key=%s", globals.WxpayAppKey))
|
||||
sig = strings.Join(valueList, "&")
|
||||
var binSig []byte
|
||||
if signType == sigTypeSha256 {
|
||||
mac := hmac.New(sha256.New, []byte(globals.WxpayAppKey))
|
||||
mac.Write([]byte(sig))
|
||||
binSig = mac.Sum(nil)
|
||||
} else {
|
||||
binSig2 := md5.Sum([]byte(sig))
|
||||
binSig = binSig2[:]
|
||||
}
|
||||
sig = fmt.Sprintf("%X", binSig)
|
||||
// baseapi.SugarLogger.Debug(sig)
|
||||
return sig
|
||||
}
|
||||
|
||||
fileList := make([]*tUploadFileInfo, len(files))
|
||||
for k, fileHeader := range files {
|
||||
fileList[k] = &tUploadFileInfo{
|
||||
FileHeader: fileHeader,
|
||||
}
|
||||
fileNameParts := strings.Split(fileHeader.Filename, "_")
|
||||
if len(fileNameParts) < 3 {
|
||||
return "", fmt.Errorf("文件名:%s不规范,没有包含三个必要的部分", fileHeader.Filename)
|
||||
}
|
||||
fileList[k].StoreID = int(utils.Str2Int64WithDefault(fileNameParts[0], 0))
|
||||
if fileList[k].StoreID < 100000 || fileList[k].StoreID > 1000000 {
|
||||
return "", fmt.Errorf("文件名:%s不规范,不以合法的京西门店ID开始", fileHeader.Filename)
|
||||
}
|
||||
}
|
||||
putPolicy := storage.PutPolicy{
|
||||
Scope: globals.QiniuBucket,
|
||||
Expires: 10 * 60,
|
||||
}
|
||||
upToken := putPolicy.UploadToken(api.QiniuAPI)
|
||||
cfg := &storage.Config{}
|
||||
task := tasksch.NewParallelTask("SendFilesToStores", tasksch.NewParallelConfig().SetIsContinueWhenError(true), ctx,
|
||||
func(t *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
fileInfo := batchItemList[0].(*tUploadFileInfo)
|
||||
fileHeader := fileInfo.FileHeader
|
||||
db := dao.GetDB()
|
||||
storeID, _ := dao.GetRealLinkStoreID(db, fileInfo.StoreID)
|
||||
file, err := fileHeader.Open()
|
||||
globals.SugarLogger.Debugf("SendFilesToStores upload file:%s", fileHeader.Filename)
|
||||
if err == nil {
|
||||
ret := storage.PutRet{}
|
||||
key := "storeBill/" + utils.Int2Str(storeID) + "_" + strings.ToLower(utils.GetUUID()) + path.Ext(fileHeader.Filename)
|
||||
formUploader := storage.NewFormUploader(cfg)
|
||||
for i := 0; i < 3; i++ {
|
||||
if err = formUploader.Put(context.Background(), &ret, upToken, key, file, fileHeader.Size, &storage.PutExtra{}); err == nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
file.Close()
|
||||
if err == nil {
|
||||
billRec := &legacymodel.StoreBill{
|
||||
Date: time.Now(),
|
||||
Url: strings.Replace(jxutils.ComposeQiniuResURL(ret.Key), "http://", "https://", -1),
|
||||
StoreId: storeID,
|
||||
BillName: fileHeader.Filename,
|
||||
ShopName: shopName,
|
||||
BillTitle: title,
|
||||
}
|
||||
if err = dao.CreateEntity(db, billRec); err == nil {
|
||||
err = weixinmsg.NotifySaleBill(storeID, title, shopName, fmt.Sprintf("%s/billshow/?path=%s", globals.BackstageHost, billRec.Url))
|
||||
if err != nil {
|
||||
globals.SugarLogger.Infof("SendFilesToStores NotifySaleBill file:%s error:%v", fileHeader.Filename, err)
|
||||
}
|
||||
err = nil // 忽略微信发送错误
|
||||
} else {
|
||||
globals.SugarLogger.Warnf("SendFilesToStores CreateEntity file:%s error:%v", fileHeader.Filename, err)
|
||||
}
|
||||
func (p *PayHandler) CreateRefund() (err error) {
|
||||
switch p.PayType {
|
||||
case model.PayTypeTL: // 收费贵,不适用
|
||||
case model.PayTypeAliPay: // 支付宝支付
|
||||
|
||||
case model.PayTypeWX: // 需要保持账号每天有交易流水,不适用
|
||||
//企业付款(提现)
|
||||
if p.VendorPayType == model.VendorPayTypeCompanyPay {
|
||||
param := &wxpayapi.TransfersParam{
|
||||
PartnerTradeNo: p.Order.OrderID,
|
||||
CheckName: wxpayapi.CheckName,
|
||||
Desc: "冲天猴儿app提现到账",
|
||||
SpbillCreateIP: p.Ctx.GetRealRemoteIP(),
|
||||
}
|
||||
//1元以下免费,以上收取对应城市手续费
|
||||
place, err := dao.GetPlaceByCode(dao.GetDB(), p.Order.CityCode)
|
||||
if err != nil || place == nil {
|
||||
return fmt.Errorf("未找到该城市!code:%v", p.Order.CityCode)
|
||||
}
|
||||
if p.Order.PayPrice < 100 {
|
||||
param.Amount = p.Order.PayPrice
|
||||
} else {
|
||||
param.Amount = p.Order.PayPrice * place.DividePercentage / 100 //手续费
|
||||
}
|
||||
if authInfo, err := p.Ctx.GetV2AuthInfo(); err == nil {
|
||||
param.OpenID = authInfo.GetAuthID()
|
||||
}
|
||||
globals.SugarLogger.Debugf("CreateRefund wx param: %v", utils.Format4Output(param, false))
|
||||
result, err2 := payMap[p.Order.Way].Transfers(param)
|
||||
if err2 == nil {
|
||||
p.Order.PayFinishedAt = utils.Str2Time(result.PaymentTime)
|
||||
p.Order.Comment = result.DeviceInfo
|
||||
p.Order.OriginalData = utils.Format4Output(result, true)
|
||||
if result.ReturnMsg == "" {
|
||||
p.Order.Status = model.OrderStatusFinished
|
||||
} else {
|
||||
globals.SugarLogger.Warnf("SendFilesToStores file:%s failed with error:%v", fileHeader.Filename, err)
|
||||
p.Order.Status = model.OrderStatusCanceled
|
||||
}
|
||||
dao.UpdateEntity(dao.GetDB(), p.Order)
|
||||
if result.ReturnMsg == "" {
|
||||
err = OnCashFinished(p.Order)
|
||||
}
|
||||
} else {
|
||||
globals.SugarLogger.Warnf("SendFilesToStores open file:%s failed with error:%v", fileHeader.Filename, err)
|
||||
return err2
|
||||
}
|
||||
return retVal, err
|
||||
}, fileList)
|
||||
tasksch.HandleTask(task, nil, true).Run()
|
||||
hint = task.ID
|
||||
if !isAsync {
|
||||
_, err = task.GetResult(0)
|
||||
err = OnCashFinished(p.Order)
|
||||
} else if p.VendorPayType == model.VendorPayTypeTransferAccount {
|
||||
p.Order.PayFinishedAt = time.Now()
|
||||
p.Order.Comment = "手动转账"
|
||||
p.Order.Status = model.OrderStatusFinished
|
||||
if _, err := dao.UpdateEntity(dao.GetDB(), p.Order); err == nil {
|
||||
err = OnCashFinished(p.Order)
|
||||
}
|
||||
}
|
||||
}
|
||||
return task.ID, err
|
||||
return err
|
||||
}
|
||||
|
||||
func GetStoreBills(ctx *jxcontext.Context, storeID int) (bills []*legacymodel.StoreBill, err error) {
|
||||
db := dao.GetDB()
|
||||
if err = dao.GetRows(db, &bills, `
|
||||
SELECT *
|
||||
FROM store_bill
|
||||
WHERE store_id = ?
|
||||
ORDER BY date DESC
|
||||
LIMIT 10
|
||||
`, storeID); err != nil {
|
||||
return nil, err
|
||||
func OnTLPayCallback(call *tonglianpayapi.CallBackResult) (err error) {
|
||||
globals.SugarLogger.Debugf("OnTLPayCallback msg:%s", utils.Format4Output(call, true))
|
||||
switch call.TrxCode {
|
||||
case tonglianpayapi.MsgTypePay:
|
||||
err = onTLpayFinished(call)
|
||||
case tonglianpayapi.MsgTypeRefund:
|
||||
err = onTLpayRefund(call)
|
||||
}
|
||||
return bills, err
|
||||
return err
|
||||
}
|
||||
|
||||
func onTLpayFinished(call *tonglianpayapi.CallBackResult) (err error) {
|
||||
order := &model.Order{
|
||||
OrderID: call.CusorderID,
|
||||
TransactionID: call.TrxID,
|
||||
}
|
||||
db := dao.GetDB()
|
||||
if err = dao.GetEntity(db, order, "OrderID"); err == nil {
|
||||
if order.Status != model.OrderStatusWait4Pay {
|
||||
globals.SugarLogger.Debugf("already pay msg:%s, err:%v", utils.Format4Output(call, true), err)
|
||||
return err
|
||||
}
|
||||
loc, _ := time.LoadLocation("Local")
|
||||
t1, _ := time.ParseInLocation("20060102150405", call.PayTime, loc)
|
||||
order.PayFinishedAt = t1
|
||||
order.OriginalData = utils.Format4Output(call, true)
|
||||
payStatus := model.PayStatusNo
|
||||
//order.PayMethod = 2 // 通联微信支付
|
||||
if call.TrxStatus == tonglianpayapi.TrxStatusSuccess {
|
||||
order.Status = model.OrderStatusFinished
|
||||
payStatus = model.OrderStatusSuccessPay
|
||||
} else {
|
||||
order.Status = model.OrderStatusCanceled
|
||||
payStatus = model.OrderStatusFailPay
|
||||
}
|
||||
|
||||
//充值会员 增加微信支付处理业务
|
||||
if (order.OrderType == model.OrderTypeMember || order.OrderType == model.OrderTypeMemberYear) && call.TrxStatus == tonglianpayapi.TrxStatusSuccess {
|
||||
return OnWXPayFinished(order)
|
||||
}
|
||||
// 充值话费
|
||||
if order.OrderType == model.OrderTypeMobile && call.TrxStatus == tonglianpayapi.TrxStatusSuccess {
|
||||
return OnWxPayTelephone(order)
|
||||
}
|
||||
// 发快递
|
||||
if order.OrderType == model.OrderTypeDelivery && call.TrxStatus == tonglianpayapi.TrxStatusSuccess {
|
||||
return OnWxPaySendPage(db, order, call, payStatus)
|
||||
}
|
||||
//需要充值到余额方式 购买的
|
||||
if order.OrderType == model.OrderTypeBalance && call.TrxStatus == tonglianpayapi.TrxStatusSuccess {
|
||||
if err := dao.UpdateUserBill(order.UserID, order.PayPrice); err != nil {
|
||||
return err
|
||||
}
|
||||
order.Status = 110
|
||||
if _, err := dao.UpdateEntity(db, order, "Status"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
globals.SugarLogger.Debugf("onTLpayFinished msg:%s, err:%v", utils.Format4Output(call, true), err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func onTLpayRefund(call *tonglianpayapi.CallBackResult) (err error) {
|
||||
orderPayRefund := &model.OrderPayRefund{
|
||||
RefundID: call.CusorderID,
|
||||
}
|
||||
db := dao.GetDB()
|
||||
if err = dao.GetEntity(db, orderPayRefund, "RefundID"); err == nil {
|
||||
if call.TrxStatus == tonglianpayapi.TrxStatusSuccess {
|
||||
orderPayRefund.Status = model.RefundStatusYes
|
||||
} else {
|
||||
orderPayRefund.Status = model.RefundStatusFailed
|
||||
}
|
||||
orderPayRefund.OriginalData = utils.Format4Output(call, true)
|
||||
dao.UpdateEntity(db, orderPayRefund)
|
||||
} else if dao.IsNoRowsError(err) {
|
||||
globals.SugarLogger.Warnf("收到异常的退款事件, call:%s", utils.Format4Output(call, true))
|
||||
}
|
||||
|
||||
orderPay := &model.Order{
|
||||
OrderID: orderPayRefund.VendorOrderID,
|
||||
}
|
||||
if err = dao.GetEntity(db, orderPay, "VendorOrderID"); err == nil {
|
||||
orderPay.Status = model.OrderStatusCancel
|
||||
}
|
||||
if orderPay.OrderType == model.PayType4Express {
|
||||
tx, _ := dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
dao.Rollback(db, tx)
|
||||
panic(r)
|
||||
}
|
||||
}()
|
||||
|
||||
if _, err = dao.UpdateEntityTx(tx, orderPay); err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
if _, err = dao.UpdateEntityTx(tx, &model.UserVendorOrder{LocalWayBill: call.CusorderID, OrderStatus: model.OrderStatusCancel}, "OrderStatus"); err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
tx.Commit()
|
||||
return err
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func OnWxPayCallback(msg *wxpayapi.CallbackMsg) (err error) {
|
||||
globals.SugarLogger.Debugf("OnWxPayCallback msg:%s", utils.Format4Output(msg, true))
|
||||
switch msg.MsgType {
|
||||
case wxpayapi.MsgTypePay:
|
||||
err = onWxpayFinished(msg.Data.(*wxpayapi.PayResultMsg))
|
||||
case wxpayapi.MsgTypeRefund:
|
||||
// err = onWxpayRefund(msg.Data.(*wxpayapi.RefundResultMsg))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func onWxpayFinished(msg *wxpayapi.PayResultMsg) (err error) {
|
||||
order := &model.Order{
|
||||
OrderID: msg.OutTradeNo,
|
||||
}
|
||||
db := dao.GetDB()
|
||||
if err = dao.GetEntity(db, order, "OrderID"); err == nil {
|
||||
order.PayFinishedAt = wxpayapi.PayTime2Time(msg.TimeEnd)
|
||||
order.TransactionID = msg.TransactionID
|
||||
order.OriginalData = utils.Format4Output(msg, true)
|
||||
if msg.ResultCode == wxpayapi.ResponseCodeSuccess {
|
||||
order.Status = model.OrderStatusFinished
|
||||
} else {
|
||||
order.Status = model.OrderStatusCanceled
|
||||
}
|
||||
dao.UpdateEntity(db, order)
|
||||
if msg.ResultCode == wxpayapi.ResponseCodeSuccess {
|
||||
err = OnPayFinished(order)
|
||||
}
|
||||
} else {
|
||||
globals.SugarLogger.Debugf("onWxpayFinished msg:%s, err:%v", utils.Format4Output(msg, true), err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// func onWxpayRefund(msg *wxpayapi.RefundResultMsg) (err error) {
|
||||
// orderPayRefund := &model.OrderPayRefund{
|
||||
// RefundID: msg.ReqInfoObj.OutRefundNo,
|
||||
// }
|
||||
// db := dao.GetDB()
|
||||
// if err = dao.GetEntity(db, orderPayRefund, "RefundID"); err == nil {
|
||||
// if msg.ResultCode == wxpayapi.ResponseCodeSuccess {
|
||||
// orderPayRefund.Status = model.RefundStatusYes
|
||||
// } else {
|
||||
// orderPayRefund.Status = model.RefundStatusFailed
|
||||
// }
|
||||
// orderPayRefund.OriginalData = utils.Format4Output(msg, true)
|
||||
// dao.UpdateEntity(db, orderPayRefund)
|
||||
// } else if dao.IsNoRowsError(err) {
|
||||
// globals.SugarLogger.Warnf("收到异常的退款事件, msg:%s", utils.Format4Output(msg, true))
|
||||
// }
|
||||
|
||||
// orderPay := &model.OrderPay{
|
||||
// VendorOrderID: orderPayRefund.VendorOrderID,
|
||||
// VendorID: jxutils.GetPossibleVendorIDFromVendorOrderID(orderPayRefund.VendorOrderID),
|
||||
// PayType: model.PayTypeWX,
|
||||
// Status: model.PayStatusYes,
|
||||
// }
|
||||
// orderPay.DeletedAt = utils.DefaultTimeValue
|
||||
// if err = dao.GetEntity(db, orderPay, "VendorOrderID", "VendorID", "PayType", "Status", "DeletedAt"); err == nil {
|
||||
// orderPay.Status = model.PayStatusRefund
|
||||
// dao.UpdateEntity(db, orderPay)
|
||||
// }
|
||||
// return err
|
||||
// }
|
||||
|
||||
224
business/jxstore/financial/pay.go
Normal file
224
business/jxstore/financial/pay.go
Normal 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
|
||||
}
|
||||
@@ -6,10 +6,8 @@ import (
|
||||
"git.rosy.net.cn/baseapi/platformapi/autonavi"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
)
|
||||
|
||||
@@ -50,10 +48,10 @@ func InitPlace(ctx *jxcontext.Context) (err error) {
|
||||
}
|
||||
placeList = placeList[0].Districts
|
||||
db := dao.GetDB()
|
||||
dao.Begin(db)
|
||||
txDB, _ := dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil || err != nil {
|
||||
dao.Rollback(db)
|
||||
dao.Rollback(db, txDB)
|
||||
if r != nil {
|
||||
panic(r)
|
||||
}
|
||||
@@ -69,124 +67,10 @@ func InitPlace(ctx *jxcontext.Context) (err error) {
|
||||
if err = insertPlace(ctx, db, nil, placeList); err != nil {
|
||||
return err
|
||||
}
|
||||
updateSqls := []string{
|
||||
`
|
||||
UPDATE place t1
|
||||
JOIN jde_city t2 ON t1.code = t2.col_tencentAddressCode
|
||||
SET t1.jd_code = t2.col_areaCode;
|
||||
`,
|
||||
`
|
||||
UPDATE place t1
|
||||
JOIN place t2 ON t1.parent_code = t2.code AND t2.jd_code != 0
|
||||
JOIN jde_district t3 ON t1.name = t3.col_areaName AND t2.jd_code = t3.col_cityCode
|
||||
SET t1.jd_code = t3.col_areaCode
|
||||
WHERE t1.level = 3;
|
||||
`,
|
||||
`
|
||||
UPDATE
|
||||
place t1
|
||||
JOIN ebde_places t2 ON t1.name = t2.col_city_name
|
||||
SET t1.ebai_code = t2.col_city_id
|
||||
WHERE t1.level = 1 OR t1.level = 2;
|
||||
`,
|
||||
`
|
||||
UPDATE
|
||||
place t1
|
||||
JOIN place t1p ON t1.parent_code = t1p.code
|
||||
JOIN ebde_places t2 ON t1.name = t2.col_city_name
|
||||
JOIN ebde_places t2p ON t2.col_parent_id = t2p.col_city_id AND t1p.ebai_code = t2p.col_city_id
|
||||
SET t1.ebai_code = t2.col_city_id
|
||||
WHERE t1.level = 3;
|
||||
`,
|
||||
`
|
||||
UPDATE
|
||||
place t1
|
||||
JOIN mtpsdeliveryprice t2 ON t1.code = t2.citycode
|
||||
SET t1.mtps_price = t2.price;
|
||||
`,
|
||||
`
|
||||
UPDATE
|
||||
place t1
|
||||
JOIN mtpsdeliveryprice t2 ON t1.name LIKE CONCAT(t2.cityname, '%')
|
||||
SET t1.mtps_price = t2.price
|
||||
WHERE t1.level = 2 AND t1.mtps_price = 0;
|
||||
`,
|
||||
`
|
||||
UPDATE place t1
|
||||
LEFT JOIN (
|
||||
SELECT DISTINCT city_code
|
||||
FROM store
|
||||
UNION DISTINCT
|
||||
SELECT DISTINCT place_code city_code
|
||||
FROM sku_name_place_bind
|
||||
) t2 ON t1.code = t2.city_code
|
||||
SET t1.enabled = 0
|
||||
WHERE t1.level = 2 AND t2.city_code IS NULL;
|
||||
`,
|
||||
}
|
||||
for _, v := range updateSqls {
|
||||
if _, err = dao.ExecuteSQL(db, v); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
dao.Commit(db)
|
||||
dao.Commit(db, txDB)
|
||||
return err
|
||||
}
|
||||
|
||||
func InitVendorCategory(ctx *jxcontext.Context, vendorID int, isAsync bool) (hint string, err error) {
|
||||
if handler := partner.GetPurchasePlatformFromVendorID(vendorID); handler != nil {
|
||||
var cats []*model.SkuVendorCategory
|
||||
rootTask := tasksch.NewSeqTask(fmt.Sprintf("创建%s的平台分类", model.VendorChineseNames[vendorID]), ctx,
|
||||
func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
|
||||
switch step {
|
||||
case 0:
|
||||
cats, err = handler.GetVendorCategories(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case 1:
|
||||
db := dao.GetDB()
|
||||
dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil || err != nil {
|
||||
dao.Rollback(db)
|
||||
if r != nil {
|
||||
panic(r)
|
||||
}
|
||||
}
|
||||
}()
|
||||
sql := `
|
||||
DELETE
|
||||
FROM sku_vendor_category
|
||||
WHERE vendor_id = ?
|
||||
`
|
||||
if _, err = dao.ExecuteSQL(db, sql, vendorID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, cat := range cats {
|
||||
dao.WrapAddIDCULEntity(cat, ctx.GetUserName())
|
||||
}
|
||||
if err = dao.CreateMultiEntities(db, cats); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dao.Commit(db)
|
||||
}
|
||||
return nil, err
|
||||
}, 2)
|
||||
tasksch.HandleTask(rootTask, nil, true).Run()
|
||||
if !isAsync {
|
||||
if _, err = rootTask.GetResult(0); err == nil {
|
||||
hint = utils.Int2Str(len(cats))
|
||||
}
|
||||
} else {
|
||||
hint = rootTask.ID
|
||||
}
|
||||
} else {
|
||||
err = fmt.Errorf("找不到平台:%d", vendorID)
|
||||
}
|
||||
return hint, err
|
||||
}
|
||||
|
||||
func UploadImg4Vendors(ctx *jxcontext.Context, isAsync, isContinueWhenError bool) (hint string, err error) {
|
||||
// db := dao.GetDB()
|
||||
// rootTask := tasksch.NewSeqTask("合并SkuName图片至DataResource", ctx,
|
||||
|
||||
@@ -1,531 +1,76 @@
|
||||
package misc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
"git.rosy.net.cn/jx-callback/business/jxstore/partner/pdd"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
bidaServer "git.rosy.net.cn/jx-callback/business/q_bida"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/partner/purchase/jdshop"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/jdapi"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/partner/purchase/jx/localjx"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/jxstore/event"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/jxstore/report"
|
||||
"git.rosy.net.cn/jx-callback/business/jxstore/cms"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/baseapi/utils/errlist"
|
||||
"git.rosy.net.cn/jx-callback/business/jxcallback/orderman"
|
||||
"git.rosy.net.cn/jx-callback/business/jxcallback/scheduler/defsch"
|
||||
"git.rosy.net.cn/jx-callback/business/jxstore/act"
|
||||
"git.rosy.net.cn/jx-callback/business/jxstore/cms"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/netprinter"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/netspider"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"github.com/astaxie/beego"
|
||||
)
|
||||
|
||||
const (
|
||||
SpecialTaskID = "Running"
|
||||
TaskNameSyncStoreSku = "SyncStoreSku"
|
||||
)
|
||||
|
||||
var (
|
||||
dailyHeartbeat = []string{
|
||||
"09:00:00",
|
||||
}
|
||||
dailyWorkTimeList = []string{
|
||||
"20:30:00",
|
||||
"00:18:35",
|
||||
}
|
||||
dailyWorkTimeList2 = []string{
|
||||
"02:00:00",
|
||||
stationTimeList = []string{
|
||||
"11:35:00",
|
||||
}
|
||||
priceReferTimeList = []string{
|
||||
"03:00:00",
|
||||
}
|
||||
checkCookieList = []string{
|
||||
"08:00:00",
|
||||
"12:00:00",
|
||||
"18:00:00",
|
||||
}
|
||||
createStorePriceTimeList = []string{
|
||||
startDeleteTime = []string{
|
||||
"04:00:00",
|
||||
}
|
||||
refreshPageActTimeList = []string{
|
||||
"7:00:00",
|
||||
"8:00:00",
|
||||
"9:00:00",
|
||||
"10:00:00",
|
||||
"11:00:00",
|
||||
"12:00:00",
|
||||
"13:00:00",
|
||||
"14:00:00",
|
||||
"15:00:00",
|
||||
"16:00:00",
|
||||
"17:00:00",
|
||||
"18:00:00",
|
||||
"19:00:00",
|
||||
"22:00:00",
|
||||
}
|
||||
ChangeStoreSkuSaleStatusList = []string{
|
||||
"7:00:00",
|
||||
"8:00:00",
|
||||
"9:00:00",
|
||||
"10:00:00",
|
||||
"11:00:00",
|
||||
"12:00:00",
|
||||
"13:00:00",
|
||||
"14:00:00",
|
||||
"15:00:00",
|
||||
"16:00:00",
|
||||
"17:00:00",
|
||||
"18:00:00",
|
||||
"19:00:00",
|
||||
"20:00:00",
|
||||
}
|
||||
openRemoteStoreTimeList = []string{
|
||||
"04:30:00",
|
||||
"23:30:00",
|
||||
}
|
||||
updateActStatusTimeList = []string{
|
||||
"00:01:00",
|
||||
}
|
||||
sendSecKillWarnList = []string{
|
||||
"9:00:00",
|
||||
}
|
||||
autoPayForPopluarManList = []string{
|
||||
"10:30:00",
|
||||
}
|
||||
|
||||
autoSaleStoreSkuTimeList = []string{
|
||||
cms.AutoSaleAtStr,
|
||||
}
|
||||
|
||||
backUpStoreSkuBindList = []string{
|
||||
"23:30:00",
|
||||
}
|
||||
|
||||
exSyncList = []string{
|
||||
"11:30:00",
|
||||
}
|
||||
|
||||
importantTaskMap = &sync.Map{}
|
||||
|
||||
cancelPayTimeOutOrderList = localjx.GetHalfHoursList()
|
||||
discountActJxList = localjx.GetDiscountActHoursList()
|
||||
|
||||
ebaiStorePageCookieExdTOKEN string
|
||||
ebaiStorePageCookieWMUSS2 string
|
||||
ebaiStorePageCookieWMSTOKEN2 string
|
||||
ebaiStorePageCookieWMUSS string
|
||||
ebaiStorePageCookieWMSTOKEN string
|
||||
mtwmCookieStr string
|
||||
mtpsStoreToken string
|
||||
jd2StorePageCookie string
|
||||
JdStorePageCookie string
|
||||
yinbaoCookie string
|
||||
feiePageCookie string
|
||||
jdStorePageEarning string
|
||||
jdsCookie string
|
||||
)
|
||||
|
||||
func GetImportantTaskID(taskName string) string {
|
||||
if value, ok := importantTaskMap.Load(taskName); ok {
|
||||
return value.(string)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func SaveImportantTaskID(taskName, taskID string) {
|
||||
importantTaskMap.Store(taskName, taskID)
|
||||
}
|
||||
|
||||
func IsImportantTaskRunning(taskName string) bool {
|
||||
taskID := GetImportantTaskID(taskName)
|
||||
if taskID == "" {
|
||||
return false
|
||||
} else if taskID == SpecialTaskID {
|
||||
return true
|
||||
}
|
||||
return tasksch.IsTaskRunning(taskID)
|
||||
}
|
||||
|
||||
func Init() {
|
||||
if globals.IsProductEnv() {
|
||||
if globals.IsMainProductEnv() {
|
||||
|
||||
//拼多多订单轮询
|
||||
ScheduleTimerFuncByInterval(func() {
|
||||
pdd.GetUnionOrders()
|
||||
}, 5*time.Second, 5*time.Minute)
|
||||
|
||||
ScheduleTimerFunc("doDailyWork", doDailyWork, dailyWorkTimeList)
|
||||
|
||||
ScheduleTimerFunc("doDailyWork2", doDailyWork2, dailyWorkTimeList2)
|
||||
ScheduleTimerFunc("InitStation", func() {
|
||||
//同步油站信息
|
||||
cms.InitStation(jxcontext.AdminCtx)
|
||||
}, stationTimeList)
|
||||
|
||||
// ScheduleTimerFuncByInterval(func() {
|
||||
// orderman.SaveJdsOrders(jxcontext.AdminCtx, time.Now().Add(-20*time.Minute), time.Now())
|
||||
// }, 10*time.Second, 10*time.Minute)
|
||||
// 定时删除打印信息
|
||||
ScheduleTimerFunc("DeleteTimeOutPrintMsg", func() {
|
||||
dao.DeletePrintMsg()
|
||||
}, stationTimeList)
|
||||
|
||||
//京东的订单信息解密密钥获取
|
||||
// 每两小时更新一下订单信息UpdateOrderStatus
|
||||
ScheduleTimerFuncByInterval(func() {
|
||||
jdshop.InitKey()
|
||||
}, 10*time.Second, 8*time.Hour)
|
||||
|
||||
ScheduleTimerFuncByInterval(func() {
|
||||
RefreshRealMobile(jxcontext.AdminCtx, model.VendorIDEBAI, time.Now().Add(-24*time.Hour), utils.DefaultTimeValue, false, true)
|
||||
}, 5*time.Second, 1*time.Hour)
|
||||
|
||||
ScheduleTimerFuncByInterval(func() {
|
||||
defsch.FixedScheduler.ConfirmSelfTakeOrders(jxcontext.AdminCtx, []int{model.VendorIDJD}, time.Now().Add(-48*time.Hour), time.Now().Add(-30*time.Minute), true, true)
|
||||
}, 5*time.Second, 10*time.Minute)
|
||||
|
||||
ScheduleTimerFunc("auto enable remote store", func() {
|
||||
cms.EnableHaveRestStores(jxcontext.AdminCtx, false, true)
|
||||
cms.OpenRemoteStoreByJxStatus(jxcontext.AdminCtx, nil, nil, false, false, true)
|
||||
}, openRemoteStoreTimeList)
|
||||
|
||||
ScheduleTimerFunc("SaveAndSendAlarmVendorSnapshot", func() {
|
||||
cms.SaveAndSendAlarmVendorSnapshot(jxcontext.AdminCtx, nil, nil, false)
|
||||
}, cms.WatchVendorStoreTimeList)
|
||||
|
||||
ScheduleTimerFunc("RefreshPageActs", func() {
|
||||
act.RefreshPageActs(jxcontext.AdminCtx, []int{model.VendorIDEBAI}, time.Now().Add(-30*24*time.Hour), false)
|
||||
}, refreshPageActTimeList)
|
||||
ScheduleTimerFunc("UpdateActStatusByTime", func() {
|
||||
dao.UpdateActStatusByTime(dao.GetDB(), time.Now())
|
||||
}, updateActStatusTimeList)
|
||||
ScheduleScoreStore()
|
||||
ScheduleCheckStoreAlert()
|
||||
ScheduleTimerFunc("ChangeStoreSkuSaleStatus", func() {
|
||||
cms.CurVendorSync.ChangeStoreSkuSaleStatus(jxcontext.AdminCtx, 0, true, true)
|
||||
}, ChangeStoreSkuSaleStatusList)
|
||||
ScheduleTimerFunc("BeginSavePriceRefer", func() {
|
||||
report.BeginSavePriceRefer(jxcontext.AdminCtx, nil, nil, true, true)
|
||||
}, priceReferTimeList)
|
||||
ScheduleTimerFunc("CreateStorePriceScore", func() {
|
||||
cms.CreateStorePriceScore(jxcontext.AdminCtx)
|
||||
}, createStorePriceTimeList)
|
||||
ScheduleTimerFunc("AutoFocusStoreSkusForTopSkus", func() {
|
||||
cms.AutoFocusStoreSkusForTopSkus(jxcontext.AdminCtx, true, true)
|
||||
}, createStorePriceTimeList)
|
||||
ScheduleTimerFunc("GetCheckVendorCookie", func() {
|
||||
event.GetCheckVendorCookie(jxcontext.AdminCtx, []int{model.VendorIDEBAI, model.VendorIDJD, model.VendorIDMTWM, model.VendorIDMTPS, model.VendorIDJDShop}, true)
|
||||
}, checkCookieList)
|
||||
ScheduleTimerFunc("SendSeckillSkusCountMsg", func() {
|
||||
cms.SendSeckillSkusCountMsg(jxcontext.AdminCtx, []int{model.VendorIDEBAI, model.VendorIDJD, model.VendorIDMTWM}, false, true)
|
||||
}, sendSecKillWarnList)
|
||||
ScheduleTimerFunc("每日报警心跳", func() {
|
||||
globals.SugarLogger.Warnf("每日报警心跳,这不是报警。启动时间:%s", cms.GetServiceInfo(jxcontext.AdminCtx)["startupTime"])
|
||||
}, dailyHeartbeat)
|
||||
ScheduleTimerFunc("AutoPayForPopluarMan", func() {
|
||||
localjx.AutoPayForPopluarMan(jxcontext.AdminCtx)
|
||||
}, autoPayForPopluarManList)
|
||||
ScheduleTimerFunc("CancelPayTimeOutOrder", func() {
|
||||
localjx.CancelPayTimeOutOrder(jxcontext.AdminCtx)
|
||||
}, cancelPayTimeOutOrderList)
|
||||
ScheduleTimerFunc("BackUpStoreSkuBind", func() {
|
||||
cms.BackUpStoreSkuBind(jxcontext.AdminCtx, true, true)
|
||||
}, backUpStoreSkuBindList)
|
||||
ScheduleTimerFunc("SendNoCatSkusToOperater", func() {
|
||||
cms.SendNoCatSkusToOperater(jxcontext.AdminCtx)
|
||||
}, autoPayForPopluarManList)
|
||||
ScheduleTimerFunc("CleanStoreIsBoughtMatter", func() {
|
||||
cms.CleanStoreIsBoughtMatter(jxcontext.AdminCtx)
|
||||
}, priceReferTimeList)
|
||||
ScheduleTimerFunc("CleanUserOrderSMSMark", func() {
|
||||
cms.CleanUserOrderSMSMark(jxcontext.AdminCtx)
|
||||
}, priceReferTimeList)
|
||||
ScheduleTimerFunc("exSync", func() {
|
||||
var (
|
||||
db = dao.GetDB()
|
||||
storeList []int
|
||||
exSyncStoreIDList string
|
||||
syncFlag = 0
|
||||
)
|
||||
syncFlag = model.SyncFlagPriceMask
|
||||
if (time.Now().Unix()/24*3600)%10 == 0 {
|
||||
syncFlag |= model.SyncFlagSaleMask
|
||||
}
|
||||
if configs, err := dao.QueryConfigs(dao.GetDB(), "exSyncStoreIDList", model.ConfigTypeSys, ""); err == nil {
|
||||
exSyncStoreIDList = configs[0].Value
|
||||
}
|
||||
storeIDList := strings.Split(exSyncStoreIDList, ",")
|
||||
for _, v := range storeIDList {
|
||||
storeList = append(storeList, int(utils.Str2Int64(v)))
|
||||
}
|
||||
cms.CurVendorSync.SyncStoresSkus2(jxcontext.AdminCtx, nil, 0, db, partner.GetMultiStoreVendorIDs(), storeList, false, nil, []int{27379}, syncFlag, true, true)
|
||||
}, exSyncList)
|
||||
ScheduleTimerFunc("CreateOrderByPriceDefend", func() {
|
||||
localjx.CreateOrderByPriceDefend(jxcontext.AdminCtx)
|
||||
}, []string{
|
||||
"22:00:00",
|
||||
})
|
||||
ScheduleTimerFunc("ChangeJxPriceByDiscountAct", func() {
|
||||
act.ChangeJxPriceByDiscountAct(jxcontext.AdminCtx)
|
||||
}, discountActJxList)
|
||||
ScheduleTimerFunc("RefreshUserMemberStatus", func() {
|
||||
cms.RefreshUserMemberStatus(jxcontext.AdminCtx)
|
||||
}, updateActStatusTimeList)
|
||||
bidaServer.UpdateOrderStatus()
|
||||
}, 5*time.Second, 2*time.Hour)
|
||||
}
|
||||
ScheduleTimerFunc("AutoSaleStoreSku", func() {
|
||||
cms.AutoSaleStoreSku(jxcontext.AdminCtx, nil, false)
|
||||
}, autoSaleStoreSkuTimeList)
|
||||
|
||||
if beego.BConfig.RunMode == "jxgy" {
|
||||
ScheduleTimerFunc("SyncMatterC4ToGy", func() {
|
||||
cms.SyncMatterC4ToGy(jxcontext.AdminCtx, true, true)
|
||||
}, dailyWorkTimeList)
|
||||
}
|
||||
if beego.BConfig.RunMode == "beta" {
|
||||
ScheduleTimerFunc("CancelPayTimeOutOrder", func() {
|
||||
localjx.CancelPayTimeOutOrder(jxcontext.AdminCtx)
|
||||
}, cancelPayTimeOutOrderList)
|
||||
ScheduleTimerFunc("GetAndStoreCitiesShops", func() {
|
||||
netspider.GetAndStoreCitiesShops(jxcontext.AdminCtx, nil, nil, 0, 0, false, false)
|
||||
}, []string{
|
||||
"04:05:06",
|
||||
})
|
||||
//京东的订单信息解密密钥获取
|
||||
ScheduleTimerFuncByInterval(func() {
|
||||
jdshop.InitKey()
|
||||
}, 10*time.Second, 8*time.Hour)
|
||||
ScheduleTimerFunc("ChangeJxPriceByDiscountAct", func() {
|
||||
act.ChangeJxPriceByDiscountAct(jxcontext.AdminCtx)
|
||||
}, discountActJxList)
|
||||
ScheduleTimerFunc("CreateOrderByPriceDefend", func() {
|
||||
localjx.CreateOrderByPriceDefend(jxcontext.AdminCtx)
|
||||
}, []string{
|
||||
"22:00:00",
|
||||
})
|
||||
}
|
||||
if configs, err := dao.QueryConfigs(dao.GetDB(), "ebaiStorePageCookieExdTOKEN", model.ConfigTypeCookie, ""); err == nil {
|
||||
ebaiStorePageCookieExdTOKEN = configs[0].Value
|
||||
}
|
||||
if configs, err := dao.QueryConfigs(dao.GetDB(), "ebaiStorePageCookieWMUSS2", model.ConfigTypeCookie, ""); err == nil {
|
||||
ebaiStorePageCookieWMUSS2 = configs[0].Value
|
||||
}
|
||||
if configs, err := dao.QueryConfigs(dao.GetDB(), "ebaiStorePageCookieWMSTOKEN2", model.ConfigTypeCookie, ""); err == nil {
|
||||
ebaiStorePageCookieWMSTOKEN2 = configs[0].Value
|
||||
}
|
||||
if configs, err := dao.QueryConfigs(dao.GetDB(), "ebaiStorePageCookieWMUSS", model.ConfigTypeCookie, ""); err == nil {
|
||||
ebaiStorePageCookieWMUSS = configs[0].Value
|
||||
}
|
||||
if configs, err := dao.QueryConfigs(dao.GetDB(), "ebaiStorePageCookieWMSTOKEN", model.ConfigTypeCookie, ""); err == nil {
|
||||
ebaiStorePageCookieWMSTOKEN = configs[0].Value
|
||||
}
|
||||
if configs, err := dao.QueryConfigs(dao.GetDB(), "mtwmCookieStr", model.ConfigTypeCookie, ""); err == nil {
|
||||
mtwmCookieStr = configs[0].Value
|
||||
}
|
||||
if configs, err := dao.QueryConfigs(dao.GetDB(), "mtpsStoreToken", model.ConfigTypeCookie, ""); err == nil {
|
||||
mtpsStoreToken = configs[0].Value
|
||||
}
|
||||
if configs, err := dao.QueryConfigs(dao.GetDB(), "jdStorePageCookie", model.ConfigTypeCookie, ""); err == nil {
|
||||
JdStorePageCookie = configs[0].Value
|
||||
}
|
||||
if configs, err := dao.QueryConfigs(dao.GetDB(), "jdStorePageEarning", model.ConfigTypeCookie, ""); err == nil {
|
||||
jdStorePageEarning = configs[0].Value
|
||||
}
|
||||
if configs, err := dao.QueryConfigs(dao.GetDB(), "jd2StorePageCookie", model.ConfigTypeCookie, ""); err == nil {
|
||||
jd2StorePageCookie = configs[0].Value
|
||||
}
|
||||
if configs, err := dao.QueryConfigs(dao.GetDB(), "feiePageCookie", model.ConfigTypeCookie, ""); err == nil {
|
||||
feiePageCookie = configs[0].Value
|
||||
}
|
||||
if configs, err := dao.QueryConfigs(dao.GetDB(), "jdsCookie", model.ConfigTypeCookie, ""); err == nil {
|
||||
jdsCookie = configs[0].Value
|
||||
api.JdShopAPI.SetCookieWithStr(jdsCookie)
|
||||
}
|
||||
if configs, err := dao.QueryConfigs(dao.GetDB(), "yinbaoCookie", model.ConfigTypeCookie, ""); err == nil {
|
||||
yinbaoCookie := configs[0].Value
|
||||
api.YinBaoAPI.SetCookie(".POSPALAUTH30220", yinbaoCookie)
|
||||
}
|
||||
if globals.Jd2OrgCode != "" {
|
||||
api.Jd2API.SetJdCookie(jd2StorePageCookie)
|
||||
}
|
||||
api.EbaiAPI.SetCookie("PASSPORT_DELIMONT_TOKEN", ebaiStorePageCookieExdTOKEN)
|
||||
api.EbaiAPI.SetCookie("WMUSS", ebaiStorePageCookieWMUSS)
|
||||
api.EbaiAPI.SetCookie("WMSTOKEN", ebaiStorePageCookieWMSTOKEN)
|
||||
api.Ebai2API.SetCookie("PASSPORT_DELIMONT_TOKEN", ebaiStorePageCookieExdTOKEN)
|
||||
api.Ebai2API.SetCookie("WMUSS", ebaiStorePageCookieWMUSS2)
|
||||
api.Ebai2API.SetCookie("WMSTOKEN", ebaiStorePageCookieWMSTOKEN2)
|
||||
api.MtwmAPI.SetCookieWithStr(mtwmCookieStr)
|
||||
api.MtpsAPI.SetCookie("token", mtpsStoreToken)
|
||||
api.JdAPI.SetJdCookie(JdStorePageCookie)
|
||||
api.JdAPI.SetCookie("user", jdStorePageEarning)
|
||||
api.JdPageAPI.SetCookie(jdapi.AccessStorePageCookieName, JdStorePageCookie)
|
||||
api.JdPageAPI.SetCookie(jdapi.AccessStorePageCookieName2, JdStorePageCookie)
|
||||
api.FeieAPI.SetCookieWithStr(feiePageCookie)
|
||||
}
|
||||
|
||||
func syncStoreSku() {
|
||||
syncFlag := 0
|
||||
// syncFlag := model.SyncFlagPriceMask
|
||||
// if (time.Now().Unix()/24*3600)%10 == 0 {
|
||||
// syncFlag |= model.SyncFlagSaleMask
|
||||
// }
|
||||
task := tasksch.NewParallelTask("同步京西与平台数据", nil, jxcontext.AdminCtx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
step := batchItemList[0].(int)
|
||||
errList := errlist.New()
|
||||
db := dao.GetDB()
|
||||
switch step {
|
||||
case 0:
|
||||
errList.AddErr(cms.DeleteSkuNameExPrefixOverdue(db))
|
||||
errList.AddErr(cms.SetMultiStoreSkuSyncModifyStatus(db, partner.GetMultiStoreVendorIDs()))
|
||||
|
||||
_, err = cms.CurVendorSync.LoopMultiStoresVendors(jxcontext.AdminCtx, db, "同步多门店平台商品库", false, true,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
vendorInfo := batchItemList[0].(*cms.MultiStoreVendorInfo)
|
||||
_, err = cms.FullSyncVendorStuff(jxcontext.AdminCtx, task, vendorInfo.VendorID, vendorInfo.OrgCode, false, true)
|
||||
return retVal, err
|
||||
})
|
||||
errList.AddErr(err)
|
||||
|
||||
_, err = cms.CurVendorSync.SyncStoresSkus2(jxcontext.AdminCtx, nil, 0, db, []int{0}, nil, false, nil, []int{27379}, syncFlag, true, true)
|
||||
// _, err = cms.CurVendorSync.FullSyncStoresSkus(jxcontext.AdminCtx, db, partner.GetMultiStoreVendorIDs(), nil, false, []int{27379}, true, true)
|
||||
errList.AddErr(err)
|
||||
case 1:
|
||||
//TODO 暂时不同步银豹(可能要从银豹到京西),2020-04-27
|
||||
errList.AddErr(cms.SetSingleStoreSkuSyncModifyStatus(db, []int{1, 3}))
|
||||
|
||||
// errList.AddErr(cms.SetSingleStoreSkuSyncModifyStatus(db, partner.GetSingleStoreVendorIDs()))
|
||||
// _, err = cms.CurVendorSync.AmendAndPruneStoreStuff(jxcontext.AdminCtx, []int{1, 3}, nil, false, true, cms.AmendPruneAll, false)
|
||||
|
||||
// _, err = cms.CurVendorSync.AmendAndPruneStoreStuff(jxcontext.AdminCtx, partner.GetSingleStoreVendorIDs(), nil, false, true, cms.AmendPruneAll, false)
|
||||
errList.AddErr(err)
|
||||
|
||||
SaveImportantTaskID(TaskNameSyncStoreSku, SpecialTaskID)
|
||||
taskID, err2 := cms.CurVendorSync.SyncStoresSkus2(jxcontext.AdminCtx, nil, 0, db, []int{1, 3, 5}, nil, false, nil, nil, syncFlag, true, true)
|
||||
// taskID, err2 := cms.CurVendorSync.SyncStoresSkus2(jxcontext.AdminCtx, nil, 0, db, partner.GetSingleStoreVendorIDs(), nil, false, nil, nil, syncFlag, true, true)
|
||||
|
||||
errList.AddErr(err2)
|
||||
SaveImportantTaskID(TaskNameSyncStoreSku, taskID)
|
||||
}
|
||||
err = errList.GetErrListAsOne()
|
||||
return retVal, err
|
||||
}, []int{0, 1})
|
||||
tasksch.HandleTask(task, nil, true).Run()
|
||||
}
|
||||
|
||||
func doDailyWork2() {
|
||||
globals.SugarLogger.Debug("doDailyWork2")
|
||||
|
||||
//同步京东商城门店的商品
|
||||
cms.CurVendorSync.SyncJdsStoresSkus(jxcontext.AdminCtx, nil, true, true)
|
||||
//刷新京东商城的门店库存
|
||||
cms.SyncJdsStoreStock(jxcontext.AdminCtx, true, true)
|
||||
}
|
||||
|
||||
func doDailyWork() {
|
||||
globals.SugarLogger.Debug("doDailyWork")
|
||||
|
||||
//同步商品额外前缀和水印图(打标记)
|
||||
cms.SyncSkuExperfixAndWatermark(jxcontext.AdminCtx)
|
||||
|
||||
dao.SetStoresMapSyncStatus(dao.GetDB(), nil, nil, model.SyncFlagStoreStatus)
|
||||
cms.CurVendorSync.SyncStore2(jxcontext.AdminCtx, dao.GetDB(), nil, nil, true, true)
|
||||
|
||||
syncStoreSku()
|
||||
InitEx()
|
||||
cms.SyncStoresCourierInfo(jxcontext.AdminCtx, nil, false, true)
|
||||
netprinter.RebindAllPrinters(jxcontext.AdminCtx, false, true)
|
||||
|
||||
// 每天补全前一天与当天的订单
|
||||
curDate := utils.Time2Date(time.Now())
|
||||
orderman.FixedOrderManager.AmendMissingOrders(jxcontext.AdminCtx, nil, 0, curDate.Add(-72*time.Hour), curDate, true, true)
|
||||
//订单门店归属补漏
|
||||
//fromDate, toDate都不传默认刷新当前天5天以前的订单,只传fromDate默认刷新fromDate到当天的订单
|
||||
//只传toDate默认刷新toDate到5天以前的订单
|
||||
orderman.RefreshOrdersWithoutJxStoreID(jxcontext.AdminCtx, "", "", true, true)
|
||||
//刷新京东门店的等级
|
||||
cms.RefreshJdLevel(jxcontext.AdminCtx)
|
||||
//删除操作日志
|
||||
// event.DeleteOperateEventAndDetail(jxcontext.AdminCtx, time.Now().AddDate(0, -3, 0))
|
||||
//禁用没有绑定的门店
|
||||
cms.DisabledStoreWithoutVendor(jxcontext.AdminCtx, true, true)
|
||||
//刷新物料订单状态
|
||||
localjx.RefreshAllMatterOrderStatus(jxcontext.AdminCtx)
|
||||
//同步银豹到京西
|
||||
// cms.CurVendorSync.SyncStoreSkusFromYb(jxcontext.AdminCtx, nil, true, true)
|
||||
//刷新京东商城订单结算价
|
||||
orderman.RefreshJdShopOrdersEarningPrice(jxcontext.AdminCtx, time.Now().AddDate(0, 0, -2).Format("20060102"), time.Now().Format("20060102"))
|
||||
//同步上架京东商城待售商品
|
||||
cms.RefreshJdsSkusStatus(jxcontext.AdminCtx)
|
||||
//同步美团配送与否状态及美团门店是否存在
|
||||
cms.SetMTPSStatus(jxcontext.AdminCtx, 0, 0)
|
||||
//售后单如果超过12小时没有审核,就自动通过
|
||||
RefreshAfsOrderStatusAccess(jxcontext.AdminCtx)
|
||||
}
|
||||
|
||||
func RefreshAfsOrderStatusAccess(ctx *jxcontext.Context) {
|
||||
var (
|
||||
offset = 0
|
||||
pageSize = 9999
|
||||
db = dao.GetDB()
|
||||
)
|
||||
afsOrderList, _, err := dao.GetAfsOrdersByPage(db, "", "", "", time.Now().AddDate(0, 0, -7), time.Now(), offset, pageSize)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, v := range afsOrderList {
|
||||
if v.Status == model.AfsOrderStatusWait4Approve && time.Now().Sub(v.AfsCreatedAt).Hours() > 12 {
|
||||
defsch.FixedScheduler.AgreeOrRefuseRefund(ctx, v.AfsOrderID, v.VendorID, model.AfsTypePartRefund, "超时系统同意")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func RefreshRealMobile(ctx *jxcontext.Context, vendorID int, fromTime, toTime time.Time, isAsync, isContinueWhenError bool) (hint string, err error) {
|
||||
globals.SugarLogger.Debug("RefreshRealMobile")
|
||||
|
||||
handler := partner.GetPurchasePlatformFromVendorID(vendorID)
|
||||
if handler == nil {
|
||||
return "", fmt.Errorf("不合法的vendorID:%d", vendorID)
|
||||
}
|
||||
sql := `
|
||||
SELECT *
|
||||
FROM goods_order
|
||||
WHERE vendor_id = ? AND consignee_mobile2 = ''
|
||||
`
|
||||
sqlParams := []interface{}{
|
||||
vendorID,
|
||||
}
|
||||
if !utils.IsTimeZero(fromTime) {
|
||||
sql += " AND order_created_at >= ?"
|
||||
sqlParams = append(sqlParams, fromTime)
|
||||
}
|
||||
if !utils.IsTimeZero(toTime) {
|
||||
sql += " AND order_created_at <= ?"
|
||||
sqlParams = append(sqlParams, toTime)
|
||||
}
|
||||
var orderList []*model.GoodsOrder
|
||||
db := dao.GetDB()
|
||||
if err = dao.GetRows(db, &orderList, sql, sqlParams...); err == nil && len(orderList) > 0 {
|
||||
task := tasksch.NewParallelTask("misc RefreshRealMobile", tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError), ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
order := batchItemList[0].(*model.GoodsOrder)
|
||||
mobile, err2 := handler.GetOrderRealMobile(ctx, order)
|
||||
if err = err2; err == nil {
|
||||
mobile = jxutils.FormalizeMobile(mobile)
|
||||
if jxutils.IsStringLikeMobile(mobile) && strings.Index(order.ConsigneeMobile, mobile) == -1 {
|
||||
order.ConsigneeMobile2 = mobile
|
||||
_, err = dao.UpdateEntity(db, order, "ConsigneeMobile2")
|
||||
}
|
||||
} else {
|
||||
globals.SugarLogger.Infof("RefreshRealMobile orderID:%s failed with error:%v", order.VendorOrderID, err)
|
||||
}
|
||||
return nil, err
|
||||
}, orderList)
|
||||
tasksch.HandleTask(task, nil, true).Run()
|
||||
hint = task.ID
|
||||
if !isAsync {
|
||||
_, err = task.GetResult(0)
|
||||
}
|
||||
}
|
||||
return hint, err
|
||||
//刷新任务过期状态
|
||||
cms.RefreshJobStatus(jxcontext.AdminCtx)
|
||||
//刷新任务标签状态
|
||||
cms.RefreshJobSpan(jxcontext.AdminCtx)
|
||||
//刷新用户会员时间
|
||||
cms.RefreshUserMemberStatus(jxcontext.AdminCtx)
|
||||
//删除聊天记录
|
||||
event.DeleteMessageRecord(jxcontext.AdminCtx)
|
||||
//自动确认收货(刷新状态)
|
||||
cms.RefreshDropShippingJob(jxcontext.AdminCtx)
|
||||
//刷新京东快递
|
||||
cms.RefreshJdDelivery(jxcontext.AdminCtx)
|
||||
//美团联盟活动自动创建
|
||||
cms.MtUnionJobAutoUpdate(jxcontext.AdminCtx)
|
||||
}
|
||||
|
||||
// 按时间序列循环
|
||||
|
||||
@@ -1,396 +0,0 @@
|
||||
package misc
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/baseapi"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxstore/cms"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/business/partner/putils"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
)
|
||||
|
||||
const (
|
||||
enableScheduleRefreshStore = true
|
||||
taskParallelCount = 4
|
||||
specialSkuNameKeyWord = "温馨提示"
|
||||
startOpStoreStockNumber = 0
|
||||
endOpStoreStockNumber = model.MaxStoreSkuStockQty
|
||||
)
|
||||
|
||||
var (
|
||||
isDaemonRunning = false
|
||||
vendorList = map[int]bool{
|
||||
model.VendorIDMTWM: true,
|
||||
model.VendorIDEBAI: true,
|
||||
}
|
||||
storeListQueueData = map[bool]*StoreListQueueData{
|
||||
true: &StoreListQueueData{},
|
||||
false: &StoreListQueueData{},
|
||||
}
|
||||
// vendorStoreRefreshTimeList = map[int][]string {
|
||||
// model.VendorIDMTWM: []string {
|
||||
// //start and end time for JXGY
|
||||
// "22:00:00",
|
||||
// "00:00:00",
|
||||
// //start and end time for JXCS
|
||||
// "22:10:00",
|
||||
// "00:10:00",
|
||||
// },
|
||||
// model.VendorIDEBAI: []string {
|
||||
// "22:20:00",
|
||||
// "06:00:00",
|
||||
|
||||
// "22:30:00",
|
||||
// "06:10:00",
|
||||
// },
|
||||
// }
|
||||
|
||||
// vendorStartEndStoreTime = map[int][]int16 {
|
||||
// model.VendorIDMTWM: []int16 {
|
||||
// int16(2200),//start time
|
||||
// int16(2355),//end time
|
||||
// },
|
||||
// model.VendorIDEBAI: []int16 {
|
||||
// int16(5),
|
||||
// int16(2355),
|
||||
// },
|
||||
// }
|
||||
)
|
||||
|
||||
type StoreListQueueData struct {
|
||||
waitQueue []*cms.StoreExt
|
||||
processQueue []*cms.StoreExt
|
||||
locker sync.RWMutex
|
||||
}
|
||||
|
||||
func (s *StoreListQueueData) GetProcessQueue() (outQueue []*cms.StoreExt) {
|
||||
s.locker.RLock()
|
||||
defer s.locker.RUnlock()
|
||||
outQueue = append(outQueue, s.processQueue...)
|
||||
return outQueue
|
||||
}
|
||||
|
||||
func (s *StoreListQueueData) InsertToWaitQueue(storeInfo *cms.StoreExt) {
|
||||
s.locker.Lock()
|
||||
defer s.locker.Unlock()
|
||||
s.waitQueue = append(s.waitQueue, storeInfo)
|
||||
}
|
||||
|
||||
func (s *StoreListQueueData) ClearProcessQueue() {
|
||||
s.locker.Lock()
|
||||
defer s.locker.Unlock()
|
||||
if len(s.processQueue) > 0 {
|
||||
s.processQueue = []*cms.StoreExt{}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *StoreListQueueData) TransferWaitQueueToProcessQueue() {
|
||||
s.locker.Lock()
|
||||
defer s.locker.Unlock()
|
||||
if len(s.processQueue) == 0 && len(s.waitQueue) > 0 {
|
||||
for _, value := range s.waitQueue {
|
||||
s.processQueue = append(s.processQueue, value)
|
||||
}
|
||||
s.waitQueue = []*cms.StoreExt{}
|
||||
}
|
||||
}
|
||||
|
||||
func AddOrDelExtraStoreOptime(ctx *jxcontext.Context, vendorID int, vendorOrgCode string, storeID int, vendorStoreID string, storeInfo *model.Store, startOpStoreTime, endOpStoreTime int16, needAddTime bool) bool {
|
||||
opTimeList := storeInfo.GetOpTimeList()
|
||||
if needAddTime {
|
||||
opTimeList = []int16{startOpStoreTime, endOpStoreTime}
|
||||
}
|
||||
handler := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.IStoreHandler)
|
||||
return handler.UpdateStoreOpTime(ctx, vendorOrgCode, storeID, vendorStoreID, opTimeList) == nil
|
||||
}
|
||||
|
||||
func GetStockValue(isStart bool) int {
|
||||
if isStart {
|
||||
return startOpStoreStockNumber
|
||||
} else {
|
||||
return endOpStoreStockNumber
|
||||
}
|
||||
}
|
||||
|
||||
// func GetOpStoreTime(vendorID int) (startTime, endTime int16) {
|
||||
// startTime = vendorStartEndStoreTime[vendorID][0]
|
||||
// endTime = vendorStartEndStoreTime[vendorID][1]
|
||||
// return startTime, endTime
|
||||
// }
|
||||
|
||||
func IsSpecialSku(name string) bool {
|
||||
return strings.Contains(name, specialSkuNameKeyWord)
|
||||
}
|
||||
|
||||
func SetSkuStock(isStart bool, storeSkuNameList []*partner.SkuNameInfo) {
|
||||
for _, skuNameInfo := range storeSkuNameList {
|
||||
for _, skuInfo := range skuNameInfo.SkuList {
|
||||
if IsSpecialSku(skuNameInfo.Name) || IsSpecialSku(skuInfo.SkuName) {
|
||||
skuInfo.Stock = endOpStoreStockNumber
|
||||
} else {
|
||||
skuInfo.Stock = GetStockValue(isStart)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func SetSpecialSkuStatus(ctx *jxcontext.Context, vendorID int, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuNameList []*partner.SkuNameInfo) {
|
||||
singleStoreHandler := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.ISingleStoreStoreSkuHandler)
|
||||
for _, skuNameInfo := range storeSkuNameList {
|
||||
for _, skuInfo := range skuNameInfo.SkuList {
|
||||
if IsSpecialSku(skuNameInfo.Name) || IsSpecialSku(skuInfo.SkuName) {
|
||||
storeSkuList := []*partner.StoreSkuInfo{&skuInfo.StoreSkuInfo}
|
||||
singleStoreHandler.UpdateStoreSkusStatus(ctx, vendorOrgCode, storeID, vendorStoreID, storeSkuList, model.SkuStatusNormal)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func GetFilterStoreSkuList(storeSkuList []*partner.StoreSkuInfo) (storeSkuListOut []*partner.StoreSkuInfo) {
|
||||
for _, value := range storeSkuList {
|
||||
if value.SkuID != 0 {
|
||||
storeSkuListOut = append(storeSkuListOut, value)
|
||||
}
|
||||
}
|
||||
|
||||
return storeSkuListOut
|
||||
}
|
||||
|
||||
func GetStoreList(ctx *jxcontext.Context) (storeList []*cms.StoreExt, err error) {
|
||||
storeInfo, err := cms.GetStores(ctx, "", map[string]interface{}{}, 0, -1, utils.DefaultTimeValue, utils.DefaultTimeValue, 0, 0)
|
||||
storeList = storeInfo.Stores
|
||||
return storeList, err
|
||||
}
|
||||
|
||||
func GetFilterStoreList(storeList []*cms.StoreExt, vendorMap, storeIDMap map[int]bool) (outStoreList []*cms.StoreExt) {
|
||||
for _, storeInfo := range storeList {
|
||||
storeID := storeInfo.ID
|
||||
//filter for storeID
|
||||
if len(storeIDMap) > 0 {
|
||||
if _, ok := storeIDMap[storeID]; !ok {
|
||||
continue
|
||||
}
|
||||
}
|
||||
for _, vendorStoreInfo := range storeInfo.StoreMaps {
|
||||
vendorID := vendorStoreInfo.VendorID
|
||||
//filter for vendorID
|
||||
if len(vendorMap) > 0 {
|
||||
if _, ok := vendorMap[vendorID]; !ok {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if _, ok := vendorList[vendorID]; !ok {
|
||||
continue
|
||||
}
|
||||
temp := *storeInfo
|
||||
newStoreInfo := &temp
|
||||
newStoreInfo.StoreMaps = []*model.StoreMap{vendorStoreInfo}
|
||||
outStoreList = append(outStoreList, newStoreInfo)
|
||||
}
|
||||
}
|
||||
|
||||
return outStoreList
|
||||
}
|
||||
|
||||
func StartOrEndOpStore(ctx *jxcontext.Context, isStart bool, vendorIDList []int, storeIDList []int, startTime, endTime int16, isAsync, isContinueWhenError bool) (retVal interface{}, err error) {
|
||||
storeList, err := GetStoreList(ctx)
|
||||
vendorMap := make(map[int]bool)
|
||||
for _, vendorID := range vendorIDList {
|
||||
vendorMap[vendorID] = true
|
||||
}
|
||||
storeIDMap := make(map[int]bool)
|
||||
for _, storeID := range storeIDList {
|
||||
storeIDMap[storeID] = true
|
||||
}
|
||||
storeList = GetFilterStoreList(storeList, vendorMap, storeIDMap)
|
||||
return StartOrEndOpStoreEx(ctx, isStart, startTime, endTime, isAsync, isContinueWhenError, storeList)
|
||||
}
|
||||
|
||||
func StartOrEndOpStoreEx(ctx *jxcontext.Context, isStart bool, startTime, endTime int16, isAsync, isContinueWhenError bool, storeList []*cms.StoreExt) (retVal interface{}, err error) {
|
||||
startProcessTime := time.Now().Unix()
|
||||
baseapi.SugarLogger.Debugf("StartOrEndOpStore start time: %v", time.Now())
|
||||
|
||||
if len(storeList) > 0 {
|
||||
taskFunc := func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
storeListValue := batchItemList[0].(*cms.StoreExt)
|
||||
storeID := storeListValue.ID
|
||||
for _, vendorListValue := range storeListValue.StoreMaps {
|
||||
vendorID := vendorListValue.VendorID
|
||||
startOpStoreTime := vendorListValue.FakeOpenStart
|
||||
endOpStoreTime := vendorListValue.FakeOpenStop
|
||||
//startOpStoreTime, endOpStoreTime := GetOpStoreTime(vendorID)
|
||||
if startTime != 0 && endTime != 0 {
|
||||
startOpStoreTime = startTime
|
||||
endOpStoreTime = endTime
|
||||
baseapi.SugarLogger.Debugf("StartOrEndOpStore SetStoreOptime:%d do:%d", startTime, endTime)
|
||||
}
|
||||
if isStart && (startOpStoreTime == 0 || endOpStoreTime == 0) {
|
||||
continue
|
||||
}
|
||||
vendorStoreID := vendorListValue.VendorStoreID
|
||||
baseapi.SugarLogger.Debugf("StartOrEndOpStore storeID:%d vendorID:%d vendorStoreID:%s", storeID, vendorID, vendorStoreID)
|
||||
singleStoreHandler := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.ISingleStoreStoreSkuHandler)
|
||||
storeSkuNameList, err := singleStoreHandler.GetStoreSkusFullInfo(ctx, task, storeID, vendorStoreID, nil)
|
||||
if err != nil {
|
||||
baseapi.SugarLogger.Errorf("StartOrEndOpStore GetStoreSkusFullInfo error:%v storeID:%d vendorID:%d vendorStoreID:%s", err, storeID, vendorID, vendorStoreID)
|
||||
} else {
|
||||
SetSkuStock(isStart, storeSkuNameList)
|
||||
SetSpecialSkuStatus(ctx, vendorID, vendorListValue.VendorOrgCode, storeID, vendorStoreID, storeSkuNameList)
|
||||
storeSkuList := putils.StoreSkuFullList2Bare(storeSkuNameList)
|
||||
if vendorID == model.VendorIDMTWM {
|
||||
storeSkuList = GetFilterStoreSkuList(storeSkuList)
|
||||
}
|
||||
if len(storeSkuList) > 0 {
|
||||
if !isStart {
|
||||
AddOrDelExtraStoreOptime(ctx, vendorID, vendorListValue.VendorOrgCode, storeID, vendorStoreID, &storeListValue.Store, startOpStoreTime, endOpStoreTime, false)
|
||||
}
|
||||
|
||||
_, err = putils.FreeBatchStoreSkuInfo("更新门店商品库存", func(task tasksch.ITask, batchedStoreSkuList []*partner.StoreSkuInfo) (result interface{}, successCount int, err error) {
|
||||
_, err = singleStoreHandler.UpdateStoreSkusStock(ctx, vendorListValue.VendorOrgCode, storeID, vendorStoreID, batchedStoreSkuList)
|
||||
return nil, 0, err
|
||||
}, ctx, task, storeSkuList, singleStoreHandler.GetStoreSkusBatchSize(partner.FuncUpdateStoreSkusStock), true)
|
||||
|
||||
if isStart {
|
||||
AddOrDelExtraStoreOptime(ctx, vendorID, vendorListValue.VendorOrgCode, storeID, vendorStoreID, &storeListValue.Store, startOpStoreTime, endOpStoreTime, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return retVal, err
|
||||
}
|
||||
taskName := ""
|
||||
if isStart {
|
||||
taskName = "开启平台商店的额外营业时间"
|
||||
} else {
|
||||
taskName = "结束平台商店的额外营业时间"
|
||||
}
|
||||
task := tasksch.NewParallelTask(taskName, tasksch.NewParallelConfig().SetParallelCount(taskParallelCount), ctx, taskFunc, storeList)
|
||||
tasksch.HandleTask(task, nil, true).Run()
|
||||
if isAsync {
|
||||
retVal = task.ID
|
||||
} else {
|
||||
_, err = task.GetResult(0)
|
||||
if err != nil {
|
||||
baseapi.SugarLogger.Debugf("StartOrEndOpStore tasksch error:%v", err)
|
||||
}
|
||||
retVal = "1"
|
||||
}
|
||||
}
|
||||
endProcessTime := time.Now().Unix()
|
||||
diff := endProcessTime - startProcessTime
|
||||
baseapi.SugarLogger.Debugf("StartOrEndOpStore end time: %v", time.Now())
|
||||
baseapi.SugarLogger.Debugf("StartOrEndOpStore cost time: %d sec", diff)
|
||||
|
||||
return retVal, err
|
||||
}
|
||||
|
||||
func IsJXCS() bool {
|
||||
return globals.IsMainProductEnv()
|
||||
}
|
||||
|
||||
// func GetVendorStoreRefreshTime(vendorID int) (startTimeList, stopTimeList []string) {
|
||||
// isJXCS := globals.IsMainProductEnv()
|
||||
// refreshTimeList := vendorStoreRefreshTimeList[vendorID]
|
||||
// if isJXCS {
|
||||
// startTimeList = []string{refreshTimeList[2]}
|
||||
// stopTimeList = []string{refreshTimeList[3]}
|
||||
// } else {
|
||||
// startTimeList = []string{refreshTimeList[0]}
|
||||
// stopTimeList = []string{refreshTimeList[1]}
|
||||
// }
|
||||
// return startTimeList, stopTimeList
|
||||
// }
|
||||
|
||||
// func RefreshStore(vendorID int) {
|
||||
// ctx := jxcontext.AdminCtx
|
||||
// startTimeList, stopTimeList := GetVendorStoreRefreshTime(vendorID)
|
||||
// vendorIDList := []int{vendorID}
|
||||
// storeIDList := []int{}
|
||||
// ScheduleTimerFunc("StartOpStore", func() {
|
||||
// if !IsImportantTaskRunning(TaskNameSyncStoreSku) {
|
||||
// StartOrEndOpStore(ctx, true, vendorIDList, storeIDList, 0, 0, false, true)
|
||||
// }
|
||||
// }, startTimeList)
|
||||
// ScheduleTimerFunc("EndOpStore", func() {
|
||||
// if !IsImportantTaskRunning(TaskNameSyncStoreSku) {
|
||||
// StartOrEndOpStore(ctx, false, vendorIDList, storeIDList, 0, 0, false, true)
|
||||
// }
|
||||
// }, stopTimeList)
|
||||
// }
|
||||
|
||||
func InitEx() {
|
||||
// for index, value := range vendorList {
|
||||
// if value {
|
||||
// RefreshStore(index)
|
||||
// }
|
||||
// }
|
||||
if enableScheduleRefreshStore && IsJXCS() {
|
||||
ctx := jxcontext.AdminCtx
|
||||
storeList, err := GetStoreList(ctx)
|
||||
storeList = GetFilterStoreList(storeList, map[int]bool{}, map[int]bool{})
|
||||
if err == nil {
|
||||
for _, storeInfo := range storeList {
|
||||
for _, vendorStoreInfo := range storeInfo.StoreMaps {
|
||||
startOpStoreTime := vendorStoreInfo.FakeOpenStart
|
||||
endOpStoreTime := vendorStoreInfo.FakeOpenStop
|
||||
if startOpStoreTime == 0 || endOpStoreTime == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
startTime := jxutils.OperationTime2StrWithSecond(startOpStoreTime)
|
||||
ScheduleTimerFuncOnce("StartOpStore", func(param interface{}) {
|
||||
if !IsImportantTaskRunning(TaskNameSyncStoreSku) {
|
||||
storeInfo := param.(*cms.StoreExt)
|
||||
storeListQueueData[true].InsertToWaitQueue(storeInfo)
|
||||
}
|
||||
}, startTime, storeInfo)
|
||||
|
||||
stopTime := jxutils.OperationTime2StrWithSecond(endOpStoreTime)
|
||||
ScheduleTimerFuncOnce("EndOpStore", func(param interface{}) {
|
||||
storeInfo := param.(*cms.StoreExt)
|
||||
storeListQueueData[false].InsertToWaitQueue(storeInfo)
|
||||
}, stopTime, storeInfo)
|
||||
}
|
||||
}
|
||||
if !isDaemonRunning {
|
||||
isDaemonRunning = true
|
||||
taskSeqFunc := func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
|
||||
switch step {
|
||||
case 0:
|
||||
periodlyFunc := func() {
|
||||
for isStart, value := range storeListQueueData {
|
||||
storeList := value.GetProcessQueue()
|
||||
if len(storeList) > 0 {
|
||||
StartOrEndOpStoreEx(ctx, isStart, 0, 0, false, true, storeList)
|
||||
}
|
||||
}
|
||||
for _, value := range storeListQueueData {
|
||||
value.ClearProcessQueue()
|
||||
value.TransferWaitQueueToProcessQueue()
|
||||
}
|
||||
}
|
||||
PeriodlyCall(60*time.Second, periodlyFunc)
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
taskSeq := tasksch.NewSeqTask("启动监听-定时刷新平台商店的额外营业时间", ctx, taskSeqFunc, 1)
|
||||
tasksch.HandleTask(taskSeq, nil, true).Run()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func PeriodlyCall(d time.Duration, handler func()) {
|
||||
ticker := time.NewTicker(d)
|
||||
for _ = range ticker.C {
|
||||
handler()
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package misc
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
)
|
||||
|
||||
func TestStartOrEndOpStore(t *testing.T) {
|
||||
StartOrEndOpStore(jxcontext.AdminCtx, true, nil, nil, 0, 0, false, true)
|
||||
}
|
||||
@@ -1,509 +0,0 @@
|
||||
package misc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/baseapi"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxstore/cms"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/weixinmsg"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/globals/refutil"
|
||||
)
|
||||
|
||||
const (
|
||||
EnableCheckStoreAlert = true
|
||||
EnableSendStoreAlert = true
|
||||
|
||||
IncludeToday = true
|
||||
CheckStoreAlertOneMonthDayNum = 30
|
||||
CheckStoreAlertOneDayNum = 1
|
||||
CheckStoreAlertOneWeekDayNum = 7
|
||||
MonthCheckOnWeekDay = 1
|
||||
|
||||
AlertTypePickTimeOrderDaDa = 0
|
||||
AlertTypeBadCommentOrder = 1
|
||||
AlertTypeAbsentGoodsOrder = 2
|
||||
AlertTypeStandardFinishTimeOrderSelfDelivery = 3
|
||||
AlertTypeStandardPickUpTimeOrderDaDa = 4
|
||||
|
||||
ColorRed = "red"
|
||||
ColorYellow = "yellow"
|
||||
ColorUnknown = "unknown"
|
||||
|
||||
AlertLevelExtraRed = 1
|
||||
AlertLevelRed = 2
|
||||
AlertLevelYellow = 3
|
||||
|
||||
OneDayName = "单日"
|
||||
OneWeekDayName = "七日"
|
||||
OneMonthDayName = "三十日"
|
||||
YellowAlertInfo = "您的店铺-%s,由于%s%s%s%d%%,可能会被系统下线,请及时补救。"
|
||||
RedAlertInfo = "您的店铺-%s,由于%s%s%s%d%%,会被系统下线,需要马上补救。"
|
||||
ExtraRedAlertInfo = "您的店铺-%s,由于%s%s%s%d%%,会被系统下线,需要马上补救。"
|
||||
NoOrderAlertInfo = "您的店铺-%s,由于近%s无订单,会被系统下线,需要马上补救。"
|
||||
RiskOrderAlertInfo = "您的店铺-%s,可能有虚假定单,定单号为:%s,可能会被罚款,请及时与运营联系!"
|
||||
)
|
||||
|
||||
var (
|
||||
checkStoreAlertTimeList = []string{
|
||||
"18:30:00",
|
||||
}
|
||||
|
||||
AlertTypeNameMap = map[int]string{
|
||||
AlertTypePickTimeOrderDaDa: "拣货履约率(达达)",
|
||||
AlertTypeBadCommentOrder: "差评率",
|
||||
AlertTypeAbsentGoodsOrder: "缺货率",
|
||||
AlertTypeStandardFinishTimeOrderSelfDelivery: "按时履约率(商家自送)",
|
||||
AlertTypeStandardPickUpTimeOrderDaDa: "10分钟取货完成率(达达)",
|
||||
}
|
||||
|
||||
AlertTypeExtraNameMap = map[int]string{
|
||||
AlertTypePickTimeOrderDaDa: "拣货超时订单(达达)",
|
||||
AlertTypeBadCommentOrder: "差评订单",
|
||||
AlertTypeAbsentGoodsOrder: "缺货订单",
|
||||
}
|
||||
|
||||
storeAlertDataWrapper StoreAlertDataWrapper
|
||||
)
|
||||
|
||||
type StoreAlertDataWrapper struct {
|
||||
storeAlertList map[int]*model.StoreAlert
|
||||
}
|
||||
|
||||
func (s *StoreAlertDataWrapper) InitData() {
|
||||
s.storeAlertList = make(map[int]*model.StoreAlert)
|
||||
}
|
||||
|
||||
func (s *StoreAlertDataWrapper) ClearData() {
|
||||
s.storeAlertList = nil
|
||||
}
|
||||
|
||||
func (s *StoreAlertDataWrapper) IsStatusField(valueName string) bool {
|
||||
return valueName == model.FieldYellowStatus || valueName == model.FieldRedStatus || valueName == model.FieldExtraRedStatus
|
||||
}
|
||||
|
||||
func (s *StoreAlertDataWrapper) SetData(storeID int, valueName string, value int) {
|
||||
data := s.storeAlertList[storeID]
|
||||
if data == nil {
|
||||
data = &model.StoreAlert{}
|
||||
data.StoreID = storeID
|
||||
data.AlertDate = utils.GetCurDate()
|
||||
s.storeAlertList[storeID] = data
|
||||
}
|
||||
if s.IsStatusField(valueName) {
|
||||
srcFieldValue := refutil.GetObjFieldByName(data, valueName).(int)
|
||||
value |= srcFieldValue
|
||||
}
|
||||
refutil.SetObjFieldByName(data, valueName, value)
|
||||
}
|
||||
|
||||
func (s StoreAlertDataWrapper) InsertStoreAlertList() {
|
||||
for _, value := range s.storeAlertList {
|
||||
dao.InsertStoreAlert(value)
|
||||
}
|
||||
}
|
||||
|
||||
func ConvertListToMap(listData []*model.StoreCount) (mapData map[int]int) {
|
||||
mapData = make(map[int]int)
|
||||
for _, value := range listData {
|
||||
mapData[value.StoreID] = value.Count
|
||||
}
|
||||
|
||||
return mapData
|
||||
}
|
||||
|
||||
func ConvertListToMapEx(listData []*model.StoreOrder) (mapData map[int][]string) {
|
||||
mapData = make(map[int][]string)
|
||||
for _, value := range listData {
|
||||
if mapData[value.StoreID] == nil {
|
||||
mapData[value.StoreID] = []string{}
|
||||
}
|
||||
mapData[value.StoreID] = append(mapData[value.StoreID], value.VendorOrderID)
|
||||
}
|
||||
|
||||
return mapData
|
||||
}
|
||||
|
||||
func GetAlertInfo(dayNum, alertLevel int, storeName string, alertType int, logicCondition string, value int) (info string) {
|
||||
if dayNum == CheckStoreAlertOneDayNum {
|
||||
if alertLevel == AlertLevelExtraRed {
|
||||
info = fmt.Sprintf(ExtraRedAlertInfo, storeName, OneDayName, AlertTypeExtraNameMap[alertType], logicCondition, value)
|
||||
} else if alertLevel == AlertLevelRed {
|
||||
info = fmt.Sprintf(RedAlertInfo, storeName, OneDayName, AlertTypeNameMap[alertType], logicCondition, value)
|
||||
} else if alertLevel == AlertLevelYellow {
|
||||
info = fmt.Sprintf(YellowAlertInfo, storeName, OneDayName, AlertTypeNameMap[alertType], logicCondition, value)
|
||||
}
|
||||
} else if dayNum == CheckStoreAlertOneWeekDayNum {
|
||||
if alertLevel == AlertLevelExtraRed {
|
||||
info = fmt.Sprintf(ExtraRedAlertInfo, storeName, OneWeekDayName, AlertTypeExtraNameMap[alertType], logicCondition, value)
|
||||
} else if alertLevel == AlertLevelRed {
|
||||
info = fmt.Sprintf(RedAlertInfo, storeName, OneWeekDayName, AlertTypeNameMap[alertType], logicCondition, value)
|
||||
} else if alertLevel == AlertLevelYellow {
|
||||
info = fmt.Sprintf(YellowAlertInfo, storeName, OneWeekDayName, AlertTypeNameMap[alertType], logicCondition, value)
|
||||
}
|
||||
} else if dayNum == CheckStoreAlertOneMonthDayNum {
|
||||
info = fmt.Sprintf(NoOrderAlertInfo, storeName, OneMonthDayName)
|
||||
}
|
||||
|
||||
return info
|
||||
}
|
||||
|
||||
func CheckAlert(alertType int, dayNum int, ratio int, count int) (alertLevel int, logicCondtion string, outValue int) {
|
||||
yellowRatio := -1
|
||||
redRatio := -1
|
||||
extraCount := -1
|
||||
conditionLessEqual := false
|
||||
|
||||
switch alertType {
|
||||
case AlertTypePickTimeOrderDaDa:
|
||||
if dayNum == CheckStoreAlertOneDayNum {
|
||||
redRatio = 0
|
||||
} else if dayNum == CheckStoreAlertOneWeekDayNum {
|
||||
yellowRatio = 70
|
||||
redRatio = 50
|
||||
extraCount = 5
|
||||
}
|
||||
conditionLessEqual = true
|
||||
case AlertTypeBadCommentOrder:
|
||||
if dayNum == CheckStoreAlertOneDayNum {
|
||||
redRatio = 100
|
||||
} else if dayNum == CheckStoreAlertOneWeekDayNum {
|
||||
yellowRatio = 1
|
||||
redRatio = 3
|
||||
extraCount = 5
|
||||
}
|
||||
conditionLessEqual = false
|
||||
case AlertTypeAbsentGoodsOrder:
|
||||
if dayNum == CheckStoreAlertOneDayNum {
|
||||
redRatio = 100
|
||||
} else if dayNum == CheckStoreAlertOneWeekDayNum {
|
||||
yellowRatio = 3
|
||||
redRatio = 5
|
||||
extraCount = 5
|
||||
}
|
||||
conditionLessEqual = false
|
||||
case AlertTypeStandardFinishTimeOrderSelfDelivery:
|
||||
yellowRatio = 85
|
||||
redRatio = 70
|
||||
conditionLessEqual = true
|
||||
case AlertTypeStandardPickUpTimeOrderDaDa:
|
||||
yellowRatio = 85
|
||||
redRatio = 70
|
||||
conditionLessEqual = true
|
||||
}
|
||||
|
||||
if conditionLessEqual {
|
||||
logicCondtion = "<="
|
||||
if extraCount != -1 && count >= extraCount {
|
||||
alertLevel = AlertLevelExtraRed
|
||||
outValue = extraCount
|
||||
} else if redRatio != -1 && ratio <= redRatio {
|
||||
alertLevel = AlertLevelRed
|
||||
outValue = redRatio
|
||||
} else if yellowRatio != -1 && ratio <= yellowRatio {
|
||||
alertLevel = AlertLevelYellow
|
||||
outValue = yellowRatio
|
||||
}
|
||||
} else {
|
||||
logicCondtion = ">="
|
||||
if extraCount != -1 && count >= extraCount {
|
||||
alertLevel = AlertLevelExtraRed
|
||||
outValue = extraCount
|
||||
} else if redRatio != -1 && ratio >= redRatio {
|
||||
alertLevel = AlertLevelRed
|
||||
outValue = redRatio
|
||||
} else if yellowRatio != -1 && ratio >= yellowRatio {
|
||||
alertLevel = AlertLevelYellow
|
||||
outValue = yellowRatio
|
||||
}
|
||||
}
|
||||
|
||||
return alertLevel, logicCondtion, outValue
|
||||
}
|
||||
|
||||
func SendAlertInfo(storeID int, storeName, alertInfo string) {
|
||||
if EnableSendStoreAlert {
|
||||
baseapi.SugarLogger.Debugf("SendAlertInfo: %d, %s", storeID, alertInfo)
|
||||
weixinmsg.NotifyStoreAlertMessage(storeID, storeName, "门店警告", alertInfo)
|
||||
}
|
||||
}
|
||||
|
||||
func GetFieldNameByAlertType(alertType, dayNum int) (fieldName string, fieldFlag int) {
|
||||
switch alertType {
|
||||
case AlertTypePickTimeOrderDaDa:
|
||||
if dayNum == CheckStoreAlertOneDayNum {
|
||||
fieldName = model.FieldPickTimeDaDa
|
||||
fieldFlag = model.FlagPickTimeDaDa
|
||||
} else if dayNum == CheckStoreAlertOneWeekDayNum {
|
||||
fieldName = model.FieldPickTimeDaDaOneWeek
|
||||
fieldFlag = model.FlagPickTimeDaDaOneWeek
|
||||
}
|
||||
case AlertTypeBadCommentOrder:
|
||||
if dayNum == CheckStoreAlertOneDayNum {
|
||||
fieldName = model.FieldBadComment
|
||||
fieldFlag = model.FlagBadComment
|
||||
} else if dayNum == CheckStoreAlertOneWeekDayNum {
|
||||
fieldName = model.FieldBadCommentOneWeek
|
||||
fieldFlag = model.FlagBadCommentOneWeek
|
||||
}
|
||||
case AlertTypeAbsentGoodsOrder:
|
||||
if dayNum == CheckStoreAlertOneDayNum {
|
||||
fieldName = model.FieldAbsentGoods
|
||||
fieldFlag = model.FlagAbsentGoods
|
||||
} else if dayNum == CheckStoreAlertOneWeekDayNum {
|
||||
fieldName = model.FieldAbsentGoodsOneWeek
|
||||
fieldFlag = model.FlagAbsentGoodsOneWeek
|
||||
}
|
||||
case AlertTypeStandardFinishTimeOrderSelfDelivery:
|
||||
fieldName = model.FieldStandardFinishTimeSelfDelivery
|
||||
fieldFlag = model.FlagStandardFinishTimeSelfDelivery
|
||||
case AlertTypeStandardPickUpTimeOrderDaDa:
|
||||
fieldName = model.FieldStandardPickUpTimeDaDa
|
||||
fieldFlag = model.FlagStandardPickUpTimeDaDa
|
||||
}
|
||||
|
||||
return fieldName, fieldFlag
|
||||
}
|
||||
|
||||
func SendAlertInfoWrapper(storeID int, storeName string, dayNum, alertType, count, totalCount int) {
|
||||
if totalCount > 0 {
|
||||
ratio := int(math.Round(float64(count) * 100 / float64(totalCount)))
|
||||
alertLevel, logicCondtion, outValue := CheckAlert(alertType, dayNum, ratio, count)
|
||||
if alertLevel != 0 {
|
||||
alertInfo := GetAlertInfo(dayNum, alertLevel, storeName, alertType, logicCondtion, outValue)
|
||||
SendAlertInfo(storeID, storeName, alertInfo)
|
||||
fieldName, fieldFlag := GetFieldNameByAlertType(alertType, dayNum)
|
||||
storeAlertDataWrapper.SetData(storeID, fieldName, ratio)
|
||||
|
||||
if alertLevel == AlertLevelExtraRed {
|
||||
storeAlertDataWrapper.SetData(storeID, model.FieldExtraRedStatus, fieldFlag)
|
||||
} else if alertLevel == AlertLevelRed {
|
||||
storeAlertDataWrapper.SetData(storeID, model.FieldRedStatus, fieldFlag)
|
||||
} else if alertLevel == AlertLevelYellow {
|
||||
storeAlertDataWrapper.SetData(storeID, model.FieldYellowStatus, fieldFlag)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func CheckStoreDayAlert(storeList []*cms.StoreExt, dayNum int) {
|
||||
db := dao.GetDB()
|
||||
//拣货履约订单(达达)
|
||||
pickTimeOrderCountDaDaList, _ := dao.GetStandardPickTimeOrderCountByDaDa(db, dayNum, IncludeToday)
|
||||
pickTimeOrderCountDaDaMapData := ConvertListToMap(pickTimeOrderCountDaDaList)
|
||||
|
||||
//完成订单(达达)
|
||||
finishOrderCountDaDaList, _ := dao.GetFinishOrderCountByDaDa(db, dayNum, IncludeToday)
|
||||
finishOrderCountDaDaMapData := ConvertListToMap(finishOrderCountDaDaList)
|
||||
|
||||
//差评订单
|
||||
badCommentOrderCountList, _ := dao.GetBadCommentOrderCountByDayNum(db, dayNum, IncludeToday)
|
||||
badCommentOrderCountMapData := ConvertListToMap(badCommentOrderCountList)
|
||||
|
||||
//缺货订单
|
||||
absentGoodsOrderCountList, _ := dao.GetAbsentGoodsOrderCountByDayNum(db, dayNum, IncludeToday)
|
||||
absentGoodsOrderCountMapData := ConvertListToMap(absentGoodsOrderCountList)
|
||||
|
||||
//完成订单
|
||||
finishOrderCountList, _ := dao.GetFinishOrderCountByDayNum(db, dayNum, IncludeToday)
|
||||
finishOrderCountMapData := ConvertListToMap(finishOrderCountList)
|
||||
|
||||
var standardFinishTimeOrderCountSelfDeliveryList []*model.StoreCount
|
||||
var standardFinishTimeOrderCountSelfDeliveryMapData map[int]int
|
||||
var finishOrderCountSelfDeliveryList []*model.StoreCount
|
||||
var finishOrderCountSelfDeliveryMapData map[int]int
|
||||
var standardPickUpTimeOrderCountDaDaList []*model.StoreCount
|
||||
var standardPickUpTimeOrderCountDaDaMapData map[int]int
|
||||
isOneWeekDay := dayNum == CheckStoreAlertOneWeekDayNum
|
||||
if isOneWeekDay {
|
||||
//按时履约订单(商家自送)
|
||||
standardFinishTimeOrderCountSelfDeliveryList, _ = dao.GetStandardFinishTimeOrderCountBySelfDelivery(db, dayNum, IncludeToday)
|
||||
standardFinishTimeOrderCountSelfDeliveryMapData = ConvertListToMap(standardFinishTimeOrderCountSelfDeliveryList)
|
||||
|
||||
//完成订单(商家自送)
|
||||
finishOrderCountSelfDeliveryList, _ = dao.GetFinishOrderCountBySelfDelivery(db, dayNum, IncludeToday)
|
||||
finishOrderCountSelfDeliveryMapData = ConvertListToMap(finishOrderCountSelfDeliveryList)
|
||||
|
||||
//10分钟取货完成订单(达达)
|
||||
standardPickUpTimeOrderCountDaDaList, _ = dao.GetStandardPickUpTimeOrderCountByDaDa(db, dayNum, IncludeToday)
|
||||
standardPickUpTimeOrderCountDaDaMapData = ConvertListToMap(standardPickUpTimeOrderCountDaDaList)
|
||||
}
|
||||
|
||||
for _, storeInfo := range storeList {
|
||||
storeID := storeInfo.ID
|
||||
storeName := storeInfo.Name
|
||||
count := pickTimeOrderCountDaDaMapData[storeID]
|
||||
totalCount := finishOrderCountDaDaMapData[storeID]
|
||||
SendAlertInfoWrapper(storeID, storeName, dayNum, AlertTypePickTimeOrderDaDa, count, totalCount)
|
||||
|
||||
count = badCommentOrderCountMapData[storeID]
|
||||
totalCount = finishOrderCountMapData[storeID]
|
||||
SendAlertInfoWrapper(storeID, storeName, dayNum, AlertTypeBadCommentOrder, count, totalCount)
|
||||
count = absentGoodsOrderCountMapData[storeID]
|
||||
SendAlertInfoWrapper(storeID, storeName, dayNum, AlertTypeAbsentGoodsOrder, count, totalCount)
|
||||
|
||||
if isOneWeekDay {
|
||||
count = standardFinishTimeOrderCountSelfDeliveryMapData[storeID]
|
||||
totalCount = finishOrderCountSelfDeliveryMapData[storeID]
|
||||
SendAlertInfoWrapper(storeID, storeName, dayNum, AlertTypeStandardFinishTimeOrderSelfDelivery, count, totalCount)
|
||||
|
||||
count = standardPickUpTimeOrderCountDaDaMapData[storeID]
|
||||
totalCount = finishOrderCountDaDaMapData[storeID]
|
||||
SendAlertInfoWrapper(storeID, storeName, dayNum, AlertTypeStandardPickUpTimeOrderDaDa, count, totalCount)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func CheckStoreMonthAlert(storeList []*cms.StoreExt) {
|
||||
db := dao.GetDB()
|
||||
storeCountList, _ := dao.GetFinishOrderCountByDayNum(db, CheckStoreAlertOneMonthDayNum, IncludeToday)
|
||||
storeCountMapData := make(map[int]int)
|
||||
for _, value := range storeCountList {
|
||||
storeCountMapData[value.StoreID] = value.Count
|
||||
}
|
||||
|
||||
for _, storeInfo := range storeList {
|
||||
storeID := storeInfo.ID
|
||||
storeName := storeInfo.Name
|
||||
if _, ok := storeCountMapData[storeID]; !ok {
|
||||
alertInfo := GetAlertInfo(CheckStoreAlertOneMonthDayNum, AlertLevelRed, storeName, -1, "", -1)
|
||||
SendAlertInfo(storeID, storeName, alertInfo)
|
||||
storeAlertDataWrapper.SetData(storeID, model.FieldNoOrderInMonth, 1)
|
||||
storeAlertDataWrapper.SetData(storeID, model.FieldRedStatus, model.FlagNoOrderInMonth)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func CheckStoreRiskOrderAlert(storeList []*cms.StoreExt, dayNum int) {
|
||||
db := dao.GetDB()
|
||||
storeOrderList, _ := dao.GetRiskOrderCount(db, dayNum, IncludeToday)
|
||||
storeOrderMapData := ConvertListToMapEx(storeOrderList)
|
||||
for _, storeInfo := range storeList {
|
||||
storeID := storeInfo.ID
|
||||
storeName := storeInfo.Name
|
||||
vendorOrderIDList := storeOrderMapData[storeID]
|
||||
if vendorOrderIDList != nil {
|
||||
vendorOrderIDStr := ""
|
||||
for index, vendorOrderID := range vendorOrderIDList {
|
||||
if index == 0 {
|
||||
vendorOrderIDStr += vendorOrderID
|
||||
} else {
|
||||
vendorOrderIDStr += "," + vendorOrderID
|
||||
}
|
||||
}
|
||||
alertInfo := fmt.Sprintf(RiskOrderAlertInfo, storeName, vendorOrderIDStr)
|
||||
SendAlertInfo(storeID, storeName, alertInfo)
|
||||
storeAlertDataWrapper.SetData(storeID, model.FieldRiskOrderCount, len(vendorOrderIDList))
|
||||
storeAlertDataWrapper.SetData(storeID, model.FieldRedStatus, model.FlagRiskOrderCount)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func GetWeekDay() int {
|
||||
return int(time.Now().Weekday())
|
||||
}
|
||||
|
||||
func CheckStoreAlert(ctx *jxcontext.Context, storeIDList []int) {
|
||||
storeAlertDataWrapper.InitData()
|
||||
storeList, _ := GetStoreList(ctx)
|
||||
storeIDMap := jxutils.IntList2Map(storeIDList)
|
||||
storeList = GetFilterStoreListEx(storeList, storeIDMap)
|
||||
if GetWeekDay() == MonthCheckOnWeekDay {
|
||||
CheckStoreMonthAlert(storeList)
|
||||
}
|
||||
CheckStoreDayAlert(storeList, CheckStoreAlertOneDayNum)
|
||||
CheckStoreDayAlert(storeList, CheckStoreAlertOneWeekDayNum)
|
||||
CheckStoreRiskOrderAlert(storeList, CheckStoreAlertOneDayNum)
|
||||
storeAlertDataWrapper.InsertStoreAlertList()
|
||||
storeAlertDataWrapper.ClearData()
|
||||
}
|
||||
|
||||
func ScheduleCheckStoreAlert() {
|
||||
if EnableCheckStoreAlert {
|
||||
ScheduleTimerFunc("ScheduleCheckStoreAlert", func() {
|
||||
CheckStoreAlert(jxcontext.AdminCtx, nil)
|
||||
}, checkStoreAlertTimeList)
|
||||
}
|
||||
}
|
||||
|
||||
func GetValueColorByStatus(extraRedStatus, redStatus, yellowStatus, flag int) (color string) {
|
||||
if (extraRedStatus&flag != 0) || (redStatus&flag != 0) {
|
||||
color = ColorRed
|
||||
} else if yellowStatus&flag != 0 {
|
||||
color = ColorYellow
|
||||
} else {
|
||||
color = ColorUnknown
|
||||
}
|
||||
|
||||
return color
|
||||
}
|
||||
|
||||
func GetStoreAlertList(storeIDList []int, cityCode int, keyWord string, dateTime time.Time, offset, pageSize int) (storeAlertData model.StoreAlertData, err error) {
|
||||
db := dao.GetDB()
|
||||
storeAlertList, err := dao.GetStoreAlertList(db, storeIDList, cityCode, keyWord, dateTime)
|
||||
if err == nil && len(storeAlertList) > 0 {
|
||||
offset = jxutils.FormalizePageOffset(offset)
|
||||
pageSize = jxutils.FormalizePageSize(pageSize)
|
||||
var pagedStoreAlertList []*model.StoreAlertEx
|
||||
for i := offset; i < offset+pageSize && i < len(storeAlertList); i++ {
|
||||
pagedStoreAlertList = append(pagedStoreAlertList, storeAlertList[i])
|
||||
}
|
||||
|
||||
var storeAlertAdvancedList []*model.StoreAlertAdvanced
|
||||
for _, value := range pagedStoreAlertList {
|
||||
storeAlertAdvanced := &model.StoreAlertAdvanced{}
|
||||
storeAlertAdvanced.ID = value.ID
|
||||
storeAlertAdvanced.CreatedTime = value.CreatedTime
|
||||
storeAlertAdvanced.AlertDate = value.AlertDate
|
||||
storeAlertAdvanced.StoreID = value.StoreID
|
||||
storeAlertAdvanced.StoreName = value.StoreName
|
||||
storeAlertAdvanced.CityName = value.CityName
|
||||
|
||||
storeAlertAdvanced.PickTimeDaDa.Value = fmt.Sprintf("%d%%", value.PickTimeDaDa)
|
||||
storeAlertAdvanced.PickTimeDaDa.Color = GetValueColorByStatus(value.ExtraRedStatus, value.RedStatus, value.YellowStatus, model.FlagPickTimeDaDa)
|
||||
|
||||
storeAlertAdvanced.BadComment.Value = fmt.Sprintf("%d%%", value.BadComment)
|
||||
storeAlertAdvanced.BadComment.Color = GetValueColorByStatus(value.ExtraRedStatus, value.RedStatus, value.YellowStatus, model.FlagBadComment)
|
||||
|
||||
storeAlertAdvanced.AbsentGoods.Value = fmt.Sprintf("%d%%", value.AbsentGoods)
|
||||
storeAlertAdvanced.AbsentGoods.Color = GetValueColorByStatus(value.ExtraRedStatus, value.RedStatus, value.YellowStatus, model.FlagAbsentGoods)
|
||||
|
||||
storeAlertAdvanced.PickTimeDaDaOneWeek.Value = fmt.Sprintf("%d%%", value.PickTimeDaDaOneWeek)
|
||||
storeAlertAdvanced.PickTimeDaDaOneWeek.Color = GetValueColorByStatus(value.ExtraRedStatus, value.RedStatus, value.YellowStatus, model.FlagPickTimeDaDaOneWeek)
|
||||
|
||||
storeAlertAdvanced.BadCommentOneWeek.Value = fmt.Sprintf("%d%%", value.BadCommentOneWeek)
|
||||
storeAlertAdvanced.BadCommentOneWeek.Color = GetValueColorByStatus(value.ExtraRedStatus, value.RedStatus, value.YellowStatus, model.FlagBadCommentOneWeek)
|
||||
|
||||
storeAlertAdvanced.AbsentGoodsOneWeek.Value = fmt.Sprintf("%d%%", value.AbsentGoodsOneWeek)
|
||||
storeAlertAdvanced.AbsentGoodsOneWeek.Color = GetValueColorByStatus(value.ExtraRedStatus, value.RedStatus, value.YellowStatus, model.FlagAbsentGoodsOneWeek)
|
||||
|
||||
storeAlertAdvanced.StandardFinishTimeSelfDelivery.Value = fmt.Sprintf("%d%%", value.StandardFinishTimeSelfDelivery)
|
||||
storeAlertAdvanced.StandardFinishTimeSelfDelivery.Color = GetValueColorByStatus(value.ExtraRedStatus, value.RedStatus, value.YellowStatus, model.FlagStandardFinishTimeSelfDelivery)
|
||||
|
||||
storeAlertAdvanced.StandardPickUpTimeDaDa.Value = fmt.Sprintf("%d%%", value.StandardPickUpTimeDaDa)
|
||||
storeAlertAdvanced.StandardPickUpTimeDaDa.Color = GetValueColorByStatus(value.ExtraRedStatus, value.RedStatus, value.YellowStatus, model.FlagStandardPickUpTimeDaDa)
|
||||
|
||||
if value.NoOrderInMonth == 1 {
|
||||
storeAlertAdvanced.NoOrderInMonth.Value = "是"
|
||||
} else {
|
||||
storeAlertAdvanced.NoOrderInMonth.Value = "否"
|
||||
}
|
||||
storeAlertAdvanced.NoOrderInMonth.Color = GetValueColorByStatus(value.ExtraRedStatus, value.RedStatus, value.YellowStatus, model.FlagNoOrderInMonth)
|
||||
|
||||
storeAlertAdvanced.RiskOrderCount.Value = utils.Int2Str(value.RiskOrderCount)
|
||||
storeAlertAdvanced.RiskOrderCount.Color = GetValueColorByStatus(value.ExtraRedStatus, value.RedStatus, value.YellowStatus, model.FlagRiskOrderCount)
|
||||
|
||||
storeAlertAdvancedList = append(storeAlertAdvancedList, storeAlertAdvanced)
|
||||
}
|
||||
storeAlertData.TotalCount = len(storeAlertList)
|
||||
storeAlertData.StoreAlertList = storeAlertAdvancedList
|
||||
}
|
||||
|
||||
return storeAlertData, err
|
||||
}
|
||||
@@ -1,882 +0,0 @@
|
||||
package misc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"reflect"
|
||||
"sort"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/baseapi"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxstore/cms"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/refutil"
|
||||
)
|
||||
|
||||
const (
|
||||
EnableScheduleScoreStore = true
|
||||
ParallelCount = 1
|
||||
|
||||
GoldMedalScore = 90
|
||||
SilverMedalScore = 80
|
||||
BronzeMedalScore = 70
|
||||
GoldMedalLevel = 1
|
||||
SilverMedalLevel = 2
|
||||
BronzeMedalLevel = 3
|
||||
|
||||
ItemTotalScore = 10
|
||||
|
||||
StoreOpenTimeNormalTime = 12.0 //小时
|
||||
SaleSkuNormalCount = 1000 //数量
|
||||
SaleSkuScorePerUnit = float64(ItemTotalScore) / SaleSkuNormalCount //分数
|
||||
PromotionSkuNormalCount = 20 //数量
|
||||
AveragePickupTimeNormalTime = 10.0 //分钟
|
||||
BadCommentOrderNormalRatio = 0.2 //百分比
|
||||
UnfinishOrderNormalRatio = 1.0 //百分比
|
||||
AbsentGoodsOrderNormalRatio = 1.0 //百分比
|
||||
StoreRangeGoodRadius = 2.0 //千米
|
||||
StoreRangeBadRadius = 1.0 //千米
|
||||
SaleSkuPriceRatio = 90 //千米
|
||||
SaleSkuCheckRange = 5.0 //千米
|
||||
|
||||
WeekNum = 5 //得到门店近期周的数量
|
||||
)
|
||||
|
||||
var (
|
||||
scoreStoreTimeList = []string{
|
||||
"23:00:00",
|
||||
}
|
||||
scoreStoreCheckTimeEnd = "23:30:00"
|
||||
fullVendorList = map[int]bool{
|
||||
model.VendorIDJD: true,
|
||||
model.VendorIDMTWM: true,
|
||||
model.VendorIDEBAI: true,
|
||||
}
|
||||
storeScoreFieldName = []string{
|
||||
model.FieldStoreOpenTime,
|
||||
model.FieldSaleSkuCount,
|
||||
model.FieldAveragePickupTime,
|
||||
model.FieldBadCommentOrder,
|
||||
model.FieldUnfinishOrder,
|
||||
model.FieldAbsentGoodsOrder,
|
||||
model.FieldPromotionSku,
|
||||
model.FieldFullVendor,
|
||||
model.FieldStoreRange,
|
||||
model.FieldSaleSkuPrice,
|
||||
}
|
||||
|
||||
storeScoreDataWrapper StoreScoreDataWrapper
|
||||
allStoreSkusWrapper AllStoreSkusWrapper
|
||||
scoreDate time.Time
|
||||
isScoring bool
|
||||
)
|
||||
|
||||
type AllStoreSkusWrapper struct {
|
||||
allStoreSkus map[int]map[int]int
|
||||
locker sync.RWMutex
|
||||
}
|
||||
|
||||
func (a *AllStoreSkusWrapper) InitData() {
|
||||
a.allStoreSkus = make(map[int]map[int]int)
|
||||
}
|
||||
|
||||
func (a *AllStoreSkusWrapper) ClearData() {
|
||||
a.allStoreSkus = nil
|
||||
}
|
||||
|
||||
func (a *AllStoreSkusWrapper) SetData(storeID int, skuMapData map[int]int) {
|
||||
a.locker.Lock()
|
||||
defer a.locker.Unlock()
|
||||
a.allStoreSkus[storeID] = skuMapData
|
||||
}
|
||||
|
||||
func (a *AllStoreSkusWrapper) GetData(storeID int) map[int]int {
|
||||
a.locker.RLock()
|
||||
defer a.locker.RUnlock()
|
||||
return a.allStoreSkus[storeID]
|
||||
}
|
||||
|
||||
type StoreScoreDataWrapper struct {
|
||||
storeScoreData map[int]*model.StoreScore
|
||||
dailyBadCommentOrderCount map[int]int
|
||||
dailyUnFinishOrderCount map[int]int
|
||||
dailyFinishOrderCount map[int]int
|
||||
dailyAbsentGoodsOrderCount map[int]int
|
||||
locker sync.RWMutex
|
||||
}
|
||||
|
||||
func (s *StoreScoreDataWrapper) InitData() {
|
||||
s.storeScoreData = make(map[int]*model.StoreScore)
|
||||
s.dailyBadCommentOrderCount = make(map[int]int)
|
||||
s.dailyUnFinishOrderCount = make(map[int]int)
|
||||
s.dailyFinishOrderCount = make(map[int]int)
|
||||
s.dailyAbsentGoodsOrderCount = make(map[int]int)
|
||||
}
|
||||
|
||||
func (s *StoreScoreDataWrapper) ClearData() {
|
||||
s.storeScoreData = nil
|
||||
s.dailyBadCommentOrderCount = nil
|
||||
s.dailyUnFinishOrderCount = nil
|
||||
s.dailyFinishOrderCount = nil
|
||||
s.dailyAbsentGoodsOrderCount = nil
|
||||
}
|
||||
|
||||
func (s *StoreScoreDataWrapper) SetData(storeID int, valueName string, value int) {
|
||||
s.locker.Lock()
|
||||
defer s.locker.Unlock()
|
||||
data := s.storeScoreData[storeID]
|
||||
if data == nil {
|
||||
data = &model.StoreScore{}
|
||||
data.StoreID = storeID
|
||||
data.ScoreDate = scoreDate
|
||||
s.storeScoreData[storeID] = data
|
||||
}
|
||||
valueInfo := reflect.ValueOf(data).Elem()
|
||||
valueInfo.FieldByName(valueName).SetInt(int64(value))
|
||||
}
|
||||
|
||||
func (s *StoreScoreDataWrapper) SetDailyBadCommentOrderCount(storeCountList []*model.StoreCount) {
|
||||
s.locker.Lock()
|
||||
defer s.locker.Unlock()
|
||||
for _, value := range storeCountList {
|
||||
s.dailyBadCommentOrderCount[value.StoreID] = value.Count
|
||||
}
|
||||
}
|
||||
|
||||
func (s *StoreScoreDataWrapper) GetDailyBadCommentOrderCount(storeID int) int {
|
||||
s.locker.RLock()
|
||||
defer s.locker.RUnlock()
|
||||
if count, ok := s.dailyBadCommentOrderCount[storeID]; ok {
|
||||
return count
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func (s *StoreScoreDataWrapper) SetDailyUnFinishOrderCount(storeCountList []*model.StoreCount) {
|
||||
for _, value := range storeCountList {
|
||||
s.dailyUnFinishOrderCount[value.StoreID] = value.Count
|
||||
}
|
||||
}
|
||||
|
||||
func (s *StoreScoreDataWrapper) GetDailyUnFinishOrderCount(storeID int) int {
|
||||
s.locker.RLock()
|
||||
defer s.locker.RUnlock()
|
||||
if count, ok := s.dailyUnFinishOrderCount[storeID]; ok {
|
||||
return count
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func (s *StoreScoreDataWrapper) SetDailyFinishOrderCount(storeCountList []*model.StoreCount) {
|
||||
for _, value := range storeCountList {
|
||||
s.dailyFinishOrderCount[value.StoreID] = value.Count
|
||||
}
|
||||
}
|
||||
|
||||
func (s *StoreScoreDataWrapper) GetDailyFinishOrderCount(storeID int) int {
|
||||
s.locker.RLock()
|
||||
defer s.locker.RUnlock()
|
||||
if count, ok := s.dailyFinishOrderCount[storeID]; ok {
|
||||
return count
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func (s *StoreScoreDataWrapper) SetDailyAbsentGoodsOrderCount(storeCountList []*model.StoreCount) {
|
||||
for _, value := range storeCountList {
|
||||
s.dailyAbsentGoodsOrderCount[value.StoreID] = value.Count
|
||||
}
|
||||
}
|
||||
|
||||
func (s *StoreScoreDataWrapper) GetDailyAbsentGoodsOrderCount(storeID int) int {
|
||||
s.locker.RLock()
|
||||
defer s.locker.RUnlock()
|
||||
if count, ok := s.dailyAbsentGoodsOrderCount[storeID]; ok {
|
||||
return count
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func (s *StoreScoreDataWrapper) InsertStoreScore() {
|
||||
for _, value := range s.storeScoreData {
|
||||
dao.InsertStoreScore(value)
|
||||
}
|
||||
}
|
||||
|
||||
//得到所有门店的可售商品(优化内存,只存商品的价格)
|
||||
func GetAllStoreSkus(ctx *jxcontext.Context, parentTask tasksch.ITask, storeList []*cms.StoreExt) {
|
||||
allStoreSkusWrapper.InitData()
|
||||
taskFunc := func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
storeInfo := batchItemList[0].(*cms.StoreExt)
|
||||
storeID := storeInfo.ID
|
||||
if jxSkuInfoData, err2 := cms.GetStoreSkus(ctx, storeID, []int{}, true, "", true, false, map[string]interface{}{}, 0, -1); jxSkuInfoData != nil {
|
||||
jxSkuPriceMapData := make(map[int]int)
|
||||
for _, value := range jxSkuInfoData.SkuNames {
|
||||
for _, skuInfo := range value.Skus {
|
||||
saleStatus := jxutils.MergeSkuStatus(skuInfo.SkuStatus, skuInfo.StoreSkuStatus)
|
||||
if saleStatus == model.SkuStatusNormal {
|
||||
jxSkuPriceMapData[skuInfo.SkuID] = skuInfo.BindPrice
|
||||
}
|
||||
}
|
||||
}
|
||||
allStoreSkusWrapper.SetData(storeID, jxSkuPriceMapData)
|
||||
} else {
|
||||
globals.SugarLogger.Warnf("store_score.GetAllStoreSkus %d return empty, err:%v", storeID, err2)
|
||||
}
|
||||
return retVal, err
|
||||
}
|
||||
taskParallel := tasksch.NewParallelTask("得到所有门店商品", tasksch.NewParallelConfig().SetParallelCount(ParallelCount), ctx, taskFunc, storeList)
|
||||
tasksch.HandleTask(taskParallel, parentTask, true).Run()
|
||||
taskParallel.GetResult(0)
|
||||
}
|
||||
|
||||
func GetOpenTime(opTimeList []int16) (opTime float64) {
|
||||
opTime = 0
|
||||
for index, _ := range opTimeList {
|
||||
if index%2 == 1 {
|
||||
endTime := opTimeList[index]
|
||||
startTime := opTimeList[index-1]
|
||||
diffHour := float64(endTime/100 - startTime/100)
|
||||
diffMin := float64(endTime%100-startTime%100) / 60
|
||||
opTime += diffHour + diffMin
|
||||
}
|
||||
}
|
||||
return opTime
|
||||
}
|
||||
|
||||
//营业时间12小时及以上满分,总分10分,每少一个小时扣1分
|
||||
func ScoreStoreOpenTime(storeInfo *cms.StoreExt) {
|
||||
storeID := storeInfo.ID
|
||||
storeStatus := storeInfo.Status
|
||||
isStoreOpen := storeStatus == model.StoreStatusOpened
|
||||
finalScore := 0
|
||||
if isStoreOpen {
|
||||
for _, storeMap := range storeInfo.StoreMaps {
|
||||
isSyncStoreSku := storeMap.IsSync
|
||||
vendorStoreStatus := storeMap.Status
|
||||
isVendorStoreOpen := vendorStoreStatus == model.StoreStatusOpened
|
||||
opTimeList := storeInfo.GetOpTimeList()
|
||||
if len(opTimeList) > 0 && isStoreOpen && isVendorStoreOpen && isSyncStoreSku != 0 {
|
||||
opTime := GetOpenTime(opTimeList)
|
||||
if opTime >= StoreOpenTimeNormalTime {
|
||||
finalScore = ItemTotalScore
|
||||
} else {
|
||||
decScore := int(math.Round(StoreOpenTimeNormalTime - opTime))
|
||||
finalScore = ItemTotalScore - decScore
|
||||
if finalScore < 0 {
|
||||
finalScore = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
storeScoreDataWrapper.SetData(storeID, model.FieldStoreOpenTime, finalScore)
|
||||
}
|
||||
|
||||
//可售商品数量大于1000,总分10分,按比例扣
|
||||
func ScoreSaleSkuCount(storeInfo *cms.StoreExt) {
|
||||
storeID := storeInfo.ID
|
||||
skusMapData := allStoreSkusWrapper.GetData(storeID)
|
||||
finalScore := 0
|
||||
if len(skusMapData) > 0 {
|
||||
saleSkuCount := len(skusMapData)
|
||||
finalScore = int(math.Round(float64(saleSkuCount) * SaleSkuScorePerUnit))
|
||||
if finalScore > ItemTotalScore {
|
||||
finalScore = ItemTotalScore
|
||||
}
|
||||
}
|
||||
storeScoreDataWrapper.SetData(storeID, model.FieldSaleSkuCount, finalScore)
|
||||
}
|
||||
|
||||
//平均捡货时间小于等于拣货截止时间为10分满分,每超出1分钟,减1分
|
||||
func ScoreAveragePickupTime(storeInfo *cms.StoreExt) {
|
||||
storeID := storeInfo.ID
|
||||
db := dao.GetDB()
|
||||
orderList, err := dao.GetDailyFinishOrderList(db, storeID, scoreDate)
|
||||
orderListCount := len(orderList)
|
||||
finalScore := 0
|
||||
if err == nil && orderListCount > 0 {
|
||||
totalScore := 0
|
||||
for _, value := range orderList {
|
||||
statusTime := value.StatusTime.Unix()
|
||||
pickDeadline := value.PickDeadline.Unix()
|
||||
if statusTime <= pickDeadline {
|
||||
totalScore += ItemTotalScore
|
||||
} else {
|
||||
decScore := int(math.Round(float64(statusTime-pickDeadline) / 60))
|
||||
tempScore := ItemTotalScore - decScore
|
||||
if tempScore < 0 {
|
||||
tempScore = 0
|
||||
}
|
||||
totalScore += tempScore
|
||||
}
|
||||
}
|
||||
finalScore = totalScore / orderListCount
|
||||
}
|
||||
storeScoreDataWrapper.SetData(storeID, model.FieldAveragePickupTime, finalScore)
|
||||
}
|
||||
|
||||
//差评订单和完成订单比例小于0.2%,得满分10分,每增加0.1%减1分
|
||||
func ScoreBadCommentOrder(storeInfo *cms.StoreExt) {
|
||||
storeID := storeInfo.ID
|
||||
badCommentOrderCount := storeScoreDataWrapper.GetDailyBadCommentOrderCount(storeID)
|
||||
finishOrderCount := storeScoreDataWrapper.GetDailyFinishOrderCount(storeID)
|
||||
finalScore := 0
|
||||
if finishOrderCount > 0 {
|
||||
badCommentOrderRatio := float64(badCommentOrderCount) * 100 / float64(finishOrderCount)
|
||||
if badCommentOrderRatio <= BadCommentOrderNormalRatio {
|
||||
finalScore = ItemTotalScore
|
||||
} else {
|
||||
decScore := int(math.Round((badCommentOrderRatio - BadCommentOrderNormalRatio) / 0.1))
|
||||
finalScore = ItemTotalScore - decScore
|
||||
if finalScore < 0 {
|
||||
finalScore = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
storeScoreDataWrapper.SetData(storeID, model.FieldBadCommentOrder, finalScore)
|
||||
}
|
||||
|
||||
//未完成订单和完成订单比小于1%,得满分10分,比例每增加5%,分数减1
|
||||
func ScoreUnfinishOrder(storeInfo *cms.StoreExt) {
|
||||
storeID := storeInfo.ID
|
||||
unFinishOrderCount := storeScoreDataWrapper.GetDailyUnFinishOrderCount(storeID)
|
||||
finishOrderCount := storeScoreDataWrapper.GetDailyFinishOrderCount(storeID)
|
||||
finalScore := 0
|
||||
if finishOrderCount > 0 {
|
||||
unfinishOrderRatio := float64(unFinishOrderCount) * 100 / float64(finishOrderCount)
|
||||
if unfinishOrderRatio <= UnfinishOrderNormalRatio {
|
||||
finalScore = ItemTotalScore
|
||||
} else {
|
||||
decScore := int(math.Round((unfinishOrderRatio - UnfinishOrderNormalRatio) / 5))
|
||||
finalScore = ItemTotalScore - decScore
|
||||
if finalScore < 0 {
|
||||
finalScore = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
storeScoreDataWrapper.SetData(storeID, model.FieldUnfinishOrder, finalScore)
|
||||
}
|
||||
|
||||
//缺货订单和完成订单比小于1%得10分,比例每增加0.1%减1分
|
||||
func ScoreAbsentGoodsOrder(storeInfo *cms.StoreExt) {
|
||||
storeID := storeInfo.ID
|
||||
absentGoodsOrderCount := storeScoreDataWrapper.GetDailyAbsentGoodsOrderCount(storeID)
|
||||
finishOrderCount := storeScoreDataWrapper.GetDailyFinishOrderCount(storeID)
|
||||
finalScore := 0
|
||||
if finishOrderCount > 0 {
|
||||
absentGoodsOrderRatio := float64(absentGoodsOrderCount) * 100 / float64(finishOrderCount)
|
||||
if absentGoodsOrderRatio <= AbsentGoodsOrderNormalRatio {
|
||||
finalScore = ItemTotalScore
|
||||
} else {
|
||||
decScore := int(math.Round((absentGoodsOrderRatio - AbsentGoodsOrderNormalRatio) / 0.1))
|
||||
finalScore = ItemTotalScore - decScore
|
||||
if finalScore < 0 {
|
||||
finalScore = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
storeScoreDataWrapper.SetData(storeID, model.FieldAbsentGoodsOrder, finalScore)
|
||||
}
|
||||
|
||||
//促销品数量20个以上为满分10分,每少2个扣1分
|
||||
func ScorePromotionSku(storeInfo *cms.StoreExt) {
|
||||
storeID := storeInfo.ID
|
||||
db := dao.GetDB()
|
||||
beginTime := time.Now()
|
||||
endTime := time.Now()
|
||||
actStoreSkuList, err := dao.GetEffectiveActStoreSkuInfo(db, -1, nil, model.ActTypeAll, []int{storeID}, nil, beginTime, endTime)
|
||||
finalScore := 0
|
||||
if err == nil && len(actStoreSkuList) > 0 {
|
||||
actStoreSkuMap := make(map[int]int)
|
||||
for _, value := range actStoreSkuList {
|
||||
if value.Type != model.ActSkuFake {
|
||||
actStoreSkuMap[value.SkuID] = 1
|
||||
}
|
||||
}
|
||||
promotionSkuCount := len(actStoreSkuMap)
|
||||
if promotionSkuCount >= PromotionSkuNormalCount {
|
||||
finalScore = ItemTotalScore
|
||||
} else {
|
||||
decScore := (PromotionSkuNormalCount - promotionSkuCount) / 2
|
||||
finalScore = ItemTotalScore - decScore
|
||||
if finalScore < 0 {
|
||||
finalScore = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
storeScoreDataWrapper.SetData(storeID, model.FieldPromotionSku, finalScore)
|
||||
}
|
||||
|
||||
//经营全平台满分10分,每少一个平台扣2分(一个平台没有得0分)
|
||||
func ScoreFullVendor(storeInfo *cms.StoreExt) {
|
||||
fullVendorCount := len(fullVendorList)
|
||||
finalScore := 0
|
||||
storeID := storeInfo.ID
|
||||
storeStatus := storeInfo.Status
|
||||
isStoreOpen := storeStatus == model.StoreStatusOpened
|
||||
count := 0
|
||||
for _, storeMap := range storeInfo.StoreMaps {
|
||||
isSyncStoreSku := storeMap.IsSync
|
||||
vendorStoreStatus := storeMap.Status
|
||||
isVendorStoreOpen := vendorStoreStatus == model.StoreStatusOpened
|
||||
opTimeList := storeInfo.GetOpTimeList()
|
||||
if len(opTimeList) > 0 && isStoreOpen && isVendorStoreOpen && isSyncStoreSku != 0 {
|
||||
count++
|
||||
}
|
||||
}
|
||||
if count > 0 {
|
||||
if count == fullVendorCount {
|
||||
finalScore = ItemTotalScore
|
||||
} else {
|
||||
decScore := (fullVendorCount - count) * 2
|
||||
finalScore = ItemTotalScore - decScore
|
||||
}
|
||||
}
|
||||
storeScoreDataWrapper.SetData(storeID, model.FieldFullVendor, finalScore)
|
||||
}
|
||||
|
||||
//经营范围面积大于半径2km的圆得满分10分,低于1km得分0
|
||||
func ScoreStoreRange(storeInfo *cms.StoreExt) {
|
||||
finalScore := 0
|
||||
storeID := storeInfo.ID
|
||||
if storeInfo.DeliveryRangeType == model.DeliveryRangeTypePolygon {
|
||||
if storeInfo.DeliveryRange != "" {
|
||||
points := jxutils.CoordinateStr2Points(storeInfo.DeliveryRange)
|
||||
area := jxutils.CalcPolygonAreaAutonavi(points)
|
||||
goodArea := math.Pi * StoreRangeGoodRadius * StoreRangeGoodRadius
|
||||
badArea := math.Pi * StoreRangeBadRadius * StoreRangeBadRadius
|
||||
if area >= goodArea {
|
||||
finalScore = ItemTotalScore
|
||||
} else if area <= badArea {
|
||||
finalScore = 0
|
||||
} else {
|
||||
diff := goodArea - area
|
||||
ratio := float64(ItemTotalScore) / (goodArea - badArea)
|
||||
finalScore = ItemTotalScore - int(math.Round(diff*ratio))
|
||||
}
|
||||
}
|
||||
} else if storeInfo.DeliveryRangeType == model.DeliveryRangeTypeRadius {
|
||||
deliveryRadius := utils.Str2Float64WithDefault(storeInfo.DeliveryRange, 0) / 1000
|
||||
if deliveryRadius >= StoreRangeGoodRadius {
|
||||
finalScore = ItemTotalScore
|
||||
} else if deliveryRadius <= StoreRangeBadRadius {
|
||||
finalScore = 0
|
||||
} else {
|
||||
diff := StoreRangeGoodRadius - deliveryRadius
|
||||
ratio := float64(ItemTotalScore) / (StoreRangeGoodRadius - StoreRangeBadRadius)
|
||||
finalScore = ItemTotalScore - int(math.Round(diff*ratio))
|
||||
}
|
||||
}
|
||||
if finalScore < 0 {
|
||||
globals.SugarLogger.Infof("ScoreStoreRange abnormal finalScore:%d, storeInfo:%s", finalScore, utils.Format4Output(storeInfo, true))
|
||||
finalScore = 0
|
||||
} else if finalScore > ItemTotalScore {
|
||||
globals.SugarLogger.Infof("ScoreStoreRange abnormal finalScore:%d, storeInfo:%s", finalScore, utils.Format4Output(storeInfo, true))
|
||||
finalScore = ItemTotalScore
|
||||
}
|
||||
storeScoreDataWrapper.SetData(storeID, model.FieldStoreRange, finalScore)
|
||||
}
|
||||
|
||||
//得到距离某个门店多少KM内的所有门店信息
|
||||
func GetRangeStoreList(storeID int, lng, lat, checkRange float64, storeList []*cms.StoreExt) (outStoreList []*cms.StoreExt) {
|
||||
for _, storeInfo := range storeList {
|
||||
if storeInfo.ID == storeID {
|
||||
outStoreList = append(outStoreList, storeInfo)
|
||||
} else {
|
||||
distance := jxutils.EarthDistance(lng, lat, storeInfo.FloatLng, storeInfo.FloatLat)
|
||||
if distance <= checkRange {
|
||||
outStoreList = append(outStoreList, storeInfo)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return outStoreList
|
||||
}
|
||||
|
||||
//得到给定门店列表里的同一SkuID商品的平均价格
|
||||
func GetStoreSkusAveragePrice(storeList []*cms.StoreExt) map[int]int {
|
||||
skusTotalPrice := make(map[int]int)
|
||||
skusCount := make(map[int]int)
|
||||
skusAveragePrice := make(map[int]int)
|
||||
for _, storeInfo := range storeList {
|
||||
storeID := storeInfo.ID
|
||||
storeSkuMapData := allStoreSkusWrapper.GetData(storeID)
|
||||
for skuID, skuPrice := range storeSkuMapData {
|
||||
skusTotalPrice[skuID] += skuPrice
|
||||
skusCount[skuID]++
|
||||
}
|
||||
}
|
||||
for id, totalPrice := range skusTotalPrice {
|
||||
skusAveragePrice[id] = int(math.Round(float64(totalPrice) / float64(skusCount[id])))
|
||||
}
|
||||
return skusAveragePrice
|
||||
}
|
||||
|
||||
func GetSkusCountLessEqualAvgPrice(storeID int, skusAveragePrice map[int]int) (count int) {
|
||||
storeSkuMapData := allStoreSkusWrapper.GetData(storeID)
|
||||
for skuID, skuPrice := range storeSkuMapData {
|
||||
skuAvgPrice := skusAveragePrice[skuID]
|
||||
if skuPrice <= skuAvgPrice {
|
||||
count++
|
||||
}
|
||||
}
|
||||
|
||||
return count
|
||||
}
|
||||
|
||||
//可售商品价格在附近5km内门店比较,价格低于等于平均值的商品数占90%以上满分10分,比例每降低10%减1分,100%超标得0分
|
||||
func ScoreSaleSkuPrice(storeInfo *cms.StoreExt, storeList []*cms.StoreExt) {
|
||||
finalScore := 0
|
||||
storeID := storeInfo.ID
|
||||
totalCount := len(allStoreSkusWrapper.GetData(storeID))
|
||||
if totalCount > 0 {
|
||||
rangeStoreList := GetRangeStoreList(storeID, storeInfo.FloatLng, storeInfo.FloatLat, SaleSkuCheckRange, storeList)
|
||||
skusAveragePrice := GetStoreSkusAveragePrice(rangeStoreList)
|
||||
count := GetSkusCountLessEqualAvgPrice(storeID, skusAveragePrice)
|
||||
if count > 0 {
|
||||
ratio := int(math.Round(float64(count) * 100 / float64(totalCount)))
|
||||
if ratio >= SaleSkuPriceRatio {
|
||||
finalScore = ItemTotalScore
|
||||
} else {
|
||||
decScore := (SaleSkuPriceRatio - ratio) / 10
|
||||
finalScore = ItemTotalScore - decScore
|
||||
if finalScore < 0 {
|
||||
finalScore = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
storeScoreDataWrapper.SetData(storeID, model.FieldSaleSkuPrice, finalScore)
|
||||
}
|
||||
|
||||
func GetFilterStoreListEx(storeList []*cms.StoreExt, storeIDMap map[int]int) (outStoreList []*cms.StoreExt) {
|
||||
for _, storeInfo := range storeList {
|
||||
storeID := storeInfo.ID
|
||||
if len(storeIDMap) > 0 {
|
||||
if _, ok := storeIDMap[storeID]; !ok {
|
||||
continue
|
||||
}
|
||||
}
|
||||
var tempStoreMaps []*model.StoreMap
|
||||
for _, vendorStoreInfo := range storeInfo.StoreMaps {
|
||||
vendorID := vendorStoreInfo.VendorID
|
||||
if _, ok := fullVendorList[vendorID]; !ok {
|
||||
continue
|
||||
}
|
||||
tempStoreMaps = append(tempStoreMaps, vendorStoreInfo)
|
||||
}
|
||||
if len(tempStoreMaps) > 0 {
|
||||
storeInfo.StoreMaps = tempStoreMaps
|
||||
outStoreList = append(outStoreList, storeInfo)
|
||||
}
|
||||
}
|
||||
|
||||
return outStoreList
|
||||
}
|
||||
|
||||
func ScoreStore(ctx *jxcontext.Context, storeIDList []int) (retVal interface{}, err error) {
|
||||
isScoring = true
|
||||
scoreDate = utils.GetCurDate()
|
||||
var storeList []*cms.StoreExt
|
||||
taskCount := 5
|
||||
taskSeqFunc := func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
|
||||
switch step {
|
||||
case 0:
|
||||
baseapi.SugarLogger.Debugf("ScoreStore step0 begin")
|
||||
storeScoreDataWrapper.InitData()
|
||||
storeList, err = GetStoreList(ctx)
|
||||
storeIDMap := jxutils.IntList2Map(storeIDList)
|
||||
storeList = GetFilterStoreListEx(storeList, storeIDMap)
|
||||
baseapi.SugarLogger.Debugf("ScoreStore step0 end")
|
||||
case 1:
|
||||
baseapi.SugarLogger.Debugf("ScoreStore step1 begin")
|
||||
GetAllStoreSkus(ctx, task, storeList)
|
||||
baseapi.SugarLogger.Debugf("ScoreStore step1 end")
|
||||
case 2:
|
||||
baseapi.SugarLogger.Debugf("ScoreStore step2 begin")
|
||||
db := dao.GetDB()
|
||||
storeCountList, err := dao.GetDailyBadCommentOrderCount(db, scoreDate)
|
||||
if err == nil {
|
||||
storeScoreDataWrapper.SetDailyBadCommentOrderCount(storeCountList)
|
||||
} else {
|
||||
baseapi.SugarLogger.Debugf("ScoreStore GetDailyBadCommentOrderCount %v", err)
|
||||
}
|
||||
storeCountList, err = dao.GetDailyUnFinishOrderCount(db, scoreDate)
|
||||
if err == nil {
|
||||
storeScoreDataWrapper.SetDailyUnFinishOrderCount(storeCountList)
|
||||
} else {
|
||||
baseapi.SugarLogger.Debugf("ScoreStore GetDailyUnFinishOrderCount %v", err)
|
||||
}
|
||||
storeCountList, err = dao.GetDailyFinishOrderCount(db, scoreDate)
|
||||
if err == nil {
|
||||
storeScoreDataWrapper.SetDailyFinishOrderCount(storeCountList)
|
||||
} else {
|
||||
baseapi.SugarLogger.Debugf("ScoreStore GetDailyFinishOrderCount %v", err)
|
||||
}
|
||||
storeCountList, err = dao.GetDailyAbsentGoodsOrderCount(db, scoreDate)
|
||||
if err == nil {
|
||||
storeScoreDataWrapper.SetDailyAbsentGoodsOrderCount(storeCountList)
|
||||
} else {
|
||||
baseapi.SugarLogger.Debugf("ScoreStore GetDailyAbsentGoodsOrderCount %v", err)
|
||||
}
|
||||
baseapi.SugarLogger.Debugf("ScoreStore step2 end")
|
||||
case 3:
|
||||
baseapi.SugarLogger.Debugf("ScoreStore step3 begin")
|
||||
taskFunc := func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
storeInfo := batchItemList[0].(*cms.StoreExt)
|
||||
storeID := storeInfo.ID
|
||||
baseapi.SugarLogger.Debugf("Begin store id:%d", storeID)
|
||||
ScoreStoreOpenTime(storeInfo)
|
||||
ScoreSaleSkuCount(storeInfo)
|
||||
ScoreAveragePickupTime(storeInfo)
|
||||
ScoreBadCommentOrder(storeInfo)
|
||||
ScoreUnfinishOrder(storeInfo)
|
||||
ScoreAbsentGoodsOrder(storeInfo)
|
||||
ScorePromotionSku(storeInfo)
|
||||
ScoreFullVendor(storeInfo)
|
||||
ScoreStoreRange(storeInfo)
|
||||
ScoreSaleSkuPrice(storeInfo, storeList)
|
||||
baseapi.SugarLogger.Debugf("End store id:%d", storeID)
|
||||
return retVal, err
|
||||
}
|
||||
taskParallel := tasksch.NewParallelTask("计算门店得分", tasksch.NewParallelConfig().SetParallelCount(ParallelCount), ctx, taskFunc, storeList)
|
||||
tasksch.HandleTask(taskParallel, task, true).Run()
|
||||
taskParallel.GetResult(0)
|
||||
_, err = taskParallel.GetResult(0)
|
||||
if err != nil {
|
||||
baseapi.SugarLogger.Debugf("ScoreStore taskParallel error:%v", err)
|
||||
}
|
||||
baseapi.SugarLogger.Debugf("ScoreStore step3 end")
|
||||
case 4:
|
||||
baseapi.SugarLogger.Debugf("ScoreStore step4 begin")
|
||||
storeScoreDataWrapper.InsertStoreScore()
|
||||
storeScoreDataWrapper.ClearData()
|
||||
allStoreSkusWrapper.ClearData()
|
||||
baseapi.SugarLogger.Debugf("ScoreStore step4 end")
|
||||
isScoring = false
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
taskSeq := tasksch.NewSeqTask("门店评分-序列任务", ctx, taskSeqFunc, taskCount)
|
||||
tasksch.HandleTask(taskSeq, nil, true).Run()
|
||||
|
||||
return retVal, err
|
||||
}
|
||||
|
||||
func ScheduleScoreStore() {
|
||||
if EnableScheduleScoreStore {
|
||||
ScheduleTimerFunc("ScheduleScoreStore", func() {
|
||||
if !isScoring {
|
||||
ScoreStore(jxcontext.AdminCtx, nil)
|
||||
}
|
||||
}, scoreStoreTimeList)
|
||||
CheckScoreStore()
|
||||
}
|
||||
}
|
||||
|
||||
func CheckScoreStore() {
|
||||
if !isScoring {
|
||||
curTime := time.Now()
|
||||
checkTimeStr1 := fmt.Sprintf("%s %s", utils.Time2DateStr(curTime), scoreStoreTimeList[0])
|
||||
checkTime1 := utils.Str2Time(checkTimeStr1)
|
||||
checkTimeStr2 := fmt.Sprintf("%s %s", utils.Time2DateStr(curTime), scoreStoreCheckTimeEnd)
|
||||
checkTime2 := utils.Str2Time(checkTimeStr2)
|
||||
if curTime.Unix() >= checkTime1.Unix() && curTime.Unix() <= checkTime2.Unix() {
|
||||
db := dao.GetDB()
|
||||
hasStoreScoreData, err := dao.CheckHasStoreScoreData(db, curTime)
|
||||
if err == nil && !hasStoreScoreData {
|
||||
ScoreStore(jxcontext.AdminCtx, nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Time2Week(t time.Time) int {
|
||||
yearDay := t.YearDay()
|
||||
yearFirstDay := t.AddDate(0, 0, -yearDay+1)
|
||||
firstDayInWeek := int(yearFirstDay.Weekday())
|
||||
|
||||
firstWeekDays := 1
|
||||
if firstDayInWeek != 0 {
|
||||
firstWeekDays = 7 - firstDayInWeek + 1
|
||||
}
|
||||
var week int
|
||||
if yearDay <= firstWeekDays {
|
||||
week = 1
|
||||
} else {
|
||||
tempWeek := (float64(yearDay) - float64(firstWeekDays)) / float64(7)
|
||||
week = int(math.Ceil(tempWeek)) + 1
|
||||
}
|
||||
|
||||
return week
|
||||
}
|
||||
|
||||
func SplitToSingleWeekDataList(storeScoreList []*model.StoreScoreEx) (weekDataList [][]*model.StoreScoreEx) {
|
||||
singleWeekData := []*model.StoreScoreEx{}
|
||||
weekIndex := 0
|
||||
for _, value := range storeScoreList {
|
||||
if weekIndex == 0 {
|
||||
weekIndex = Time2Week(value.ScoreDate)
|
||||
}
|
||||
if weekIndex == Time2Week(value.ScoreDate) {
|
||||
singleWeekData = append(singleWeekData, value)
|
||||
} else {
|
||||
weekDataList = append(weekDataList, singleWeekData)
|
||||
singleWeekData = []*model.StoreScoreEx{}
|
||||
weekIndex = 0
|
||||
singleWeekData = append(singleWeekData, value)
|
||||
}
|
||||
}
|
||||
if len(singleWeekData) > 0 {
|
||||
weekDataList = append(weekDataList, singleWeekData)
|
||||
}
|
||||
|
||||
return weekDataList
|
||||
}
|
||||
|
||||
func GetStoreScoreLevel(score int) int {
|
||||
level := 0
|
||||
if score >= GoldMedalScore {
|
||||
level = GoldMedalLevel
|
||||
} else if score >= SilverMedalScore {
|
||||
level = SilverMedalLevel
|
||||
} else if score >= BronzeMedalScore {
|
||||
level = BronzeMedalLevel
|
||||
}
|
||||
|
||||
return level
|
||||
}
|
||||
|
||||
func GetWeeklyStoreScore(storeID, weekIndexParam int) (outWeeklyStoreScoreDataList []*model.WeeklyStoreScore, err error) {
|
||||
db := dao.GetDB()
|
||||
storeScoreList, err := dao.GetWeeklyStoreScoreList(db, storeID, WeekNum)
|
||||
if err == nil && len(storeScoreList) > 0 {
|
||||
weeklyStoreScoreDataList := []*model.WeeklyStoreScore{}
|
||||
weekDataList := SplitToSingleWeekDataList(storeScoreList)
|
||||
for weekIndex, weekData := range weekDataList {
|
||||
weeklyData := &model.WeeklyStoreScore{}
|
||||
weeklyData.ID = weekIndex
|
||||
weeklyData.ItemTotalScore = ItemTotalScore
|
||||
weeklyData.StoreID = storeID
|
||||
weeklyStoreScoreDataList = append(weeklyStoreScoreDataList, weeklyData)
|
||||
weekDataCount := len(weekData)
|
||||
for dayIndex, dayData := range weekData {
|
||||
for _, fieldName := range storeScoreFieldName {
|
||||
srcFieldValue := refutil.GetObjFieldByName(dayData, fieldName).(int)
|
||||
destFieldValue := refutil.GetObjFieldByName(weeklyData, fieldName).(int)
|
||||
refutil.SetObjFieldByName(weeklyData, fieldName, destFieldValue+srcFieldValue)
|
||||
}
|
||||
if weekDataCount == 1 {
|
||||
weeklyData.BeginTime = dayData.ScoreDate
|
||||
weeklyData.EndTime = dayData.ScoreDate
|
||||
} else {
|
||||
if dayIndex == 0 {
|
||||
weeklyData.EndTime = dayData.ScoreDate
|
||||
} else if dayIndex == weekDataCount-1 {
|
||||
weeklyData.BeginTime = dayData.ScoreDate
|
||||
}
|
||||
}
|
||||
weeklyData.StoreName = dayData.StoreName
|
||||
}
|
||||
for _, fieldName := range storeScoreFieldName {
|
||||
destFieldValue := refutil.GetObjFieldByName(weeklyData, fieldName).(int)
|
||||
refutil.SetObjFieldByName(weeklyData, fieldName, int(math.Round(float64(destFieldValue)/float64(weekDataCount))))
|
||||
}
|
||||
for _, fieldName := range storeScoreFieldName {
|
||||
srcFieldValue := refutil.GetObjFieldByName(weeklyData, fieldName).(int)
|
||||
destFieldValue := refutil.GetObjFieldByName(weeklyData, model.FieldTotalScore).(int)
|
||||
refutil.SetObjFieldByName(weeklyData, model.FieldTotalScore, destFieldValue+srcFieldValue)
|
||||
}
|
||||
weeklyData.Level = GetStoreScoreLevel(weeklyData.TotalScore)
|
||||
}
|
||||
if weekIndexParam == -1 {
|
||||
outWeeklyStoreScoreDataList = weeklyStoreScoreDataList
|
||||
} else {
|
||||
fmt.Println("testss", utils.Format4Output(weeklyStoreScoreDataList, false))
|
||||
outWeeklyStoreScoreDataList = []*model.WeeklyStoreScore{weeklyStoreScoreDataList[weekIndexParam]}
|
||||
}
|
||||
}
|
||||
|
||||
return outWeeklyStoreScoreDataList, err
|
||||
}
|
||||
|
||||
func GetStoreTotalScoreList(storeIDList []int, cityCode int, keyWord string, beginTime, endTime time.Time, isDesc bool, checkScoreLow, checkScoreHigh, offset, pageSize int) (storeTotalScoreEx model.StoreTotalScoreEx, err error) {
|
||||
db := dao.GetDB()
|
||||
storeTotalScoreMapData := make(map[int]*model.StoreTotalScore)
|
||||
storeTotalScoreList, err := dao.GetStoreTotalScoreList(db, storeIDList, cityCode, keyWord, beginTime, endTime)
|
||||
var filterStoreTotalScoreList []*model.StoreTotalScore
|
||||
if err == nil && len(storeTotalScoreList) > 0 {
|
||||
countDayNum := make(map[int]int)
|
||||
for _, value := range storeTotalScoreList {
|
||||
storeID := value.StoreID
|
||||
if storeTotalScoreMapData[storeID] == nil {
|
||||
storeTotalScore := &model.StoreTotalScore{}
|
||||
storeTotalScore.StoreID = value.StoreID
|
||||
storeTotalScore.StoreName = value.StoreName
|
||||
storeTotalScore.CityName = value.CityName
|
||||
storeTotalScoreMapData[storeID] = storeTotalScore
|
||||
}
|
||||
storeTotalScore := storeTotalScoreMapData[storeID]
|
||||
storeTotalScore.StoreScore += value.StoreScore
|
||||
countDayNum[storeID]++
|
||||
}
|
||||
for storeID, value := range storeTotalScoreMapData {
|
||||
value.StoreScore = int(math.Round(float64(value.StoreScore) / float64(countDayNum[storeID])))
|
||||
needAdd := true
|
||||
if checkScoreLow > 0 && value.StoreScore < checkScoreLow {
|
||||
needAdd = false
|
||||
}
|
||||
if checkScoreHigh > 0 && value.StoreScore > checkScoreHigh {
|
||||
needAdd = false
|
||||
}
|
||||
if needAdd {
|
||||
filterStoreTotalScoreList = append(filterStoreTotalScoreList, value)
|
||||
}
|
||||
}
|
||||
if isDesc {
|
||||
sort.Slice(filterStoreTotalScoreList, func(i, j int) bool {
|
||||
data1 := filterStoreTotalScoreList[i]
|
||||
data2 := filterStoreTotalScoreList[j]
|
||||
if data1.StoreScore == data2.StoreScore {
|
||||
return data1.StoreID < data2.StoreID
|
||||
} else {
|
||||
return data1.StoreScore > data2.StoreScore
|
||||
}
|
||||
})
|
||||
} else {
|
||||
sort.Slice(filterStoreTotalScoreList, func(i, j int) bool {
|
||||
data1 := filterStoreTotalScoreList[i]
|
||||
data2 := filterStoreTotalScoreList[j]
|
||||
if data1.StoreScore == data2.StoreScore {
|
||||
return data1.StoreID < data2.StoreID
|
||||
} else {
|
||||
return data1.StoreScore < data2.StoreScore
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
offset = jxutils.FormalizePageOffset(offset)
|
||||
pageSize = jxutils.FormalizePageSize(pageSize)
|
||||
var pagedStoreTotalScoreList []*model.StoreTotalScore
|
||||
for i := offset; i < offset+pageSize && i < len(filterStoreTotalScoreList); i++ {
|
||||
pagedStoreTotalScoreList = append(pagedStoreTotalScoreList, filterStoreTotalScoreList[i])
|
||||
}
|
||||
|
||||
storeTotalScoreEx.TotalCount = len(filterStoreTotalScoreList)
|
||||
storeTotalScoreEx.StoreTotalScoreList = pagedStoreTotalScoreList
|
||||
|
||||
return storeTotalScoreEx, err
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
package misc
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/globals/api2"
|
||||
"git.rosy.net.cn/jx-callback/globals/testinit"
|
||||
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/ebai"
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/elm"
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/jd"
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/mtwm"
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/weimob/wsc"
|
||||
)
|
||||
|
||||
func init() {
|
||||
testinit.Init()
|
||||
api2.Init()
|
||||
}
|
||||
|
||||
func TestScoreStore(t *testing.T) {
|
||||
ScoreStore(jxcontext.AdminCtx, []int{})
|
||||
}
|
||||
@@ -1,176 +0,0 @@
|
||||
package misc
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"sync"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/jxstore/cms"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
)
|
||||
|
||||
const (
|
||||
DayNum = 30 //请求天数
|
||||
LimitNum = 100 //最大数据限制
|
||||
)
|
||||
|
||||
func GetStoreSkuSalesInfo(ctx *jxcontext.Context, storeID int) (outStoreSkuSales []*model.StoreSkuSales, err error) {
|
||||
db := dao.GetDB()
|
||||
//得到所有门店
|
||||
storeList, err := GetStoreList(ctx)
|
||||
if err == nil {
|
||||
storeList = GetFilterStoreListEx(storeList, nil)
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
storeMapData := make(map[int]*cms.StoreExt)
|
||||
for _, value := range storeList {
|
||||
storeMapData[value.ID] = value
|
||||
}
|
||||
curStoreInfo := storeMapData[storeID]
|
||||
if curStoreInfo == nil {
|
||||
return nil, errors.New(fmt.Sprintf("未找到商店:[%d]", storeID))
|
||||
}
|
||||
cityCode := curStoreInfo.CityCode
|
||||
|
||||
//获取本市商品总销量
|
||||
citySkuSalesCntMap := make(map[int]int)
|
||||
citySkuSalesCntList, err := dao.GetSkuSalesCntList(db, -1, cityCode, DayNum, LimitNum, nil)
|
||||
citySkuIDs := []int{}
|
||||
if err == nil {
|
||||
for _, value := range citySkuSalesCntList {
|
||||
citySkuSalesCntMap[value.SkuID] = value.Count
|
||||
citySkuIDs = append(citySkuIDs, value.SkuID)
|
||||
}
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
//获取本店商品总销量
|
||||
storeSkuSalesCntMap := make(map[int]int)
|
||||
storeSkuSalesCntList, err := dao.GetSkuSalesCntList(db, storeID, cityCode, DayNum, -1, citySkuIDs)
|
||||
if err == nil {
|
||||
for _, value := range storeSkuSalesCntList {
|
||||
storeSkuSalesCntMap[value.SkuID] = value.Count
|
||||
}
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
//获取本店商品差评数量
|
||||
storeSkuBadCommentCntMap := make(map[int]int)
|
||||
storeSkuBadCommentCntList, err := dao.GetSkuBadCommentCntList(db, storeID, DayNum)
|
||||
if err == nil {
|
||||
for _, value := range storeSkuBadCommentCntList {
|
||||
storeSkuBadCommentCntMap[value.SkuID] = value.Count
|
||||
}
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
//得到当前门店商品数据
|
||||
storeSkuMapData := make(map[int]*dao.StoreSkuNameExt)
|
||||
storeSkuData, err := cms.GetStoreSkus(ctx, storeID, citySkuIDs, true, "", true, false, map[string]interface{}{}, 0, -1)
|
||||
if err == nil {
|
||||
for _, value := range storeSkuData.SkuNames {
|
||||
for _, skuInfo := range value.Skus {
|
||||
storeSkuMapData[skuInfo.SkuID] = value
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
//得到5KM内的所有门店
|
||||
rangeStoreList := GetRangeStoreList(storeID, curStoreInfo.FloatLng, curStoreInfo.FloatLat, SaleSkuCheckRange, storeList)
|
||||
|
||||
//得到5KM内的所有门店的商品的价格
|
||||
allStoreSkus := make(map[int]map[int]int)
|
||||
var locker sync.RWMutex
|
||||
taskFunc := func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
storeInfo := batchItemList[0].(*cms.StoreExt)
|
||||
storeID := storeInfo.ID
|
||||
jxSkuInfoData, err := cms.GetStoreSkus(ctx, storeID, citySkuIDs, true, "", true, false, map[string]interface{}{}, 0, -1)
|
||||
jxSkuPriceMapData := make(map[int]int)
|
||||
for _, value := range jxSkuInfoData.SkuNames {
|
||||
for _, skuInfo := range value.Skus {
|
||||
jxSkuPriceMapData[skuInfo.SkuID] = skuInfo.BindPrice
|
||||
}
|
||||
}
|
||||
locker.Lock()
|
||||
defer locker.Unlock()
|
||||
allStoreSkus[storeID] = jxSkuPriceMapData
|
||||
return retVal, err
|
||||
}
|
||||
taskParallel := tasksch.NewParallelTask("得到所有门店商品", nil, ctx, taskFunc, rangeStoreList)
|
||||
taskParallel.Run()
|
||||
_, err = taskParallel.GetResult(0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
//计算商品的平均价格
|
||||
skusTotalPrice := make(map[int]int)
|
||||
skusCount := make(map[int]int)
|
||||
skusAveragePrice := make(map[int]int)
|
||||
for _, storeInfo := range rangeStoreList {
|
||||
storeID := storeInfo.ID
|
||||
storeSkuMapData := allStoreSkus[storeID]
|
||||
for skuID, skuPrice := range storeSkuMapData {
|
||||
skusTotalPrice[skuID] += skuPrice
|
||||
skusCount[skuID]++
|
||||
}
|
||||
}
|
||||
for id, totalPrice := range skusTotalPrice {
|
||||
skusAveragePrice[id] = int(math.Round(float64(totalPrice) / float64(skusCount[id])))
|
||||
}
|
||||
|
||||
//输出商品销量统计结果
|
||||
skuAndNameMapData := make(map[int]*model.SkuAndName)
|
||||
if len(storeSkuMapData) < len(citySkuIDs) {
|
||||
skuAndNameList, err := dao.GetSkus(db, citySkuIDs, nil, nil, nil, nil)
|
||||
if err == nil {
|
||||
for _, value := range skuAndNameList {
|
||||
skuAndNameMapData[value.ID] = value
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, value := range citySkuSalesCntList {
|
||||
skuID := value.SkuID
|
||||
storeSkuSales := &model.StoreSkuSales{}
|
||||
storeSkuSales.SkuID = skuID
|
||||
storeSkuInfo := storeSkuMapData[skuID]
|
||||
skuAndNameInfo := skuAndNameMapData[skuID]
|
||||
if storeSkuInfo != nil {
|
||||
skuName := storeSkuInfo.SkuName
|
||||
skuInfo := storeSkuInfo.Skus[0]
|
||||
storeSkuSales.SkuName = jxutils.ComposeSkuName(skuName.Prefix, skuName.Name, skuInfo.Comment, skuName.Unit, skuInfo.SkuSpecQuality, skuInfo.SkuSpecUnit, 0, skuName.ExPrefix, skuName.ExPrefixBegin, skuName.ExPrefixEnd)
|
||||
storeSkuSales.SkuImage = storeSkuInfo.Img
|
||||
storeSkuSales.SkuPrice = jxutils.IntPrice2StandardCurrencyString(int64(storeSkuInfo.Skus[0].BindPrice))
|
||||
} else if skuAndNameInfo != nil {
|
||||
skuNameList, err := dao.GetSkuNames(db, []int{skuAndNameInfo.NameID}, nil, "", false)
|
||||
prefix := ""
|
||||
if err == nil && len(skuNameList) > 0 {
|
||||
storeSkuSales.SkuImage = skuNameList[0].Img
|
||||
prefix = skuNameList[0].Prefix
|
||||
}
|
||||
storeSkuSales.SkuName = jxutils.ComposeSkuName(prefix, skuAndNameInfo.Name, skuAndNameInfo.Comment, skuAndNameInfo.Unit, skuAndNameInfo.SpecQuality, skuAndNameInfo.SpecUnit, 0, skuAndNameInfo.ExPrefix, skuAndNameInfo.ExPrefixBegin, skuAndNameInfo.ExPrefixEnd)
|
||||
storeSkuSales.SkuPrice = "N/A"
|
||||
} else {
|
||||
storeSkuSales.SkuName = "N/A"
|
||||
storeSkuSales.SkuPrice = "N/A"
|
||||
}
|
||||
storeSkuSales.SkuAvgPrice = jxutils.IntPrice2StandardCurrencyString(int64(skusAveragePrice[skuID]))
|
||||
storeSkuSales.BadCommentCnt = storeSkuBadCommentCntMap[skuID]
|
||||
storeSkuSales.StoreSkuSalesCnt = storeSkuSalesCntMap[skuID]
|
||||
storeSkuSales.CitySkuSalesCnt = citySkuSalesCntMap[skuID]
|
||||
outStoreSkuSales = append(outStoreSkuSales, storeSkuSales)
|
||||
}
|
||||
|
||||
return outStoreSkuSales, err
|
||||
}
|
||||
27
business/jxstore/partner/jds/jds.go
Normal file
27
business/jxstore/partner/jds/jds.go
Normal 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
|
||||
}
|
||||
48
business/jxstore/partner/jds/union.go
Normal file
48
business/jxstore/partner/jds/union.go
Normal 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
|
||||
}
|
||||
34
business/jxstore/partner/mt/mt.go
Normal file
34
business/jxstore/partner/mt/mt.go
Normal 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
|
||||
}
|
||||
136
business/jxstore/partner/mt/union.go
Normal file
136
business/jxstore/partner/mt/union.go
Normal 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]
|
||||
}
|
||||
107
business/jxstore/partner/partner.go
Normal file
107
business/jxstore/partner/partner.go
Normal 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]
|
||||
}
|
||||
27
business/jxstore/partner/pdd/pdd.go
Normal file
27
business/jxstore/partner/pdd/pdd.go
Normal 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
|
||||
}
|
||||
280
business/jxstore/partner/pdd/union.go
Normal file
280
business/jxstore/partner/pdd/union.go
Normal 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]
|
||||
}
|
||||
27
business/jxstore/partner/taobao/taobao.go
Normal file
27
business/jxstore/partner/taobao/taobao.go
Normal 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
|
||||
}
|
||||
189
business/jxstore/partner/taobao/union.go
Normal file
189
business/jxstore/partner/taobao/union.go
Normal 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]
|
||||
}
|
||||
@@ -1,285 +0,0 @@
|
||||
package report
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
)
|
||||
|
||||
type tStoreSkuBindAndSkuName struct {
|
||||
CityCode int
|
||||
StoreID int `orm:"column(store_id)"`
|
||||
NameID int `orm:"column(name_id)"`
|
||||
UnitPrice int
|
||||
UnitPriceList []int
|
||||
}
|
||||
|
||||
func GetStatisticsReportForOrders(ctx *jxcontext.Context, storeIDs []int, fromDate string, toDate string) (statisticsReportForOrdersList []*dao.StatisticsReportForOrdersList, err error) {
|
||||
db := dao.GetDB()
|
||||
fromDateParm := utils.Str2Time(fromDate)
|
||||
toDateParm := utils.Str2Time(toDate)
|
||||
//若时间间隔大于3个月则不允许查询
|
||||
if math.Ceil(toDateParm.Sub(fromDateParm).Hours()/24) > 92 {
|
||||
return nil, errors.New(fmt.Sprintf("查询间隔时间不允许大于3个月!: 时间范围:[%v] 至 [%v]", fromDate, toDate))
|
||||
}
|
||||
statisticsReportForOrdersList, err = dao.GetStatisticsReportForOrders(db, storeIDs, fromDateParm, toDateParm)
|
||||
return statisticsReportForOrdersList, err
|
||||
}
|
||||
|
||||
func GetStatisticsReportForAfsOrders(ctx *jxcontext.Context, storeIDs []int, fromDate string, toDate string) (statisticsReportForOrdersList []*dao.StatisticsReportForOrdersList, err error) {
|
||||
db := dao.GetDB()
|
||||
fromDateParm := utils.Str2Time(fromDate)
|
||||
toDateParm := utils.Str2Time(toDate)
|
||||
//若时间间隔大于3个月则不允许查询
|
||||
if math.Ceil(toDateParm.Sub(fromDateParm).Hours()/24) > 92 {
|
||||
return nil, errors.New(fmt.Sprintf("查询间隔时间不允许大于3个月!: 时间范围:[%v] 至 [%v]", fromDate, toDate))
|
||||
}
|
||||
statisticsReportForOrdersList, err = dao.GetGetStatisticsReportForAfsOrders(db, storeIDs, fromDateParm, toDateParm)
|
||||
return statisticsReportForOrdersList, err
|
||||
}
|
||||
|
||||
func StatisticsReportForStoreSkusPrice(ctx *jxcontext.Context, cityCodes, skuIDs []int, snapDate string, offset, pageSize int) (pagedInfo *model.PagedInfo, err error) {
|
||||
var snapDateParam time.Time
|
||||
db := dao.GetDB()
|
||||
if snapDate != "" {
|
||||
snapDateParam = utils.Str2Time(snapDate)
|
||||
}
|
||||
priceReferSnapshot, totalCount, err := dao.GetPriceReferSnapshot(db, cityCodes, skuIDs, 0, snapDateParam, offset, pageSize)
|
||||
pagedInfo = &model.PagedInfo{
|
||||
Data: priceReferSnapshot,
|
||||
TotalCount: totalCount,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func BeginSavePriceRefer(ctx *jxcontext.Context, cityCodes, skuIDs []int, isAsync, isContinueWhenError bool) (hint string, err error) {
|
||||
var priceReferSnapshotList []*model.PriceReferSnapshot
|
||||
db := dao.GetDB()
|
||||
snapshotAt := utils.Time2Date(time.Now().AddDate(0, 0, -1))
|
||||
dao.DeletePriceReferHistory(db, utils.Time2Date(snapshotAt.AddDate(0, 0, -7)))
|
||||
priceReferSnapshotDelete := &model.PriceReferSnapshot{SnapshotAt: snapshotAt}
|
||||
dao.DeleteEntity(db, priceReferSnapshotDelete, "SnapshotAt")
|
||||
taskSeqFunc := func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
|
||||
switch step {
|
||||
case 0:
|
||||
priceReferSnapshot, err := dao.GetStatisticsReportForStoreSkusPrice(db, cityCodes, skuIDs)
|
||||
if len(priceReferSnapshot) > 0 {
|
||||
dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil || err != nil {
|
||||
dao.Rollback(db)
|
||||
if r != nil {
|
||||
panic(r)
|
||||
}
|
||||
}
|
||||
}()
|
||||
for _, v := range priceReferSnapshot {
|
||||
dao.WrapAddIDCULDEntity(v, ctx.GetUserName())
|
||||
v.SnapshotAt = snapshotAt
|
||||
}
|
||||
dao.CreateMultiEntities(db, priceReferSnapshot)
|
||||
dao.Commit(db)
|
||||
}
|
||||
case 1:
|
||||
priceReferSnapshotList, err = dao.GetPriceReferSnapshotNoPage(db, nil, nil, nil, snapshotAt)
|
||||
var (
|
||||
citySkuMap = make(map[int]map[int][]int)
|
||||
countryMap = make(map[int][]int)
|
||||
resultMap = make(map[int]map[int]*model.PriceReferSnapshot)
|
||||
resultCountryMap = make(map[int]*model.PriceReferSnapshot)
|
||||
)
|
||||
storeList, err := dao.GetStoreList(db, nil, nil, nil, nil, "")
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
for _, v := range storeList {
|
||||
if v.PayPercentage < 50 {
|
||||
continue
|
||||
}
|
||||
var tList []*tStoreSkuBindAndSkuName
|
||||
sql := `
|
||||
SELECT DISTINCT b.city_code, a.store_id, Round(a.unit_price * IF(b.pay_percentage < 50 , 70, b.pay_percentage) / 100) AS unit_price, c.name_id
|
||||
FROM store_sku_bind a
|
||||
JOIN store b ON b.id = a.store_id AND b.deleted_at = ? AND b.status != ?
|
||||
JOIN sku c ON c.id = a.sku_id
|
||||
WHERE a.store_id = ?
|
||||
AND c.name_id NOT IN(
|
||||
SELECT b.name_id
|
||||
FROM store_sku_bind a
|
||||
JOIN sku b ON a.sku_id = b.id AND b.deleted_at = ?
|
||||
WHERE a.deleted_at = ?
|
||||
AND a.store_id = ?
|
||||
AND b.name_id NOT IN(SELECT DISTINCT b.name_id
|
||||
FROM store_sku_bind a
|
||||
JOIN sku b ON a.sku_id = b.id AND b.deleted_at = ?
|
||||
WHERE a.deleted_at = ?
|
||||
AND a.store_id = ?
|
||||
AND a.status = ?)
|
||||
)
|
||||
AND a.deleted_at = ?
|
||||
`
|
||||
sqlParams := []interface{}{
|
||||
utils.DefaultTimeValue,
|
||||
model.StoreStatusDisabled,
|
||||
v.ID,
|
||||
utils.DefaultTimeValue,
|
||||
utils.DefaultTimeValue,
|
||||
v.ID,
|
||||
utils.DefaultTimeValue,
|
||||
utils.DefaultTimeValue,
|
||||
v.ID,
|
||||
model.StoreSkuBindStatusNormal,
|
||||
utils.DefaultTimeValue,
|
||||
}
|
||||
dao.GetRows(db, &tList, sql, sqlParams...)
|
||||
skuNameMap := make(map[int][]int)
|
||||
if len(tList) > 0 {
|
||||
for _, vv := range tList {
|
||||
skuNameMap[vv.NameID] = append(skuNameMap[vv.NameID], vv.UnitPrice)
|
||||
countryMap[vv.NameID] = append(countryMap[vv.NameID], vv.UnitPrice)
|
||||
}
|
||||
if citySkuMap[v.CityCode] != nil {
|
||||
for nameID, unitPriceList := range skuNameMap {
|
||||
if citySkuMap[v.CityCode][nameID] != nil {
|
||||
citySkuMap[v.CityCode][nameID] = append(citySkuMap[v.CityCode][nameID], unitPriceList...)
|
||||
} else {
|
||||
citySkuMap[v.CityCode][nameID] = unitPriceList
|
||||
}
|
||||
}
|
||||
} else {
|
||||
citySkuMap[v.CityCode] = skuNameMap
|
||||
}
|
||||
}
|
||||
}
|
||||
for k, v := range countryMap {
|
||||
var midUnitPrice int
|
||||
var avgUnitPrice int
|
||||
sort.Ints(v)
|
||||
if len(v)%2 == 0 {
|
||||
midUnitPrice = v[len(v)/2-1]
|
||||
} else {
|
||||
midUnitPrice = v[len(v)/2]
|
||||
}
|
||||
for _, vv := range v {
|
||||
avgUnitPrice += vv
|
||||
}
|
||||
priceRefer := &model.PriceReferSnapshot{
|
||||
MidUnitPrice: midUnitPrice,
|
||||
MaxUnitPrice: v[len(v)-1],
|
||||
MinUnitPrice: v[0],
|
||||
AvgUnitPrice: avgUnitPrice / len(v),
|
||||
}
|
||||
resultCountryMap[k] = priceRefer
|
||||
}
|
||||
for k1, v := range citySkuMap {
|
||||
skuNameMap := make(map[int]*model.PriceReferSnapshot)
|
||||
for k2, _ := range v {
|
||||
var midUnitPrice int
|
||||
var avgUnitPrice int
|
||||
sort.Ints(v[k2])
|
||||
if len(v[k2])%2 == 0 {
|
||||
midUnitPrice = v[k2][len(v[k2])/2-1]
|
||||
} else {
|
||||
midUnitPrice = v[k2][len(v[k2])/2]
|
||||
}
|
||||
for _, vv := range v[k2] {
|
||||
avgUnitPrice += vv
|
||||
}
|
||||
skuNameMap[k2] = &model.PriceReferSnapshot{
|
||||
MidUnitPrice: midUnitPrice,
|
||||
MaxUnitPrice: v[k2][len(v[k2])-1],
|
||||
MinUnitPrice: v[k2][0],
|
||||
AvgUnitPrice: avgUnitPrice / len(v[k2]),
|
||||
}
|
||||
}
|
||||
resultMap[k1] = skuNameMap
|
||||
}
|
||||
dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil || err != nil {
|
||||
dao.Rollback(db)
|
||||
if r != nil {
|
||||
panic(r)
|
||||
}
|
||||
}
|
||||
}()
|
||||
if len(priceReferSnapshotList) > 0 {
|
||||
for _, v := range priceReferSnapshotList {
|
||||
if v.CityCode == 0 {
|
||||
if resultCountryMap[v.NameID] != nil {
|
||||
v.MidUnitPrice = resultCountryMap[v.NameID].MidUnitPrice
|
||||
v.MaxUnitPrice = resultCountryMap[v.NameID].MaxUnitPrice
|
||||
v.AvgUnitPrice = resultCountryMap[v.NameID].AvgUnitPrice
|
||||
v.MinUnitPrice = resultCountryMap[v.NameID].MinUnitPrice
|
||||
dao.UpdateEntity(db, v, "MidUnitPrice", "MaxUnitPrice", "MinUnitPrice", "AvgUnitPrice")
|
||||
}
|
||||
continue
|
||||
}
|
||||
if resultMap[v.CityCode][v.NameID] != nil {
|
||||
v.MidUnitPrice = resultMap[v.CityCode][v.NameID].MidUnitPrice
|
||||
v.MaxUnitPrice = resultMap[v.CityCode][v.NameID].MaxUnitPrice
|
||||
v.AvgUnitPrice = resultMap[v.CityCode][v.NameID].AvgUnitPrice
|
||||
v.MinUnitPrice = resultMap[v.CityCode][v.NameID].MinUnitPrice
|
||||
dao.UpdateEntity(db, v, "MidUnitPrice", "MaxUnitPrice", "MinUnitPrice", "AvgUnitPrice")
|
||||
}
|
||||
}
|
||||
}
|
||||
dao.Commit(db)
|
||||
case 2:
|
||||
dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil || err != nil {
|
||||
dao.Rollback(db)
|
||||
if r != nil {
|
||||
panic(r)
|
||||
}
|
||||
}
|
||||
}()
|
||||
if len(priceReferSnapshotList) > 0 {
|
||||
for _, v := range priceReferSnapshotList {
|
||||
result, _ := dao.GetPriceReferPrice(db, v.CityCode, v.SkuID, snapshotAt)
|
||||
v.MaxPrice = result.MaxPrice
|
||||
v.MinPrice = result.MinPrice
|
||||
v.AvgPrice = result.AvgPrice
|
||||
v.MidPrice = result.MidPrice
|
||||
dao.UpdateEntity(db, v, "MidPrice", "MaxPrice", "MinPrice", "AvgPrice")
|
||||
}
|
||||
}
|
||||
dao.Commit(db)
|
||||
//TODO 京东查询接口报错,暂时屏蔽了
|
||||
// case 3:
|
||||
// priceReferSnapshotList, err = dao.GetPriceReferSnapshotNoPage(db, []int{0}, nil, nil, snapshotAt)
|
||||
// taskFunc := func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
// v := batchItemList[0].(*model.PriceReferSnapshot)
|
||||
// for _, appOrg := range apimanager.CurAPIManager.GetAppOrgCodeList(model.VendorIDJD) {
|
||||
// directPrice, _ := jd.GetAPI(appOrg).GetJdSkuDirectPrice(v.SkuID)
|
||||
// v.JdDirectPrice = int(directPrice)
|
||||
// dao.UpdateEntity(db, v, "JdDirectPrice")
|
||||
// }
|
||||
// return retVal, err
|
||||
// }
|
||||
// taskParallel := tasksch.NewParallelTask("获取并更新京东指导价格", tasksch.NewParallelConfig(), ctx, taskFunc, priceReferSnapshotList)
|
||||
// tasksch.HandleTask(taskParallel, task, true).Run()
|
||||
// _, err = taskParallel.GetResult(0)
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
taskSeq := tasksch.NewSeqTask2("生成每日价格统计", ctx, isContinueWhenError, taskSeqFunc, 3)
|
||||
tasksch.HandleTask(taskSeq, nil, true).Run()
|
||||
if !isAsync {
|
||||
_, err = taskSeq.GetResult(0)
|
||||
hint = "1"
|
||||
} else {
|
||||
hint = taskSeq.GetID()
|
||||
}
|
||||
return hint, err
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,44 +0,0 @@
|
||||
package tempop
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/globals/api2"
|
||||
"git.rosy.net.cn/jx-callback/globals/testinit"
|
||||
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/ebai"
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/elm"
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/jd"
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/mtwm"
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/weimob/wsc"
|
||||
)
|
||||
|
||||
func init() {
|
||||
testinit.Init()
|
||||
api2.Init()
|
||||
}
|
||||
|
||||
func TestJdStoreInfo1125(t *testing.T) {
|
||||
_, err := JdStoreInfo1125()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func Testaa(t *testing.T) {
|
||||
request, _ := http.NewRequest(http.MethodGet, "https://stores.shop.jd.com/stores/updateStoreStatus?storeId=24332466&storeStatus=1", nil)
|
||||
c := &http.Cookie{
|
||||
Name: "thor",
|
||||
Value: "80FAF09E9A09B6E618A68057BDFCFCB8C86E8252DC9F7D3B34572625904FBA0AB6BF053A5325612EC0407791BB05F5301356E71E8B282C40C06D0B5DF3439DEECB102A78FAFF7AC0FC4E2D1FA8DD8BBAE1A011E50B5C74F1870AD982D7BF453F470F31F2241B73AC4C25485025C2ABEBC8A538AF7257824D2FAEE300A1435175B0B451FB5C19B78D729FC83152CA3BAF",
|
||||
}
|
||||
request.AddCookie(c)
|
||||
client := &http.Client{}
|
||||
fmt.Println("test1", request.URL)
|
||||
response, _ := client.Do(request)
|
||||
defer response.Body.Close()
|
||||
bodyData, _ := ioutil.ReadAll(response.Body)
|
||||
fmt.Println("test1", string(bodyData))
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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()
|
||||
|
||||
@@ -3,6 +3,8 @@ package datares
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
"github.com/qiniu/api.v7/storage"
|
||||
"image"
|
||||
"image/gif"
|
||||
"image/jpeg"
|
||||
@@ -14,10 +16,9 @@ import (
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
"github.com/qiniu/api.v7/storage"
|
||||
//"git.rosy.net.cn/jx-callback/globals/api"
|
||||
//"github.com/qiniu/api.v7/storage"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -109,10 +110,10 @@ func RegisterDataResource(ctx *jxcontext.Context, name, resourceURL, mimeType, h
|
||||
return dataRes, err
|
||||
}
|
||||
if imgType > 0 {
|
||||
if globals.EnableStoreWrite {
|
||||
// 忽略上传错误
|
||||
UploadImage2Vendors(ctx, nil, dataRes, resBinary, isAsyncUpload2Vendor)
|
||||
}
|
||||
//if globals.EnableStoreWrite {
|
||||
// 忽略上传错误
|
||||
UploadImage2Vendors(ctx, nil, dataRes, resBinary, isAsyncUpload2Vendor)
|
||||
//}
|
||||
}
|
||||
return dataRes, err
|
||||
}
|
||||
@@ -152,82 +153,82 @@ func GetDataResource(ctx *jxcontext.Context, hashCode string) (resourceURL strin
|
||||
|
||||
// 这个函数,可能部分平台成功,部分失败
|
||||
func UploadImage2Vendors(ctx *jxcontext.Context, parentTask tasksch.ITask, dataRes *model.DataResource, imgData []byte, isAsync bool) (hint string, err error) {
|
||||
var vendorIDs []int
|
||||
if dataRes.EbaiURL == "" {
|
||||
vendorIDs = append(vendorIDs, model.VendorIDEBAI)
|
||||
}
|
||||
if dataRes.MtwmURL == "" {
|
||||
vendorIDs = append(vendorIDs, model.VendorIDMTWM)
|
||||
}
|
||||
// var vendorIDs []int
|
||||
// if dataRes.EbaiURL == "" {
|
||||
// vendorIDs = append(vendorIDs, model.VendorIDEBAI)
|
||||
// }
|
||||
// if dataRes.MtwmURL == "" {
|
||||
// vendorIDs = append(vendorIDs, model.VendorIDMTWM)
|
||||
// }
|
||||
// if dataRes.JdsURL == "" {
|
||||
// vendorIDs = append(vendorIDs, model.VendorIDJDShop)
|
||||
// }
|
||||
if len(vendorIDs) > 0 {
|
||||
imgName := jxutils.GetShortNameFromURL(dataRes.MainURL)
|
||||
task := tasksch.NewSeqTask(fmt.Sprintf("上传图片至平台1:%s,%s", dataRes.Name, dataRes.MainURL), ctx,
|
||||
func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
|
||||
switch step {
|
||||
case 0:
|
||||
if imgData == nil {
|
||||
if imgData, _, err = jxutils.DownloadFileByURL(dataRes.MainURL); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
case 1:
|
||||
uploadTask := tasksch.NewParallelTask(fmt.Sprintf("上传图片至平台2:%s,%s", dataRes.Name, imgName),
|
||||
tasksch.NewParallelConfig().SetIsContinueWhenError(true), ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
vendorID := batchItemList[0].(int)
|
||||
if handler := partner.GetPurchasePlatformFromVendorID(vendorID); handler != nil {
|
||||
// TODO vendorOrgCode
|
||||
imgHint, err2 := handler.UploadImg(ctx, "", dataRes.MainURL, imgData, imgName, int(dataRes.UseType))
|
||||
if err = err2; err == nil {
|
||||
retVal = [][]interface{}{
|
||||
[]interface{}{
|
||||
vendorID,
|
||||
imgHint,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
return retVal, err
|
||||
}, vendorIDs)
|
||||
tasksch.HandleTask(uploadTask, task, false).Run()
|
||||
resultList, err2 := uploadTask.GetResult(0)
|
||||
err = err2
|
||||
if len(resultList) > 0 {
|
||||
db := dao.GetDB()
|
||||
for _, v := range resultList {
|
||||
result := v.([]interface{})
|
||||
vendorID := result[0].(int)
|
||||
imgHint := result[1].(string)
|
||||
updateField := ""
|
||||
if vendorID == model.VendorIDEBAI {
|
||||
dataRes.EbaiURL = imgHint
|
||||
updateField = "EbaiURL"
|
||||
} else if vendorID == model.VendorIDMTWM {
|
||||
dataRes.MtwmURL = imgHint
|
||||
updateField = "MtwmURL"
|
||||
}
|
||||
// else if vendorID == model.VendorIDJDShop {
|
||||
// dataRes.JdsURL = imgHint
|
||||
// updateField = "JdsURL"
|
||||
// }
|
||||
dao.UpdateEntity(db, dataRes, updateField)
|
||||
}
|
||||
}
|
||||
}
|
||||
return result, err
|
||||
}, 2)
|
||||
tasksch.HandleTask(task, parentTask, false).Run()
|
||||
if !isAsync {
|
||||
if _, err = task.GetResult(0); err == nil {
|
||||
hint = "1"
|
||||
}
|
||||
} else {
|
||||
hint = task.GetID()
|
||||
}
|
||||
}
|
||||
// if len(vendorIDs) > 0 {
|
||||
// imgName := jxutils.GetShortNameFromURL(dataRes.MainURL)
|
||||
// task := tasksch.NewSeqTask(fmt.Sprintf("上传图片至平台1:%s,%s", dataRes.Name, dataRes.MainURL), ctx,
|
||||
// func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
|
||||
// switch step {
|
||||
// case 0:
|
||||
// if imgData == nil {
|
||||
// if imgData, _, err = jxutils.DownloadFileByURL(dataRes.MainURL); err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// }
|
||||
// case 1:
|
||||
// uploadTask := tasksch.NewParallelTask(fmt.Sprintf("上传图片至平台2:%s,%s", dataRes.Name, imgName),
|
||||
// tasksch.NewParallelConfig().SetIsContinueWhenError(true), ctx,
|
||||
// func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
// vendorID := batchItemList[0].(int)
|
||||
// if handler := partner.GetPurchasePlatformFromVendorID(vendorID); handler != nil {
|
||||
// // TODO vendorOrgCode
|
||||
// imgHint, err2 := handler.UploadImg(ctx, "", dataRes.MainURL, imgData, imgName, int(dataRes.UseType))
|
||||
// if err = err2; err == nil {
|
||||
// retVal = [][]interface{}{
|
||||
// []interface{}{
|
||||
// vendorID,
|
||||
// imgHint,
|
||||
// },
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return retVal, err
|
||||
// }, vendorIDs)
|
||||
// tasksch.HandleTask(uploadTask, task, false).Run()
|
||||
// resultList, err2 := uploadTask.GetResult(0)
|
||||
// err = err2
|
||||
// if len(resultList) > 0 {
|
||||
// db := dao.GetDB()
|
||||
// for _, v := range resultList {
|
||||
// result := v.([]interface{})
|
||||
// vendorID := result[0].(int)
|
||||
// imgHint := result[1].(string)
|
||||
// updateField := ""
|
||||
// if vendorID == model.VendorIDEBAI {
|
||||
// dataRes.EbaiURL = imgHint
|
||||
// updateField = "EbaiURL"
|
||||
// } else if vendorID == model.VendorIDMTWM {
|
||||
// dataRes.MtwmURL = imgHint
|
||||
// updateField = "MtwmURL"
|
||||
// }
|
||||
// // else if vendorID == model.VendorIDJDShop {
|
||||
// // dataRes.JdsURL = imgHint
|
||||
// // updateField = "JdsURL"
|
||||
// // }
|
||||
// dao.UpdateEntity(db, dataRes, updateField)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return result, err
|
||||
// }, 2)
|
||||
// tasksch.HandleTask(task, parentTask, false).Run()
|
||||
// if !isAsync {
|
||||
// if _, err = task.GetResult(0); err == nil {
|
||||
// hint = "1"
|
||||
// }
|
||||
// } else {
|
||||
// hint = task.GetID()
|
||||
// }
|
||||
// }
|
||||
return hint, err
|
||||
}
|
||||
|
||||
|
||||
@@ -1,32 +1,25 @@
|
||||
package datares
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/globals/api2"
|
||||
"git.rosy.net.cn/jx-callback/globals/testinit"
|
||||
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/ebai"
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/jd"
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/mtwm"
|
||||
)
|
||||
|
||||
func init() {
|
||||
testinit.Init()
|
||||
api2.Init()
|
||||
}
|
||||
|
||||
func TestGetQiniuUploadToken(t *testing.T) {
|
||||
token, err := GetQiniuUploadToken(jxcontext.AdminCtx, "", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
fmt.Print(token)
|
||||
}
|
||||
//func TestGetQiniuUploadToken(t *testing.T) {
|
||||
// token, err := GetQiniuUploadToken(jxcontext.AdminCtx, "", "")
|
||||
// if err != nil {
|
||||
// t.Fatal(err)
|
||||
// }
|
||||
// fmt.Print(token)
|
||||
//}
|
||||
|
||||
func TestGetDataResource(t *testing.T) {
|
||||
dataRes, err := GetDataResource(jxcontext.AdminCtx, "1D3E4A8259F359FB4CF47D541843950D")
|
||||
|
||||
@@ -101,15 +101,12 @@ func (h *Hub) GetToken(tokenType, oldToken string, waitTime time.Duration) (toke
|
||||
case EventTypeWXToken:
|
||||
token = api.WeixinAPI.CBGetToken()
|
||||
case EventTypeYLYToken:
|
||||
token = api.YilianyunAPI.GetToken()
|
||||
case EventTypeWeimobToken:
|
||||
if weimobToken := api.WeimobAPI.GetToken(); weimobToken != nil {
|
||||
token = string(utils.MustMarshal(weimobToken))
|
||||
}
|
||||
case EventTypePushToken:
|
||||
token = api.PushAPI.CBGetToken()
|
||||
case EventTypeWX2Token:
|
||||
token = api.WeixinMiniAPI2.CBGetToken()
|
||||
//token = api.PushAPI.CBGetToken()
|
||||
}
|
||||
|
||||
if token != oldToken {
|
||||
|
||||
@@ -25,6 +25,8 @@ type Context struct {
|
||||
|
||||
const (
|
||||
MaxUserNameLen = 30
|
||||
|
||||
RsmDefultToken = "rushSkyMonkeyToken_20201203"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -74,6 +76,8 @@ func New(notUsed interface{}, token string, w http.ResponseWriter, r *http.Reque
|
||||
if err == model.ErrTokenIsInvalid {
|
||||
if !globals.IsProductEnv() {
|
||||
err = nil
|
||||
} else if token == RsmDefultToken {
|
||||
err = nil
|
||||
} else {
|
||||
errCode = model.ErrCodeTokenIsInvalid
|
||||
}
|
||||
|
||||
@@ -7,11 +7,13 @@ import (
|
||||
"crypto/md5"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"golang.org/x/text/encoding/simplifiedchinese"
|
||||
"golang.org/x/text/transform"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
"math/rand"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -42,33 +44,11 @@ var (
|
||||
model.VendorIDEBAI: []string{
|
||||
"image-star.elemecdn.com",
|
||||
},
|
||||
model.VendorIDYB: []string{
|
||||
"pospalstoreimg.area27.pospal.cn",
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
const fileExt = ".xlsx"
|
||||
|
||||
type OrderSkuList []*model.OrderSku
|
||||
|
||||
func (l OrderSkuList) Len() int {
|
||||
return len(l)
|
||||
}
|
||||
|
||||
// Less reports whether the element with
|
||||
// index i should sort before the element with index j.
|
||||
func (l OrderSkuList) Less(i, j int) bool {
|
||||
return l[i].SalePrice < l[j].SalePrice
|
||||
}
|
||||
|
||||
// Swap swaps the elements with indexes i and j.
|
||||
func (l OrderSkuList) Swap(i, j int) {
|
||||
tmp := l[i]
|
||||
l[i] = l[j]
|
||||
l[j] = tmp
|
||||
}
|
||||
|
||||
func init() {
|
||||
rand.Seed(time.Now().Unix())
|
||||
routinePool = routinepool.New(1000, 1000)
|
||||
@@ -80,30 +60,6 @@ func init() {
|
||||
orderNoBeginTimestamp = utils.Str2Time("2010-01-01 00:00:00").Unix()
|
||||
}
|
||||
|
||||
func getJxStoreIDFromOrder(order *model.GoodsOrder) (retVal int) {
|
||||
if order.JxStoreID != 0 {
|
||||
return order.JxStoreID
|
||||
}
|
||||
return order.StoreID
|
||||
}
|
||||
|
||||
// 此函数得到的是order的销售门店京西ID,与GetJxStoreIDFromOrder的区别是order.StoreID的解释不同,参考其它相关资料
|
||||
func GetSaleStoreIDFromOrder(order *model.GoodsOrder) (retVal int) {
|
||||
return getJxStoreIDFromOrder(order)
|
||||
}
|
||||
|
||||
// 此函数得到的是order的商品的展示门店京西ID,与GetJxStoreIDFromOrder的区别是order.StoreID的解释不同,参考其它相关资料
|
||||
func GetShowStoreIDFromOrder(order *model.GoodsOrder) (retVal int) {
|
||||
return getJxStoreIDFromOrder(order)
|
||||
}
|
||||
|
||||
func GetSkuIDFromOrderSku(sku *model.OrderSku) (skuID int) {
|
||||
if sku.JxSkuID > 0 {
|
||||
return sku.JxSkuID
|
||||
}
|
||||
return sku.SkuID
|
||||
}
|
||||
|
||||
func GetSaleStoreIDFromAfsOrder(order *model.AfsOrder) (retVal int) {
|
||||
if order.JxStoreID > 0 {
|
||||
return order.JxStoreID
|
||||
@@ -160,8 +116,6 @@ func GetPossibleVendorIDFromVendorOrderID(vendorOrderID string) (vendorID int) {
|
||||
}
|
||||
} else if orderIDLen == len("33437032333978492") {
|
||||
vendorID = model.VendorIDMTWM
|
||||
} else if orderIDLen == len("5287873015048") {
|
||||
vendorID = model.VendorIDWSC
|
||||
} else if orderIDLen == len("1000004390") {
|
||||
vendorID = model.VendorIDJX
|
||||
} else if orderIDLen == len("124557362562000001") || orderIDLen == len("13153183146800000100") {
|
||||
@@ -171,7 +125,26 @@ func GetPossibleVendorIDFromVendorOrderID(vendorOrderID string) (vendorID int) {
|
||||
return vendorID
|
||||
}
|
||||
|
||||
func GenRand6() (num int) {
|
||||
return utils.Str2Int(fmt.Sprintf("%06v", rand.New(rand.NewSource(time.Now().UnixNano())).Int31n(1000000)))
|
||||
}
|
||||
|
||||
func GenOrderNo() (orderNo int64) {
|
||||
var prefix = utils.Str2Int64(time.Now().Format("20060102"))
|
||||
const randPartNum = 1000
|
||||
orderNo = time.Now().Unix() - orderNoBeginTimestamp
|
||||
orderNo = orderNo * randPartNum
|
||||
md5Bytes := md5.Sum([]byte(utils.GetUUID()))
|
||||
randPart := 0
|
||||
for k, v := range md5Bytes {
|
||||
randPart += int(v) << ((k % 3) * 8)
|
||||
}
|
||||
orderNo += int64(randPart % randPartNum)
|
||||
orderNo += int64(math.Pow10(int(math.Log10(float64(orderNo)))+1)) * prefix
|
||||
return orderNo
|
||||
}
|
||||
|
||||
func GenJobOrderNo() (orderNo int64) {
|
||||
const prefix = 88
|
||||
const randPartNum = 1000
|
||||
orderNo = time.Now().Unix() - orderNoBeginTimestamp
|
||||
@@ -186,6 +159,35 @@ func GenOrderNo() (orderNo int64) {
|
||||
return orderNo
|
||||
}
|
||||
|
||||
func GenBillID() (billID int64) {
|
||||
const prefix = 66
|
||||
const randPartNum = 100
|
||||
billID = time.Now().Unix() - orderNoBeginTimestamp
|
||||
billID = billID * randPartNum
|
||||
md5Bytes := md5.Sum([]byte(utils.GetUUID()))
|
||||
randPart := 0
|
||||
for k, v := range md5Bytes {
|
||||
randPart += int(v) << ((k % 3) * 8)
|
||||
}
|
||||
billID += int64(randPart % randPartNum)
|
||||
billID += int64(math.Pow10(int(math.Log10(float64(billID)))+1)) * prefix
|
||||
return billID
|
||||
}
|
||||
|
||||
func GenGroupID() (groupID int64) {
|
||||
const randPartNum = 100
|
||||
groupID = time.Now().Unix() - orderNoBeginTimestamp
|
||||
groupID = groupID * randPartNum
|
||||
md5Bytes := md5.Sum([]byte(utils.GetUUID()))
|
||||
randPart := 0
|
||||
for k, v := range md5Bytes {
|
||||
randPart += int(v) << ((k % 3) * 8)
|
||||
}
|
||||
groupID += int64(randPart % randPartNum)
|
||||
groupID += int64(math.Pow10(int(math.Log10(float64(groupID))) + 1))
|
||||
return groupID
|
||||
}
|
||||
|
||||
func GenAfsOrderNo() (orderNo int64) {
|
||||
const prefix = 80
|
||||
const randPartNum = 100
|
||||
@@ -221,18 +223,6 @@ func ComposeUniversalOrderID(orderID string, vendorID int) string {
|
||||
return orderID // 当前用长度就能区分,先不加上vendorID
|
||||
}
|
||||
|
||||
func GetUniversalOrderIDFromWaybill(bill *model.Waybill) string {
|
||||
return ComposeUniversalOrderID(bill.VendorOrderID, bill.OrderVendorID)
|
||||
}
|
||||
|
||||
func GetUniversalOrderIDFromOrder(order *model.GoodsOrder) string {
|
||||
return ComposeUniversalOrderID(order.VendorOrderID, order.VendorID)
|
||||
}
|
||||
|
||||
func GetUniversalOrderIDFromOrderStatus(status *model.OrderStatus) string {
|
||||
return ComposeUniversalOrderID(status.VendorOrderID, status.VendorID)
|
||||
}
|
||||
|
||||
// distance单位为米
|
||||
func ConvertDistanceToLogLat(lng, lat, distance, angle float64) (newLng, newLat float64) {
|
||||
oneDu := 111319.55 // 单位为米
|
||||
@@ -555,7 +545,7 @@ func MakeValidationMapFromSlice(validValues []string, flag int) map[string]int {
|
||||
}
|
||||
|
||||
func ComposeQiniuResURL(key string) string {
|
||||
return "http://image.jxc4.com/" + key
|
||||
return "https://image.jxc4.com/" + key
|
||||
}
|
||||
|
||||
func IsLegalMobileNumber(num int64) bool {
|
||||
@@ -595,58 +585,6 @@ func Strings2Objs(strAndObjAddPairs ...interface{}) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
func RefreshOrderSkuRelated(order *model.GoodsOrder) *model.GoodsOrder {
|
||||
order.SkuCount = 0
|
||||
order.GoodsCount = 0
|
||||
order.SalePrice = 0
|
||||
order.VendorPrice = 0
|
||||
order.ShopPrice = 0
|
||||
order.Weight = 0
|
||||
order.EarningPrice = 0
|
||||
for _, sku := range order.Skus {
|
||||
if sku.SkuID > math.MaxInt32 {
|
||||
sku.SkuID = sku.JxSkuID
|
||||
}
|
||||
sku.OrderCreatedAt = order.OrderCreatedAt
|
||||
sku.VendorID = order.VendorID
|
||||
sku.VendorOrderID = order.VendorOrderID
|
||||
order.SkuCount++
|
||||
order.GoodsCount += sku.Count
|
||||
order.SalePrice += sku.SalePrice * int64(sku.Count)
|
||||
order.VendorPrice += sku.VendorPrice * int64(sku.Count)
|
||||
order.ShopPrice += sku.ShopPrice * int64(sku.Count)
|
||||
order.EarningPrice += sku.EarningPrice * int64(sku.Count)
|
||||
order.Weight += sku.Weight * sku.Count
|
||||
}
|
||||
return order
|
||||
}
|
||||
|
||||
func RefreshOrderEarningPrice2(order *model.GoodsOrder, payPercentage int) *model.GoodsOrder {
|
||||
if order.EarningType == model.EarningTypePoints {
|
||||
// if order.VendorID == model.VendorIDJDShop || order.VendorID == model.VendorIDJX {
|
||||
// order.NewEarningPrice = order.TotalShopMoney * int64((100 - payPercentage)) / 100
|
||||
// } else {
|
||||
order.NewEarningPrice = order.TotalShopMoney * int64((100 - payPercentage/2)) / 100
|
||||
// }
|
||||
} else {
|
||||
order.NewEarningPrice = order.EarningPrice
|
||||
}
|
||||
return order
|
||||
}
|
||||
|
||||
func RefreshOrderEarningPrice3(order *model.GoodsOrder, payPercentage int, bill *model.Waybill) *model.GoodsOrder {
|
||||
if order.EarningType == model.EarningTypePoints {
|
||||
// if order.VendorID == model.VendorIDJDShop || order.VendorID == model.VendorIDJX {
|
||||
// order.NewEarningPrice = (order.TotalShopMoney - bill.DesiredFee) * int64((100 - payPercentage)) / 100
|
||||
// } else {
|
||||
order.NewEarningPrice = order.TotalShopMoney*int64((100-payPercentage/2))/100 - bill.DesiredFee
|
||||
// }
|
||||
} else {
|
||||
order.NewEarningPrice = order.EarningPrice
|
||||
}
|
||||
return order
|
||||
}
|
||||
|
||||
func RefreshAfsOrderSkuRelated(afsOrder *model.AfsOrder) *model.AfsOrder {
|
||||
afsOrder.SkuUserMoney = 0
|
||||
afsOrder.PmSkuSubsidyMoney = 0
|
||||
@@ -660,56 +598,6 @@ func RefreshAfsOrderSkuRelated(afsOrder *model.AfsOrder) *model.AfsOrder {
|
||||
return afsOrder
|
||||
}
|
||||
|
||||
func RemoveSkuFromOrder(order *model.GoodsOrder, removedSkuList []*model.OrderSku) *model.GoodsOrder {
|
||||
removedSkuMap := make(map[int]*model.OrderSku)
|
||||
removedSkuMap2 := make(map[string]*model.OrderSku)
|
||||
for _, sku := range removedSkuList {
|
||||
if skuID := GetSkuIDFromOrderSku(sku); skuID > 0 {
|
||||
if removedSkuMap[skuID] == nil {
|
||||
removedSkuMap[skuID] = sku
|
||||
} else {
|
||||
removedSkuMap[skuID].Count += sku.Count
|
||||
}
|
||||
}
|
||||
if vendorSkuID := sku.VendorSkuID; vendorSkuID != "" {
|
||||
if removedSkuMap2[vendorSkuID] == nil {
|
||||
removedSkuMap2[vendorSkuID] = sku
|
||||
} else {
|
||||
removedSkuMap2[vendorSkuID].Count += sku.Count
|
||||
}
|
||||
}
|
||||
}
|
||||
var skuList []*model.OrderSku
|
||||
sort.Sort(sort.Reverse(OrderSkuList(order.Skus)))
|
||||
for _, sku := range order.Skus {
|
||||
var removedSku *model.OrderSku
|
||||
if skuID := GetSkuIDFromOrderSku(sku); skuID > 0 {
|
||||
removedSku = removedSkuMap[skuID]
|
||||
}
|
||||
if removedSku == nil {
|
||||
if vendorSkuID := sku.VendorSkuID; vendorSkuID != "" {
|
||||
removedSku = removedSkuMap2[vendorSkuID]
|
||||
}
|
||||
}
|
||||
copiedSku := *sku
|
||||
tmp := &copiedSku
|
||||
if removedSku != nil {
|
||||
if removedSku.Count >= sku.Count {
|
||||
tmp = nil
|
||||
removedSku.Count -= sku.Count
|
||||
} else {
|
||||
tmp.Count -= removedSku.Count
|
||||
removedSku.Count = 0
|
||||
}
|
||||
}
|
||||
if tmp != nil {
|
||||
skuList = append(skuList, tmp)
|
||||
}
|
||||
}
|
||||
order.Skus = skuList
|
||||
return RefreshOrderSkuRelated(order)
|
||||
}
|
||||
|
||||
func UploadExportContent(content []byte, key string) (downloadURL string, err error) {
|
||||
putPolicy := storage.PutPolicy{
|
||||
Scope: globals.QiniuBucket,
|
||||
@@ -797,42 +685,15 @@ func OperationTime2Str2(openTime, closeTime int16) (str string) {
|
||||
return str
|
||||
}
|
||||
|
||||
func OperationTimeStr4VendorStore(v *model.VendorStoreSnapshot) (str string) {
|
||||
str = fmt.Sprintf("%s", OperationTime2Str2(v.OpenTime1, v.CloseTime1))
|
||||
if v.OpenTime2 > 0 && v.CloseTime2 > 0 {
|
||||
str += fmt.Sprintf(",%s", OperationTime2Str2(v.OpenTime2, v.CloseTime2))
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
func OperationTime2HourMinuteFormat(time time.Time) (i int16) {
|
||||
return int16(time.Hour()*100 + time.Minute())
|
||||
}
|
||||
|
||||
// 得到饿百订单的取货码
|
||||
func GetEbaiOrderGetCode(order *model.GoodsOrder) (getCode string) {
|
||||
if order.VendorID == model.VendorIDEBAI && len(order.VendorOrderID2) >= 4 {
|
||||
getCode = order.VendorOrderID2[len(order.VendorOrderID2)-4:]
|
||||
}
|
||||
return getCode
|
||||
}
|
||||
|
||||
func WriteFile(fileName string, binData []byte) error {
|
||||
err := ioutil.WriteFile(fileName, binData, 0666)
|
||||
return err
|
||||
}
|
||||
|
||||
func GetRealMobile4Order(order *model.GoodsOrder) (mobileNumber string) {
|
||||
mobileNumber = order.ConsigneeMobile2
|
||||
if mobileNumber == "" {
|
||||
mobileNumber = order.ConsigneeMobile
|
||||
}
|
||||
if !IsStringLikeMobile(mobileNumber) {
|
||||
mobileNumber = ""
|
||||
}
|
||||
return mobileNumber
|
||||
}
|
||||
|
||||
func GuessDataResourceVendor(resourceURL string) (vendorID int) {
|
||||
vendorID = -1
|
||||
for tmpVendorID, urlList := range resourceTypeMap {
|
||||
@@ -895,30 +756,23 @@ func GetOneEmailFromStr(str string) (email string) {
|
||||
|
||||
// 计算一个坐标点距离一个门店的距离,单位为米,如果不在有效范围内,则返回0
|
||||
func Point2StoreDistance(lng, lat float64, intStoreLng, intStoreLat int, deliveryRangeType int8, deliveryRange string) (distance int) {
|
||||
storeLng := IntCoordinate2Standard(intStoreLng)
|
||||
storeLat := IntCoordinate2Standard(intStoreLat)
|
||||
if deliveryRangeType == model.DeliveryRangeTypeRadius {
|
||||
maxDistance := int(utils.Str2Int64WithDefault(deliveryRange, 0))
|
||||
distance = int(EarthDistance(lng, lat, storeLng, storeLat) * 1000)
|
||||
if distance > maxDistance {
|
||||
distance = 0
|
||||
}
|
||||
} else {
|
||||
points := CoordinateStr2Points(deliveryRange)
|
||||
if utils.IsPointInPolygon(lng, lat, points) {
|
||||
distance = int(EarthDistance(lng, lat, storeLng, storeLat) * 1000)
|
||||
}
|
||||
}
|
||||
// storeLng := IntCoordinate2Standard(intStoreLng)
|
||||
// storeLat := IntCoordinate2Standard(intStoreLat)
|
||||
// if deliveryRangeType == model.DeliveryRangeTypeRadius {
|
||||
// maxDistance := int(utils.Str2Int64WithDefault(deliveryRange, 0))
|
||||
// distance = int(EarthDistance(lng, lat, storeLng, storeLat) * 1000)
|
||||
// if distance > maxDistance {
|
||||
// distance = 0
|
||||
// }
|
||||
// } else {
|
||||
// points := CoordinateStr2Points(deliveryRange)
|
||||
// if utils.IsPointInPolygon(lng, lat, points) {
|
||||
// distance = int(EarthDistance(lng, lat, storeLng, storeLat) * 1000)
|
||||
// }
|
||||
// }
|
||||
return distance
|
||||
}
|
||||
|
||||
func TranslateStorePriceType(storePriceType int8) int8 {
|
||||
if storePriceType == model.StoreChangePriceTypeManagedStore {
|
||||
storePriceType = model.StoreChangePriceTypeBossDisabled
|
||||
}
|
||||
return storePriceType
|
||||
}
|
||||
|
||||
func TranslateSoundSize(vendorID, soundPercentage int) (soundSize string) {
|
||||
if vendorID == model.VendorIDYiLianYun || vendorID == model.VendorIDFeiE {
|
||||
if soundPercentage == 0 {
|
||||
@@ -970,42 +824,27 @@ func PKCS5UnPadding(origData []byte) []byte {
|
||||
}
|
||||
|
||||
//合成水印图
|
||||
func MixWatermarkImg(imgWatermark, img string, exPrefixBegin, exPrefixEnd *time.Time) (imgMix string) {
|
||||
if exPrefixBegin != nil && exPrefixEnd != nil {
|
||||
if utils.Time2Date(time.Now().Add(6*time.Hour)).Sub(*exPrefixBegin) >= 0 && utils.Time2Date(time.Now()).Sub(*exPrefixEnd) <= 0 {
|
||||
baseURL := base64.URLEncoding.EncodeToString([]byte(imgWatermark))
|
||||
var imgUrl string
|
||||
if strings.Contains(img, "?") {
|
||||
imgUrl = img + "/imageView2/0/q/75|watermark/1/image/" + baseURL + "/dissolve/100/gravity/Center/dx/0/dy/0"
|
||||
} else {
|
||||
imgUrl = img + "?imageView2/0/q/75|watermark/1/image/" + baseURL + "/dissolve/100/gravity/Center/dx/0/dy/0"
|
||||
func MixWatermarkImg(imgWatermark, img, positon string) (imgMix string) {
|
||||
baseURL := base64.URLEncoding.EncodeToString([]byte(imgWatermark))
|
||||
var imgUrl string
|
||||
if strings.Contains(img, "?") {
|
||||
imgUrl = img + "/imageView2/0/q/75|watermark/1/image/" + baseURL + "/dissolve/100/gravity/" + positon + "/dx/10/dy/10"
|
||||
} else {
|
||||
imgUrl = img + "?imageView2/0/q/75|watermark/1/image/" + baseURL + "/dissolve/100/gravity/" + positon + "/dx/10/dy/10"
|
||||
}
|
||||
if resBinary, _, err := DownloadFileByURL(imgUrl); err == nil {
|
||||
if downloadURL, err := UploadExportContent(resBinary, "image/"+utils.Int64ToStr(time.Now().Unix())+img[strings.LastIndex(img, "/")+1:len(img)]); err == nil {
|
||||
if err == nil {
|
||||
return downloadURL
|
||||
}
|
||||
if resBinary, _, err := DownloadFileByURL(imgUrl); err == nil {
|
||||
if downloadURL, err := UploadExportContent(resBinary, utils.Int64ToStr(time.Now().Unix())+img[strings.LastIndex(img, "/")+1:len(img)]); err == nil {
|
||||
if err == nil {
|
||||
return downloadURL
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if utils.Time2Date(time.Now().Add(6*time.Hour)).Sub(*exPrefixEnd) > 0 {
|
||||
return imgMix
|
||||
}
|
||||
}
|
||||
return imgMix
|
||||
}
|
||||
|
||||
func GetDefendPriceIssue() (issue int) {
|
||||
if time.Now().Hour() >= 22 {
|
||||
issue = utils.Str2Int(time.Now().AddDate(0, 0, 1).Format("20060102"))
|
||||
} else {
|
||||
issue = utils.Str2Int(time.Now().Format("20060102"))
|
||||
}
|
||||
return issue
|
||||
}
|
||||
|
||||
func GetLastDefendPriceIssue() (issue int) {
|
||||
return utils.Str2Int(time.Now().AddDate(0, 0, 1).Format("20060102"))
|
||||
func GetIssue() (issue int) {
|
||||
year, month, _ := time.Now().Date()
|
||||
return year*100 + int(month)
|
||||
}
|
||||
|
||||
//根据一堆坐标求面积
|
||||
@@ -1037,3 +876,54 @@ func polarTriangleArea(tan1, lng1, tan2, lng2 float64) (s float64) {
|
||||
t := tan1 * tan2
|
||||
return 2 * math.Atan2(t*math.Sin(deltaLng), 1+t*math.Cos(deltaLng))
|
||||
}
|
||||
|
||||
func GenRandomString(l int) string {
|
||||
str := "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
bytes := []byte(str)
|
||||
result := []byte{}
|
||||
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
for i := 0; i < l; i++ {
|
||||
result = append(result, bytes[r.Intn(len(bytes))])
|
||||
}
|
||||
return string(result)
|
||||
}
|
||||
|
||||
func GetDayTime() (dayTimeBegin, dayTimeEnd time.Time) {
|
||||
dayTimeBegin = utils.Str2Time(utils.Time2Str(utils.Time2Date(time.Now())) + " 00:00:00")
|
||||
dayTimeEnd = dayTimeBegin.AddDate(0, 0, 1)
|
||||
return dayTimeBegin, dayTimeEnd
|
||||
}
|
||||
|
||||
func GetWeekTime() (weekTimeBegin, weekTimeEnd time.Time) {
|
||||
offset := int(time.Now().Weekday() - 1)
|
||||
if offset == -1 {
|
||||
offset = -6
|
||||
}
|
||||
weekTimeBegin = time.Now().AddDate(0, 0, offset)
|
||||
weekTimeEnd = weekTimeBegin.AddDate(0, 0, 7)
|
||||
return weekTimeBegin, weekTimeEnd
|
||||
}
|
||||
|
||||
func Utf8ToGbk(str []byte) (b []byte, err error) {
|
||||
r := transform.NewReader(bytes.NewReader(str), simplifiedchinese.GBK.NewEncoder())
|
||||
b, err = ioutil.ReadAll(r)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
func Hextob(str string) []byte {
|
||||
slen := len(str)
|
||||
bHex := make([]byte, len(str)/2)
|
||||
ii := 0
|
||||
for i := 0; i < len(str); i = i + 2 {
|
||||
if slen != 1 {
|
||||
ss := string(str[i]) + string(str[i+1])
|
||||
bt, _ := strconv.ParseInt(ss, 16, 32)
|
||||
bHex[ii] = byte(bt)
|
||||
ii = ii + 1
|
||||
slen = slen - 2
|
||||
}
|
||||
}
|
||||
return bHex
|
||||
}
|
||||
|
||||
@@ -216,42 +216,6 @@ func RegularizeSkuQuality(specQuality float32, specUnit string) (g int) {
|
||||
return int(specQuality)
|
||||
}
|
||||
|
||||
// 计算SKU价格,unitPrice为一斤的单价,specQuality为质量,单位为克
|
||||
func CaculateSkuPrice(unitPrice int, specQuality float32, specUnit string, skuNameUnit string) int {
|
||||
if skuNameUnit != model.SpecialUnit {
|
||||
return unitPrice
|
||||
}
|
||||
specQuality2 := RegularizeSkuQuality(specQuality, specUnit)
|
||||
floatPrice := float64(unitPrice) * float64(specQuality2) / float64(model.SpecialSpecQuality)
|
||||
// if specQuality2 < 250 {
|
||||
// floatPrice = floatPrice * 110 / 100
|
||||
// } else if specQuality2 < 500 {
|
||||
// floatPrice = floatPrice * 105 / 100
|
||||
// }
|
||||
if floatPrice <= 1 {
|
||||
floatPrice = 1
|
||||
}
|
||||
return int(math.Round(floatPrice))
|
||||
}
|
||||
|
||||
// 计算SKU标准价格,CaculateSkuPrice的逆过程
|
||||
func CaculateUnitPrice(skuPrice int, specQuality float32, specUnit string, skuNameUnit string) (unitPrice int) {
|
||||
if skuNameUnit != model.SpecialUnit {
|
||||
return skuPrice
|
||||
}
|
||||
specQuality2 := RegularizeSkuQuality(specQuality, specUnit)
|
||||
unitPrice = skuPrice * model.SpecialSpecQuality / specQuality2
|
||||
// if specQuality2 < 250 {
|
||||
// unitPrice = unitPrice * 100 / 110
|
||||
// } else if specQuality2 < 500 {
|
||||
// unitPrice = unitPrice * 100 / 105
|
||||
// }
|
||||
if unitPrice <= 1 {
|
||||
unitPrice = 1
|
||||
}
|
||||
return unitPrice
|
||||
}
|
||||
|
||||
func ConstrainPricePercentage(percentage int) int {
|
||||
if percentage < model.MinVendorPricePercentage || percentage > model.MaxVendorPricePercentage {
|
||||
percentage = model.DefVendorPricePercentage
|
||||
@@ -287,65 +251,6 @@ func CaculateSkuPriceFromVendor(vendorPrice, percentage, priceAdd int) (price in
|
||||
return price
|
||||
}
|
||||
|
||||
func GetPricePercentage(l model.PricePercentagePack, price int, defPricePercentage int) (pricePercentage, priceAdd int) {
|
||||
pricePercentage = defPricePercentage
|
||||
itemLen := len(l)
|
||||
if itemLen > 0 {
|
||||
low := 0
|
||||
high := itemLen - 1
|
||||
mid := 0
|
||||
for low <= high {
|
||||
mid = low + (high-low)/2
|
||||
if mid < 0 || mid >= itemLen-1 {
|
||||
break
|
||||
}
|
||||
if price >= l[mid].BeginPrice {
|
||||
if price < l[mid+1].BeginPrice {
|
||||
break
|
||||
} else {
|
||||
low = mid + 1
|
||||
}
|
||||
} else {
|
||||
high = mid - 1
|
||||
}
|
||||
}
|
||||
if mid >= 0 && mid <= itemLen-1 && low <= high {
|
||||
pricePercentage = l[mid].PricePercentage
|
||||
priceAdd = l[mid].PriceAdd
|
||||
}
|
||||
}
|
||||
return pricePercentage, priceAdd
|
||||
}
|
||||
|
||||
func GetPricePercentageByVendorPrice(l model.PricePercentagePack, vendorPrice int, defPricePercentage int) (pricePercentage, priceAdd int) {
|
||||
pricePercentage = defPricePercentage
|
||||
if len(l) > 0 {
|
||||
var lastItem *model.PricePercentageItem
|
||||
for _, v := range l {
|
||||
if CaculateSkuVendorPrice(v.BeginPrice, v.PricePercentage, v.PriceAdd) > vendorPrice {
|
||||
break
|
||||
}
|
||||
lastItem = v
|
||||
}
|
||||
if lastItem != nil {
|
||||
pricePercentage = lastItem.PricePercentage
|
||||
priceAdd = lastItem.PriceAdd
|
||||
}
|
||||
}
|
||||
return pricePercentage, priceAdd
|
||||
}
|
||||
|
||||
func CaculatePriceByPricePack(l model.PricePercentagePack, defPricePercentage, price int) (outPrice int) {
|
||||
pricePercentage, priceAdd := GetPricePercentage(l, price, defPricePercentage)
|
||||
return CaculateSkuVendorPrice(price, pricePercentage, priceAdd)
|
||||
}
|
||||
|
||||
func CaculateJxPriceByPricePack(l model.PricePercentagePack, defPricePercentage, vendorPrice int) (jxPrice int) {
|
||||
pricePercentage, priceAdd := GetPricePercentageByVendorPrice(l, vendorPrice, defPricePercentage)
|
||||
jxPrice = CaculateSkuPriceFromVendor(vendorPrice, pricePercentage, priceAdd)
|
||||
return jxPrice
|
||||
}
|
||||
|
||||
func ConstrainPayPercentage(payPerCentage int) int {
|
||||
if payPerCentage <= 50 {
|
||||
payPerCentage = 70
|
||||
@@ -353,10 +258,6 @@ func ConstrainPayPercentage(payPerCentage int) int {
|
||||
return payPerCentage
|
||||
}
|
||||
|
||||
func IsSkuSpecial(specQuality float32, specUnit string) bool {
|
||||
return int(specQuality) == model.SpecialSpecQuality && (specUnit == model.SpecialSpecUnit || specUnit == model.SpecialSpecUnit2)
|
||||
}
|
||||
|
||||
var lastFakeID int64
|
||||
var lastFakeIDMutex sync.RWMutex
|
||||
|
||||
@@ -440,28 +341,6 @@ func FormatSkuWeight(specQuality float32, specUnit string) int {
|
||||
return RegularizeSkuQuality(specQuality, specUnit)
|
||||
}
|
||||
|
||||
type SkuList []*model.Sku
|
||||
|
||||
func (s SkuList) Len() int {
|
||||
return len(s)
|
||||
}
|
||||
|
||||
func (s SkuList) Less(i, j int) bool {
|
||||
if s[i].NameID == s[j].NameID {
|
||||
if s[i].SpecUnit == s[j].SpecUnit {
|
||||
return s[i].SpecQuality < s[j].SpecQuality
|
||||
}
|
||||
return s[i].SpecUnit < s[j].SpecUnit
|
||||
}
|
||||
return s[i].NameID < s[j].NameID
|
||||
}
|
||||
|
||||
func (s SkuList) Swap(i, j int) {
|
||||
tmp := s[i]
|
||||
s[i] = s[j]
|
||||
s[j] = tmp
|
||||
}
|
||||
|
||||
func DownloadFileByURL(fileURL string) (bodyData []byte, fileMD5 string, err error) {
|
||||
response, err := http.Get(fileURL)
|
||||
if err == nil {
|
||||
@@ -582,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())
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -1,231 +0,0 @@
|
||||
package netprinter
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
)
|
||||
|
||||
const (
|
||||
testVendorOrderID = "test"
|
||||
realTestVendorOrderID = "901234567890123"
|
||||
realTestOrderVendorID = model.VendorIDJD
|
||||
)
|
||||
|
||||
const (
|
||||
PrinterNotifyUserApplyCancel = 1
|
||||
PrinterNotifyNewAfsOrder = 2
|
||||
)
|
||||
|
||||
func PrintOrder(ctx *jxcontext.Context, vendorOrderID string, vendorID int) (printResult *partner.PrinterStatus, err error) {
|
||||
storeID := vendorID
|
||||
if vendorOrderID == testVendorOrderID {
|
||||
vendorOrderID = realTestVendorOrderID
|
||||
vendorID = realTestOrderVendorID
|
||||
}
|
||||
order, err := partner.CurOrderManager.LoadOrder(vendorOrderID, vendorID)
|
||||
if err == nil {
|
||||
if vendorOrderID == realTestVendorOrderID {
|
||||
order.StoreID = storeID
|
||||
order.JxStoreID = storeID
|
||||
}
|
||||
printResult, err = PrintOrderByOrder(ctx, order)
|
||||
}
|
||||
return printResult, err
|
||||
}
|
||||
|
||||
func PrintOrderByOrder(ctx *jxcontext.Context, order *model.GoodsOrder) (printResult *partner.PrinterStatus, err error) {
|
||||
return PrintOrderByOrder4Store(ctx, order, jxutils.GetSaleStoreIDFromOrder(order))
|
||||
}
|
||||
|
||||
func getStore4Print(db *dao.DaoDB, storeID int) (store *model.Store, err error) {
|
||||
for i := 0; i < 3; i++ {
|
||||
store2 := &model.Store{}
|
||||
store2.ID = storeID
|
||||
if err = dao.GetEntity(db, store2); err == nil {
|
||||
store = store2
|
||||
if store.LinkStoreID != 0 {
|
||||
storeID = store.LinkStoreID
|
||||
} else {
|
||||
break
|
||||
}
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
if store != nil {
|
||||
err = nil
|
||||
}
|
||||
return store, err
|
||||
}
|
||||
|
||||
func PrintOrderByOrder4Store(ctx *jxcontext.Context, order *model.GoodsOrder, storeID int) (printResult *partner.PrinterStatus, err error) {
|
||||
globals.SugarLogger.Debugf("PrintOrderByOrder4Store orderID:%s", order.VendorOrderID)
|
||||
db := dao.GetDB()
|
||||
store, err := getStore4Print(db, storeID)
|
||||
if err == nil {
|
||||
handler, err := GetHandlerFromStore(store)
|
||||
if err != nil {
|
||||
return &partner.PrinterStatus{
|
||||
PrintResult: partner.PrintResultNoPrinter,
|
||||
}, nil
|
||||
}
|
||||
printResult, err = handler.PrintOrder(ctx, store, order)
|
||||
if err == nil {
|
||||
dao.SetOrderPrintFlag(db, ctx.GetUserName(), order.VendorOrderID, order.VendorID, true)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
globals.SugarLogger.Infof("PrintOrderByOrder4Store orderID:%s failed with error:%v", order.VendorOrderID, err)
|
||||
}
|
||||
return printResult, err
|
||||
}
|
||||
|
||||
func GetNetPrinterStatus(ctx *jxcontext.Context, storeID int) (printResult *partner.PrinterStatus, err error) {
|
||||
store := &model.Store{}
|
||||
store.ID = storeID
|
||||
db := dao.GetDB()
|
||||
if err = dao.GetEntity(db, store); err == nil {
|
||||
return getNetPrinterStatus(ctx, store)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func getNetPrinterStatus(ctx *jxcontext.Context, store *model.Store) (printResult *partner.PrinterStatus, err error) {
|
||||
handler, err := GetHandlerFromStore(store)
|
||||
if err != nil {
|
||||
return &partner.PrinterStatus{
|
||||
PrintResult: partner.PrintResultNoPrinter,
|
||||
}, nil
|
||||
}
|
||||
return handler.GetPrinterStatus(ctx, store.PrinterSN, store.PrinterKey)
|
||||
}
|
||||
|
||||
func GetHandlerFromStore(store *model.Store) (printerHandler partner.IPrinterHandler, err error) {
|
||||
if store.IsPrinterDisabled() {
|
||||
return nil, fmt.Errorf("门店%s没有启用网络打印机", store.Name)
|
||||
}
|
||||
if printerHandler = partner.GetPrinterPlatformFromVendorID(store.PrinterVendorID); printerHandler == nil {
|
||||
return nil, fmt.Errorf("门店%s没有配置网络打印机", store.Name)
|
||||
}
|
||||
return printerHandler, nil
|
||||
}
|
||||
|
||||
func BindPrinter(ctx *jxcontext.Context, storeID int, data string) (printResult *partner.PrinterStatus, err error) {
|
||||
store := &model.Store{}
|
||||
store.ID = storeID
|
||||
db := dao.GetDB()
|
||||
if err = dao.GetEntity(db, store); err == nil {
|
||||
var mapData map[string]interface{}
|
||||
if err = utils.UnmarshalUseNumber([]byte(data), &mapData); err == nil {
|
||||
printerVendorID := model.VendorIDUnknown
|
||||
if mapData["machineCode"] != nil {
|
||||
printerVendorID = model.VendorIDYiLianYun
|
||||
}
|
||||
if handler := partner.GetPrinterPlatformFromVendorID(printerVendorID); handler != nil {
|
||||
if store.PrinterVendorID > 0 && store.PrinterVendorID != printerVendorID {
|
||||
err = fmt.Errorf("门店:%d已经绑定了%s打印机,如果需要重新绑定,请联系运营先解绑", storeID, model.VendorChineseNames[store.PrinterVendorID])
|
||||
} else {
|
||||
bindResult, err2 := handler.BindPrinter(ctx, mapData)
|
||||
if err = err2; err == nil {
|
||||
store.PrinterVendorID = printerVendorID
|
||||
store.PrinterSN = bindResult.PrinterSN
|
||||
store.PrinterKey = bindResult.PrinterKey
|
||||
store.PrinterBindInfo = string(utils.MustMarshal(bindResult))
|
||||
if _, err = dao.UpdateEntity(db, store); err == nil {
|
||||
err = handler.EmptyPrintList(ctx, bindResult.PrinterSN, bindResult.PrinterKey)
|
||||
printResult, err = handler.GetPrinterStatus(ctx, bindResult.PrinterSN, bindResult.PrinterKey)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
err = fmt.Errorf("打印机类型:%d当前不支持", printerVendorID)
|
||||
}
|
||||
} else {
|
||||
err = fmt.Errorf("请扫描正确的二维码,如需要帮助,请联系运营!")
|
||||
}
|
||||
}
|
||||
return printResult, err
|
||||
}
|
||||
|
||||
func RebindAllPrinters(ctx *jxcontext.Context, isForce, isAsync bool) (hint string, err error) {
|
||||
storeList, err := dao.GetRebindPrinterStoreList(dao.GetDB())
|
||||
if err == nil {
|
||||
var needRebindList []*model.Store
|
||||
bindResultMap := make(map[int]*partner.BindPrinterResult)
|
||||
now := time.Now()
|
||||
for _, v := range storeList {
|
||||
var bindResult partner.BindPrinterResult
|
||||
if err = utils.UnmarshalUseNumber([]byte(v.PrinterBindInfo), &bindResult); err == nil {
|
||||
if isForce || now.Sub(utils.Timestamp2Time(bindResult.ExpiresAt)) > -3*24*time.Hour {
|
||||
needRebindList = append(needRebindList, v)
|
||||
bindResultMap[v.ID] = &bindResult
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
globals.SugarLogger.Debugf("RebindAllPrinters len(needRebindList):%d", len(needRebindList))
|
||||
if len(needRebindList) > 0 {
|
||||
db := dao.GetDB()
|
||||
task := tasksch.NewParallelTask("RebindAllPrinters", tasksch.NewParallelConfig().SetIsContinueWhenError(true).SetParallelCount(4), ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
store := batchItemList[0].(*model.Store)
|
||||
if handler := partner.GetPrinterPlatformFromVendorID(store.PrinterVendorID); handler != nil {
|
||||
bindResult, err2 := handler.RebindPrinter(ctx, bindResultMap[store.ID])
|
||||
globals.SugarLogger.Debugf("RebindAllPrinters storeID:%d, result:%s, err:%v", store.ID, utils.Format4Output(bindResult, true), err2)
|
||||
if err = err2; err == nil {
|
||||
store.PrinterSN = bindResult.PrinterSN
|
||||
store.PrinterKey = bindResult.PrinterKey
|
||||
store.PrinterBindInfo = string(utils.MustMarshal(bindResult))
|
||||
if _, err = dao.UpdateEntity(db, store); err == nil {
|
||||
retVal = []int{1}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
globals.SugarLogger.Warnf("RebindAllPrinters strange PrinterVendorID:%d", store.PrinterVendorID)
|
||||
}
|
||||
return retVal, err
|
||||
}, needRebindList)
|
||||
|
||||
tasksch.ManageTask(task).Run()
|
||||
if !isAsync {
|
||||
hint = task.GetID()
|
||||
} else {
|
||||
result, err2 := task.GetResult(0)
|
||||
if err = err2; err == nil {
|
||||
hint = utils.Int2Str(len(result))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return hint, err
|
||||
}
|
||||
|
||||
func NofityOrderMsg(ctx *jxcontext.Context, storeID int, orderID, notifyMsg string) (err error) {
|
||||
if notifyMsg != "" {
|
||||
notifyMsg = strings.ReplaceAll(notifyMsg, ",", "")
|
||||
db := dao.GetDB()
|
||||
store := &model.Store{}
|
||||
store.ID = storeID
|
||||
if err = dao.GetEntity(db, store); err == nil {
|
||||
handler, err := GetHandlerFromStore(store)
|
||||
if err == nil {
|
||||
if globals.EnableStoreWrite {
|
||||
_, err = handler.PlayText(ctx, store.PrinterSN, store.PrinterKey, orderID, notifyMsg)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -8,8 +8,6 @@ import (
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/baseapi/utils/errlist"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
)
|
||||
@@ -23,13 +21,13 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
func SendSMSMsg(mobileList []string, signName, templateCode string, templateParam map[string]interface{}, order *model.GoodsOrder) (err error) {
|
||||
func SendSMSMsg(mobileList []string, signName, templateCode string, templateParam map[string]interface{}) (err error) {
|
||||
if len(mobileList) > 0 {
|
||||
errList := errlist.New()
|
||||
mobileList = jxutils.StringMap2List(jxutils.StringList2Map(mobileList))
|
||||
for _, mobileNum := range mobileList {
|
||||
if mobileNum != "" {
|
||||
globals.SugarLogger.Debugf("SendSMSMsg mobileNum:%s, templateCode:%s", mobileNum, templateCode)
|
||||
globals.SugarLogger.Debugf("SendSMSMsg 1 mobileNum:%s, templateCode:%s", mobileNum, templateCode)
|
||||
if true { //globals.EnableStoreWrite {
|
||||
if response, err := api.SMSClient.Execute(globals.AliKey, globals.AliSecret, mobileNum, signName, templateCode, string(utils.MustMarshal(templateParam))); err != nil {
|
||||
globals.SugarLogger.Warnf("SendSMSMsg mobileNum:%s failed with error:%v", mobileNum, err)
|
||||
@@ -42,10 +40,6 @@ func SendSMSMsg(mobileList []string, signName, templateCode string, templatePara
|
||||
} else {
|
||||
globals.SugarLogger.Infof(errMsg)
|
||||
}
|
||||
} else {
|
||||
if order != nil {
|
||||
err = updateStoreSMSNotifyMark(order)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -54,147 +48,3 @@ func SendSMSMsg(mobileList []string, signName, templateCode string, templatePara
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func getOrderNotifyPhone(order *model.GoodsOrder) (phoneList []string) {
|
||||
return dao.GetOrderNotifyPhones(dao.GetDB(), jxutils.GetSaleStoreIDFromOrder(order))
|
||||
}
|
||||
|
||||
func NotifyNewOrder(order *model.GoodsOrder) (err error) {
|
||||
if isPushSMS(order) {
|
||||
err = SendSMSMsg(getOrderNotifyPhone(order), globals.SMSSignName, globals.SMSNewOrderTemplate, map[string]interface{}{
|
||||
"daySeq": order.OrderSeq,
|
||||
"consigneeName": order.ConsigneeName,
|
||||
"payMoney": jxutils.IntPrice2StandardString(order.ActualPayPrice),
|
||||
}, order)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func NotifyOrderCanceled(order *model.GoodsOrder) (err error) {
|
||||
err = SendSMSMsg(getOrderNotifyPhone(order), globals.SMSSignName, globals.SMSOrderCanceledTemplate, map[string]interface{}{
|
||||
"vendorName": model.VendorChineseNames[order.VendorID],
|
||||
"seq": order.OrderSeq,
|
||||
"orderID": order.VendorOrderID,
|
||||
}, order)
|
||||
return err
|
||||
}
|
||||
|
||||
func isPushSMS(order *model.GoodsOrder) bool {
|
||||
storeID := 0
|
||||
if order.StoreID == 0 {
|
||||
storeID = order.JxStoreID
|
||||
} else {
|
||||
storeID = order.StoreID
|
||||
}
|
||||
stores, _ := dao.GetStoresMapList(dao.GetDB(), []int{order.VendorID}, []int{storeID}, nil, model.StoreStatusAll, model.StoreIsSyncAll, "", "")
|
||||
if len(stores) > 0 {
|
||||
if stores[0].IsOrder == model.NO {
|
||||
if storeID == model.MatterStoreID {
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func updateStoreSMSNotifyMark(order *model.GoodsOrder) (err error) {
|
||||
var db = dao.GetDB()
|
||||
stores, _ := dao.GetStoreList(db, []int{order.StoreID}, nil, nil, nil, "")
|
||||
if len(stores) > 0 {
|
||||
stores[0].SMSNotifyMark = model.YES
|
||||
_, err = dao.UpdateEntity(db, stores[0], "SMSNotifyMark")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
//每月向用户发送
|
||||
func NotifyNewUserOrder(order *model.GoodsOrder) (err error) {
|
||||
var (
|
||||
db = dao.GetDB()
|
||||
storeTel string
|
||||
storeID int
|
||||
mobile string
|
||||
)
|
||||
if order.StoreID == 0 {
|
||||
storeID = order.JxStoreID
|
||||
} else {
|
||||
storeID = order.StoreID
|
||||
}
|
||||
if order.ConsigneeMobile2 != "" {
|
||||
mobile = order.ConsigneeMobile2
|
||||
uoSMS, err := dao.GetUserOrderSMS(db, mobile, "")
|
||||
stores, _ := dao.GetStoreList(db, []int{storeID}, nil, nil, nil, "")
|
||||
if len(stores) > 0 {
|
||||
if stores[0].Tel1 == "" {
|
||||
storeTel = stores[0].Tel2
|
||||
} else {
|
||||
storeTel = stores[0].Tel1
|
||||
}
|
||||
}
|
||||
if uoSMS == nil {
|
||||
uoSMSc := &model.UserOrderSms{
|
||||
Mobile: mobile,
|
||||
Name: order.ConsigneeName,
|
||||
VendorUserID: order.VendorUserID,
|
||||
TotalCount: 0,
|
||||
SMSMark: model.NO,
|
||||
}
|
||||
err = dao.CreateEntity(db, uoSMSc)
|
||||
err = SendSMSMsg([]string{uoSMSc.Mobile}, globals.SMSSignName, globals.SMSNewUserOrderTemplate, map[string]interface{}{
|
||||
"tel": storeTel,
|
||||
}, nil)
|
||||
if err == nil {
|
||||
uoSMS2, _ := dao.GetUserOrderSMS(db, mobile, "")
|
||||
uoSMS2.SMSMark = model.YES
|
||||
uoSMS2.TotalCount++
|
||||
_, err = dao.UpdateEntity(db, uoSMS2, "SMSMark", "TotalCount")
|
||||
}
|
||||
} else {
|
||||
if uoSMS.SMSMark != model.YES {
|
||||
err = SendSMSMsg([]string{uoSMS.Mobile}, globals.SMSSignName, globals.SMSNewUserOrderTemplate, map[string]interface{}{
|
||||
"tel": storeTel,
|
||||
}, nil)
|
||||
if err == nil {
|
||||
uoSMS.SMSMark = model.YES
|
||||
uoSMS.TotalCount++
|
||||
_, err = dao.UpdateEntity(db, uoSMS, "SMSMark", "TotalCount")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
//给配送员发短信
|
||||
func NotifyNewCourierOrder(bill *model.Waybill) (err error) {
|
||||
var (
|
||||
db = dao.GetDB()
|
||||
storeTel string
|
||||
storeID int
|
||||
)
|
||||
order := &model.GoodsOrder{}
|
||||
order.VendorOrderID = bill.VendorOrderID
|
||||
err = dao.GetEntity(db, order, "VendorOrderID")
|
||||
if order.StoreID == 0 {
|
||||
storeID = order.JxStoreID
|
||||
} else {
|
||||
storeID = order.StoreID
|
||||
}
|
||||
stores, _ := dao.GetStoreList(db, []int{storeID}, nil, nil, nil, "")
|
||||
if len(stores) > 0 {
|
||||
if stores[0].Tel1 == "" {
|
||||
storeTel = stores[0].Tel2
|
||||
} else {
|
||||
storeTel = stores[0].Tel1
|
||||
}
|
||||
}
|
||||
err = SendSMSMsg([]string{bill.CourierMobile}, globals.SMSSignName, globals.SMSNewOrderTemplate, map[string]interface{}{
|
||||
"tel": storeTel,
|
||||
}, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
package storeskulock
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
)
|
||||
|
||||
const (
|
||||
cacheKeyPrefix = "jdpromotion"
|
||||
)
|
||||
|
||||
func LockJdStoreSku(jdStoreID string, jdSkuID int64, expire time.Time) {
|
||||
return
|
||||
globals.SugarLogger.Debug(expire, " ", time.Now())
|
||||
duration := expire.Sub(time.Now())
|
||||
if duration > 0 {
|
||||
api.Cacher.Set(genCacheKey(jdStoreID, jdSkuID), 1, duration)
|
||||
}
|
||||
}
|
||||
|
||||
func UnlockJdStoreSku(jdStoreID string, jdSkuID int64) {
|
||||
api.Cacher.Del(genCacheKey(jdStoreID, jdSkuID))
|
||||
}
|
||||
|
||||
func IsJdStoreSkuLocked(jdStoreID string, jdSkuID int64) bool {
|
||||
return false
|
||||
return api.Cacher.Get(genCacheKey(jdStoreID, jdSkuID)) != nil
|
||||
}
|
||||
|
||||
func ClearJdStoreSkuLock() {
|
||||
api.Cacher.FlushKeys(cacheKeyPrefix)
|
||||
}
|
||||
|
||||
func genCacheKey(jdStoreID string, jdSkuID int64) string {
|
||||
return fmt.Sprintf("%s.%s.%d", cacheKeyPrefix, jdStoreID, jdSkuID)
|
||||
}
|
||||
@@ -15,12 +15,11 @@ import (
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/weimobapi"
|
||||
"git.rosy.net.cn/baseapi/platformapi/yilianyunapi"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/astaxie/beego/orm"
|
||||
beego "github.com/astaxie/beego/adapter"
|
||||
"github.com/astaxie/beego/client/orm"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -139,87 +138,6 @@ func RefreshWeixinToken() (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
func RefreshWeixin2Token() (err error) {
|
||||
if api.WeixinMiniAPI2 != nil {
|
||||
err = RefreshConfig("wechat2", weixinTokenExpires, func() (token string, expireTimeStr string) {
|
||||
globals.SugarLogger.Debugf("RefreshWeixin2Token RunMode:%s", beego.BConfig.RunMode)
|
||||
if globals.IsMainProductEnv() {
|
||||
if tokenInfo, err := api.WeixinMiniAPI2.CBRetrieveToken(); err == nil {
|
||||
globals.SugarLogger.Debugf("RefreshWeixin2Token tokenInfo:%s", utils.Format4Output(tokenInfo, true))
|
||||
token = tokenInfo.AccessToken
|
||||
} else {
|
||||
globals.SugarLogger.Errorf("RefreshWeixin2Token RefreshToken failed with error:%v", err)
|
||||
}
|
||||
} else {
|
||||
if tokenInfo := getWX2TokenFromRemote(api.WeixinMiniAPI2.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.OnNewWX2Token(value)
|
||||
api.WeixinMiniAPI2.CBSetToken(value)
|
||||
})
|
||||
}
|
||||
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) {
|
||||
@@ -282,33 +200,6 @@ func SaveWeimobToken(token *weimobapi.TokenInfo) (err error) {
|
||||
return dao.CreateOrUpdate(db, config)
|
||||
}
|
||||
|
||||
func RefreshYilianyunToken() (err error) {
|
||||
return RefreshConfig("yilianyun", yilianyunTokenExpires, func() (token string, expireTimeStr string) {
|
||||
globals.SugarLogger.Debugf("RefreshYilianyunToken RunMode:%s", beego.BConfig.RunMode)
|
||||
if globals.IsMainProductEnv() { // 只有京西菜市刷新易联云key
|
||||
if tokenInfo, err := api.YilianyunAPI.RetrieveToken(); err == nil {
|
||||
token = string(utils.MustMarshal(tokenInfo))
|
||||
} else {
|
||||
globals.SugarLogger.Errorf("RefreshYilianyunToken RefreshToken failed with error:%v", err)
|
||||
}
|
||||
} else {
|
||||
if tokenInfo := getYLYTokenFromRemote(api.YilianyunAPI.GetToken()); tokenInfo != nil {
|
||||
expireTimeStr = utils.Time2Str(time.Now().Add(-yilianyunTokenExpires))
|
||||
token = tokenInfo.Token
|
||||
}
|
||||
}
|
||||
return token, expireTimeStr
|
||||
}, func(value string) {
|
||||
token := value
|
||||
var tokenInfo *yilianyunapi.TokenInfo
|
||||
if err := utils.TryUnmarshalUseNumber([]byte(value), &tokenInfo); err == nil {
|
||||
token = tokenInfo.AccessToken
|
||||
}
|
||||
syseventhub.SysEventHub.OnNewYLYToken(token)
|
||||
api.YilianyunAPI.SetToken(token)
|
||||
})
|
||||
}
|
||||
|
||||
func PollingRemotEvent(remoteURL string, waitSecond int, params map[string]interface{}) (tokenInfo *syseventhub.TokenInfo) {
|
||||
if waitSecond == 0 {
|
||||
waitSecond = 5 * 60
|
||||
|
||||
@@ -476,7 +476,9 @@ func (t *BaseTask) run(taskHandler func()) {
|
||||
if t.finishHook != nil {
|
||||
t.finishHook(t)
|
||||
} else {
|
||||
SendMessage(t)
|
||||
if globals.IsMainProductEnv() {
|
||||
SendMessage(t)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user