Compare commits
1991 Commits
c1f973df21
...
rsm
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9d19b162cc | ||
|
|
de1c4d00de | ||
|
|
eaa27cbaa7 | ||
|
|
f2ce2db029 | ||
|
|
29634ad17f | ||
|
|
3cb53546f8 | ||
|
|
35c8468789 | ||
|
|
040f0b7d8d | ||
|
|
d339ebb47b | ||
|
|
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 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -14,5 +14,4 @@ param_parser.go
|
||||
*.exe
|
||||
*.exe~
|
||||
.vscode
|
||||
.idea
|
||||
./swagger
|
||||
.idea
|
||||
@@ -1,32 +0,0 @@
|
||||
package app_version
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
)
|
||||
|
||||
// AddApplicationVersion 添加app版本控制
|
||||
func AddApplicationVersion(userName, appId, version string) error {
|
||||
config := &model.NewConfig{
|
||||
Type: model.ConfigTypeApplication,
|
||||
Key: appId,
|
||||
Value: version,
|
||||
}
|
||||
dao.WrapAddIDCULDEntity(config, userName)
|
||||
return dao.CreateEntity(dao.GetDB(), config)
|
||||
}
|
||||
|
||||
// UpdateApplicationVersion 修改app版本
|
||||
func UpdateApplicationVersion(appId, version string) error {
|
||||
sql := ` UPDATE new_config c SET c.value = ? WHERE c.key = ? AND c.deleted_at = ? `
|
||||
param := []interface{}{version, appId, utils.DefaultTimeValue}
|
||||
|
||||
_, err := dao.ExecuteSQL(dao.GetDB(), sql, param...)
|
||||
return err
|
||||
}
|
||||
|
||||
// GetApplicationVersion 查询小程序版本控制
|
||||
func GetApplicationVersion(appId string) ([]*model.NewConfig, error) {
|
||||
return dao.QueryConfigs(dao.GetDB(), appId, model.ConfigTypeApplication, "")
|
||||
}
|
||||
@@ -3,8 +3,8 @@ package auth2
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
"github.com/dchest/captcha"
|
||||
)
|
||||
@@ -32,18 +33,15 @@ const (
|
||||
)
|
||||
|
||||
const (
|
||||
AuthTypeNone = ""
|
||||
AuthTypePassword = "localpass"
|
||||
AuthTypeEmail = "email"
|
||||
AuthTypeMobile = "mobile"
|
||||
AuthTypeWXApp = "weixinapp" //微信小程序(商家版)
|
||||
AuthTypeWXAppCaishi = "weixinappcs" //微信小程序(用户)
|
||||
AuthTypeWXMini = "weixinmini" //微信小程序
|
||||
AuthTypeNone = ""
|
||||
AuthTypePassword = "localpass"
|
||||
AuthTypeEmail = "email"
|
||||
AuthTypeMobile = "mobile"
|
||||
)
|
||||
|
||||
const (
|
||||
DefTokenDuration = 7 * 24 * 2 * time.Hour // 正式TOKEN,7天有效期
|
||||
TmpTokenDuration = 30 * time.Minute // 临时TOKEN,30分钟有效期
|
||||
DefTokenDuration = 7 * 24 * time.Hour // 正式TOKEN,7天有效期
|
||||
TmpTokenDuration = 30 * time.Minute // 临时TOKEN,30分钟有效期
|
||||
MinCaptchaLen = 4
|
||||
MaxCaptchaWidth = 400
|
||||
MaxCaptchaHeight = 400
|
||||
@@ -64,7 +62,6 @@ const (
|
||||
UpdateUserTypeAdd = 1
|
||||
UpdateUserTypeDelete = 2
|
||||
UpdateUserTypeUpdate = 3
|
||||
WeCartAppID = "wx4b5930c13f8b1170"
|
||||
)
|
||||
|
||||
type IUserProvider interface {
|
||||
@@ -162,7 +159,6 @@ func getFixedTokenName(token string) *AuthInfo {
|
||||
|
||||
func createAuthInfo(user IUser, authBindInfo *AuthBindEx) (authInfo *AuthInfo) {
|
||||
token, tokenType := createToken(user, authBindInfo)
|
||||
//user为空 tokenType=2
|
||||
expireDuration := DefTokenDuration
|
||||
authInfo = &AuthInfo{
|
||||
AuthBindInfo: authBindInfo,
|
||||
@@ -173,9 +169,11 @@ func createAuthInfo(user IUser, authBindInfo *AuthBindEx) (authInfo *AuthInfo) {
|
||||
}
|
||||
if user != nil {
|
||||
authInfo.UpdateByIUser(user)
|
||||
globals.SugarLogger.Debugf("createAuthInfo id:%s, id2:%s, mobile:%s, authInfo:%s", authInfo.GetID(), authInfo.GetID2(), authInfo.GetMobile(), utils.Format4Output(authInfo, true))
|
||||
} else {
|
||||
expireDuration = TmpTokenDuration
|
||||
authInfo.ExpiresAt = time.Now().Add(expireDuration).Unix()
|
||||
globals.SugarLogger.Debugf("createAuthInfo authInfo:%s", utils.Format4Output(authInfo, true))
|
||||
}
|
||||
SetUserInfo(token, authInfo, expireDuration)
|
||||
return authInfo
|
||||
@@ -215,9 +213,6 @@ func SendVerifyCode(authToken, captchaID, captchaValue, authID string) (verfifyC
|
||||
if handler := authers[authType]; handler == nil {
|
||||
err = ErrIllegalAuthType
|
||||
} else {
|
||||
//if user, _ := dao.GetUserByID(dao.GetDB(), "mobile", authID); user != nil {
|
||||
// return "", authInfo, fmt.Errorf("该用户已存在,请勿重复注册!")
|
||||
//}
|
||||
verfifyCode, err = handler.SendVerifyCode(authID)
|
||||
}
|
||||
}
|
||||
@@ -248,8 +243,7 @@ func LoginInternal(ctx *Context, authType, authID, authIDType, authSecret string
|
||||
}
|
||||
realAuthID = user.GetID()
|
||||
}
|
||||
authBindEx, err = handler.VerifySecret(realAuthID, authSecret)
|
||||
if err == nil {
|
||||
if authBindEx, err = handler.VerifySecret(realAuthID, authSecret); err == nil {
|
||||
if authBindEx == nil { // mobile, email会返回nil(表示不会新建AuthBind实体)
|
||||
user = userProvider.GetUser(authID, authIDType)
|
||||
authBindEx = &AuthBindEx{
|
||||
@@ -263,18 +257,15 @@ func LoginInternal(ctx *Context, authType, authID, authIDType, authSecret string
|
||||
// 返回authBind中UserID为空表示只是认证,但本地没有记录,这种情况会返回临时TOKEN
|
||||
if authBindEx.UserHint != nil && authBindEx.UserID == "" {
|
||||
// 利用得到受信任的信息查找用户
|
||||
if authBindEx.UserHint.Mobile != "" {
|
||||
user = userProvider.GetUser(authBindEx.UserHint.Mobile, UserIDMobile)
|
||||
}
|
||||
if user == nil && authBindEx.UserHint.Email != "" {
|
||||
user = userProvider.GetUser(authBindEx.UserHint.Email, UserIDEmail)
|
||||
}
|
||||
if user != nil {
|
||||
authBindEx.UserID = user.GetID()
|
||||
}
|
||||
if user2 := userProvider.GetUser(authBindEx.UserHint.Email, UserIDMobile); user2 != nil {
|
||||
user = user2
|
||||
}
|
||||
// if authBindEx.UserHint.Mobile != "" {
|
||||
// user = userProvider.GetUser(authBindEx.UserHint.Mobile, UserIDMobile)
|
||||
// }
|
||||
// if user == nil && authBindEx.UserHint.Email != "" {
|
||||
// user = userProvider.GetUser(authBindEx.UserHint.Email, UserIDEmail)
|
||||
// }
|
||||
// if user != nil {
|
||||
// authBindEx.UserID = user.GetID()
|
||||
// }
|
||||
} else if authBindEx.UserID != "" {
|
||||
user = userProvider.GetUser(authBindEx.UserID, UserIDID)
|
||||
}
|
||||
@@ -284,12 +275,11 @@ func LoginInternal(ctx *Context, authType, authID, authIDType, authSecret string
|
||||
userProvider.UpdateLastLogin(user.GetID(), authType, ctx.GetRealRemoteIP())
|
||||
}
|
||||
//如果是小程序
|
||||
if authType == AuthTypeWXMini { // || authType == AuthTypeWXApp 此处AuthTypeWXApp没用上
|
||||
if authType == "weixinmini" || authType == "weixinapp" {
|
||||
appID := strings.Split(authSecret, ",")[0]
|
||||
// 菜市商家 // // // 京西商城
|
||||
if appID == model.JXC4BusinessAppId || appID == "wx2d6949f724b2541d" || appID == "wx18111a41fd17f24f" || appID == model.JXC4AppId { //菜市或者果园
|
||||
if authInfo.AuthBindInfo.UserID != "" {
|
||||
binds, err := dao.GetUserBindAuthInfo(dao.GetDB(), authInfo.AuthBindInfo.UserID, 0, nil, "", "", []string{"wx2bb99eb5d2c9b82c", "wx4b5930c13f8b1170"})
|
||||
if appID == "wxa4a76d7b4c88604e" || appID == "wx2d6949f724b2541d" || appID == "wx18111a41fd17f24f" { //菜市或者果园
|
||||
if user != nil {
|
||||
binds, err := dao.GetUserBindAuthInfo(dao.GetDB(), user.GetID(), 0, nil, "", "", "wx2bb99eb5d2c9b82c")
|
||||
if err != nil {
|
||||
return authInfo, err
|
||||
}
|
||||
@@ -298,29 +288,9 @@ func LoginInternal(ctx *Context, authType, authID, authIDType, authSecret string
|
||||
} else {
|
||||
authInfo.IsExistOpenID = true
|
||||
}
|
||||
if WeCartAppID == appID {
|
||||
authInfo.AppID = WeCartAppID
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//微信APP端登录
|
||||
if authType == AuthTypeWXApp || authType == AuthTypeWXAppCaishi {
|
||||
appID := strings.Split(authSecret, ",")[0]
|
||||
if appID == model.JXC4ClientAppID && authInfo.AuthBindInfo.UserID != "" {
|
||||
binds, err := dao.GetUserBindAuthInfo(dao.GetDB(), authInfo.AuthBindInfo.UserID, 0, nil, "", "", []string{model.JXC4ClientAppID})
|
||||
if err != nil {
|
||||
return authInfo, err
|
||||
}
|
||||
if len(binds) == 0 {
|
||||
authInfo.IsExistOpenID = false
|
||||
} else {
|
||||
authInfo.IsExistOpenID = true
|
||||
}
|
||||
authInfo.AppID = model.JXC4ClientAppID
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
err = ErrIllegalAuthType
|
||||
@@ -335,59 +305,6 @@ func Login(ctx *Context, authType, authID, authIDType, authSecret string) (authI
|
||||
return LoginInternal(ctx, authType, authID, authIDType, authSecret)
|
||||
}
|
||||
|
||||
// TikTokDecryptInfo 抖音用户信息解密
|
||||
type TikTokDecryptInfo struct {
|
||||
CountryCode string `json:"countryCode"`
|
||||
PhoneNumber string `json:"phoneNumber"`
|
||||
PurePhoneNumber string `json:"purePhoneNumber"`
|
||||
Watermark *struct {
|
||||
AppID string `json:"appid"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
} `json:"watermark"`
|
||||
}
|
||||
|
||||
// KuaiShouInfo 抖音用户信息解密
|
||||
type KuaiShouInfo struct {
|
||||
CountryCode string `json:"countryCode"`
|
||||
PhoneNumber string `json:"phoneNumber"`
|
||||
}
|
||||
|
||||
func DecryptUserMsg(sessionKey, iv, msg, loginType string) (string, error) {
|
||||
decodeMsg, err := base64.StdEncoding.DecodeString(msg)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
decodeIv, err := base64.StdEncoding.DecodeString(iv)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
decodeSessionKey, err := base64.StdEncoding.DecodeString(sessionKey)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
userInfo, err := utils.AESCBC16Decrypt(decodeSessionKey, decodeIv, decodeMsg)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
switch loginType {
|
||||
case "tiktokmini":
|
||||
result := &TikTokDecryptInfo{}
|
||||
if err := json.Unmarshal(userInfo, result); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return result.PhoneNumber, nil
|
||||
case "kuaishoumini":
|
||||
result := &KuaiShouInfo{}
|
||||
if err := json.Unmarshal(userInfo, result); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return result.PhoneNumber, nil
|
||||
}
|
||||
return "", ErrIllegalAuthType
|
||||
}
|
||||
|
||||
// 通过临时TOKEN绑定新创建的用户
|
||||
func BindUser(inauthInfo *AuthInfo, user IUser) (outauthInfo *AuthInfo, err error) {
|
||||
if err = AddAuthBind(user, inauthInfo); err == nil {
|
||||
@@ -399,6 +316,7 @@ func BindUser(inauthInfo *AuthInfo, user IUser) (outauthInfo *AuthInfo, err erro
|
||||
|
||||
// 添加新绑定
|
||||
func AddAuthBind(user IUser, newAuthInfo *AuthInfo) (err error) {
|
||||
globals.SugarLogger.Debugf("AddAuthBind user:%s, newAuthInfo:%s", utils.Format4Output(user, true), utils.Format4Output(newAuthInfo, true))
|
||||
if user == nil || newAuthInfo == nil {
|
||||
return ErrInternalErrror
|
||||
}
|
||||
@@ -424,10 +342,7 @@ func AddAuthBind(user IUser, newAuthInfo *AuthInfo) (err error) {
|
||||
|
||||
func AddAuthBindWithMobile(authInfo *AuthInfo, mobile string) (err error) {
|
||||
if handler := authers[authInfo.AuthBindInfo.Type]; handler != nil {
|
||||
user, err := dao.GetUserByID(dao.GetDB(), "mobile", mobile)
|
||||
if err != nil {
|
||||
return errors.New("此接口有执行顺序,请先调用注册登录接口:【第一步:Login,第二步:TiktokDecrypt】")
|
||||
}
|
||||
user, _ := dao.GetUserByID(dao.GetDB(), "mobile", mobile)
|
||||
authInfo.AuthBindInfo.UserID = user.UserID
|
||||
//handler.UnbindAuth(user.GetID(), newAuthInfo.GetAuthType(), newAuthInfo.GetAuthTypeID(), user.GetName())
|
||||
err = handler.AddAuthBind(authInfo.AuthBindInfo, user.GetName())
|
||||
@@ -438,6 +353,7 @@ func AddAuthBindWithMobile(authInfo *AuthInfo, mobile string) (err error) {
|
||||
}
|
||||
|
||||
func UnbindAuth(userID, authType, authTypeID, userName string) (err error) {
|
||||
globals.SugarLogger.Debugf("UnbindAuth userID:%s, authType:%s, authTypeID:%s, userName:%s", userID, authType, authTypeID, userName)
|
||||
if handler := authers[authType]; handler != nil {
|
||||
err = handler.UnbindAuth(userID, authType, authTypeID, userName)
|
||||
} else {
|
||||
@@ -447,6 +363,7 @@ func UnbindAuth(userID, authType, authTypeID, userName string) (err error) {
|
||||
}
|
||||
|
||||
func Logout(authInfo *AuthInfo) (err error) {
|
||||
globals.SugarLogger.Debugf("Logout authInfo:%s", utils.Format4Output(authInfo, true))
|
||||
if handler := authers[authInfo.AuthBindInfo.Type]; handler != nil {
|
||||
err = handler.Logout(authInfo)
|
||||
}
|
||||
@@ -488,6 +405,8 @@ func ClearUserToken(userID string) {
|
||||
}
|
||||
}
|
||||
|
||||
/////////////
|
||||
|
||||
func createToken(user IUser, authBindInfo *AuthBindEx) (token string, tokenType int) {
|
||||
userID := TokenUserEmpty
|
||||
userName := authBindInfo.AuthID
|
||||
@@ -556,7 +475,7 @@ func DisableUser(userID, operatorUserName string) (err error) {
|
||||
}
|
||||
|
||||
func GetUserBindAuthInfo(userID string) (authList []*model.AuthBind, err error) {
|
||||
return dao.GetUserBindAuthInfo(dao.GetDB(), userID, model.AuthBindTypeAuth, nil, "", "", nil)
|
||||
return dao.GetUserBindAuthInfo(dao.GetDB(), userID, model.AuthBindTypeAuth, nil, "", "", "")
|
||||
}
|
||||
|
||||
func DeletedTokenInfoWithoutParam(authInfo *AuthInfo) (err error) {
|
||||
@@ -569,3 +488,16 @@ func DeletedTokenInfoWithoutParam(authInfo *AuthInfo) (err error) {
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func CheckWeixinminiAuthBind(userID string) (err error) {
|
||||
var (
|
||||
db = dao.GetDB()
|
||||
)
|
||||
authBinds, err := dao.GetUserBindAuthInfo(db, userID, model.AuthBindTypeAuth, []string{"weixinmini", "weixinapp"}, "", "", "")
|
||||
if len(authBinds) == 0 {
|
||||
return fmt.Errorf("请绑定微信认证方式!")
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
)
|
||||
|
||||
type Context struct {
|
||||
@@ -20,6 +21,7 @@ func NewContext(w http.ResponseWriter, r *http.Request) (ctx *Context) {
|
||||
r: r,
|
||||
accessUUID: utils.GetUUID(),
|
||||
}
|
||||
globals.SugarLogger.Debugf("NewContext ip:%s", ctx.GetRealRemoteIP())
|
||||
return ctx
|
||||
}
|
||||
|
||||
@@ -38,6 +40,7 @@ func (ctx *Context) GetTrackInfo() string {
|
||||
func (ctx *Context) GetRealRemoteIP() (ip string) {
|
||||
r := ctx.r
|
||||
if r != nil {
|
||||
// globals.SugarLogger.Debugf("GetRealRemoteIP header:%s", utils.Format4Output(r.Header, false))
|
||||
ip = r.Header.Get("X-Forwarded-For")
|
||||
if ip == "" {
|
||||
ip = r.Header.Get("X-real-ip")
|
||||
|
||||
@@ -74,7 +74,6 @@ type AuthInfo struct {
|
||||
Token string `json:"token"`
|
||||
TokenType int `json:"tokenType"` // TOKEN类型,
|
||||
IsExistOpenID bool `json:"isExistOpenID"`
|
||||
AppID string `json:"appId"` // appId
|
||||
}
|
||||
|
||||
func (a *AuthInfo) GetAuthID() string {
|
||||
|
||||
@@ -4,13 +4,12 @@ import (
|
||||
"git.rosy.net.cn/baseapi/platformapi/alipayapi"
|
||||
"git.rosy.net.cn/jx-callback/business/auth2"
|
||||
"git.rosy.net.cn/jx-callback/business/auth2/authprovider"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
)
|
||||
|
||||
const (
|
||||
AuthType = "alipaycode"
|
||||
|
||||
AuthKey = "GHp3ojlVYRRu2XID4FX2ew=="
|
||||
)
|
||||
|
||||
type Auther struct {
|
||||
@@ -27,13 +26,17 @@ func init() {
|
||||
}
|
||||
|
||||
func (a *Auther) VerifySecret(dummy, code string) (authBindEx *auth2.AuthBindEx, err error) {
|
||||
globals.SugarLogger.Debugf("VerifySecret dummy:%s, code:%s", dummy, code)
|
||||
tokenInfo, err := api.AliPayAPI.SystemAuthToken(alipayapi.GrantTypeCode, code, "")
|
||||
if err == nil {
|
||||
//userInfo, err2 := api.AliPayAPI.UserInfoShare(tokenInfo.AccessToken)
|
||||
//if err = err2; err == nil {
|
||||
if authBindEx, err = a.UnionFindAuthBind(AuthType, api.AliPayAPI.GetAppID(), nil, tokenInfo.UserID, tokenInfo.AlipayUserID, tokenInfo); err == nil {
|
||||
authBindEx.AuthSecret = tokenInfo.AccessToken
|
||||
authBindEx.AuthSecret2 = tokenInfo.RefreshToken
|
||||
userInfo, err2 := api.AliPayAPI.UserInfoShare(tokenInfo.AccessToken)
|
||||
if err = err2; err == nil {
|
||||
if authBindEx, err = a.UnionFindAuthBind(AuthType, api.AliPayAPI.GetAppID(), nil, userInfo.UserID, "", userInfo); err == nil {
|
||||
authBindEx.UserHint = &auth2.UserBasic{
|
||||
Name: userInfo.NickName,
|
||||
Avatar: userInfo.Avatar,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return authBindEx, err
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"git.rosy.net.cn/jx-callback/business/auth2"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
)
|
||||
|
||||
@@ -35,6 +36,7 @@ func (a *DefAuther) AddAuthBind(authBindEx *auth2.AuthBindEx, userName string) (
|
||||
}
|
||||
|
||||
func (a *DefAuther) UnbindAuth(userID, authType, authTypeID, userName string) (err error) {
|
||||
globals.SugarLogger.Debugf("DefAuther.UnbindAuth userID:%s, authType:%s, GetAuthTypeID:%s, userName:%s", userID, authType, authTypeID, userName)
|
||||
condition := map[string]interface{}{
|
||||
"UserID": userID,
|
||||
"Type": authType,
|
||||
@@ -62,6 +64,8 @@ func (a *DefAuther) GetUserType() (userType int8) {
|
||||
|
||||
// 此函数用于联合(通过unionID)查找用户
|
||||
func (a *DefAuther) UnionFindAuthBind(curAuthType, curAuthTypeID string, unionAuthTypeList []string, openID, unionID string, authDetail interface{}) (authBindEx *auth2.AuthBindEx, err error) {
|
||||
globals.SugarLogger.Debugf("UnionFindAuthBind curAuthType:%s, curAuthTypeID:%s, unionAuthTypeList:%v, openID:%s, unionID:%s, authDetail:%s",
|
||||
curAuthType, curAuthTypeID, unionAuthTypeList, openID, unionID, utils.Format4Output(authDetail, true))
|
||||
db := dao.GetDB()
|
||||
var authBind *model.AuthBind
|
||||
if authBind, err = dao.GetAuthBind(db, model.AuthBindTypeAuth, curAuthType, openID); err == nil { // 直接找到了
|
||||
@@ -76,9 +80,9 @@ func (a *DefAuther) UnionFindAuthBind(curAuthType, curAuthTypeID string, unionAu
|
||||
dao.UpdateEntity(db, authBind, "TypeID")
|
||||
}
|
||||
} else if dao.IsNoRowsError(err) { // 直接找不到,尝试unionID
|
||||
if unionID != "" || openID != "" { // 且有unionID
|
||||
if unionID != "" { // 且有unionID
|
||||
var authBindList []*model.AuthBind
|
||||
if authBindList, err = dao.GetUserBindAuthInfo(db, "", model.AuthBindTypeAuth, unionAuthTypeList, openID, unionID, nil); err == nil && len(authBindList) > 0 { // 通过unionID找到至少一个认证方式
|
||||
if authBindList, err = dao.GetUserBindAuthInfo(db, "", model.AuthBindTypeAuth, unionAuthTypeList, "", unionID, ""); err == nil && len(authBindList) > 0 { // 通过unionID找到至少一个认证方式
|
||||
authBind = authBindList[0]
|
||||
authBind.Type = curAuthType
|
||||
authBind.TypeID = curAuthTypeID
|
||||
@@ -98,8 +102,7 @@ func (a *DefAuther) UnionFindAuthBind(curAuthType, curAuthTypeID string, unionAu
|
||||
err = nil
|
||||
}
|
||||
}
|
||||
if err == nil && authBindEx == nil {
|
||||
//如果没有报错,且没有找到一个认证方式,创建无用户(UserID为空)的认证方式
|
||||
if err == nil && authBindEx == nil { //如果没有报错,且没有找到一个认证方式,创建无用户(UserID为空)的认证方式
|
||||
authBindEx = &auth2.AuthBindEx{
|
||||
AuthBind: model.AuthBind{
|
||||
Type: curAuthType,
|
||||
@@ -139,6 +142,7 @@ func (a *DefAuther) GenerateVerifyCode(keyID string) (verifyCode string) {
|
||||
if verifyCode == "" {
|
||||
verifyCode = fmt.Sprintf("%06d", rand.Intn(1000000))
|
||||
}
|
||||
globals.SugarLogger.Debugf("GenerateVerifyCode keyID:%s verifyCode:%s", keyID, verifyCode)
|
||||
return verifyCode
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/auth2"
|
||||
"git.rosy.net.cn/jx-callback/business/auth2/authprovider"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
)
|
||||
|
||||
@@ -20,29 +21,17 @@ func init() {
|
||||
auth2.RegisterAuther(AuthTypeQRCode, AutherObjQRCode)
|
||||
}
|
||||
|
||||
func (a *QRCodeAuther) VerifySecret(dummy, code string) (*auth2.AuthBindEx, error) {
|
||||
userQRInfo, err := api.DingDingQRCodeAPI.GetUserInfoByCode(code)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tmp_userID, err := api.DingDingAPI.GetByUnionID(userQRInfo.UnionID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
userInfo, err := api.DingDingAPI.GetUser(tmp_userID.UserID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
authBindEx, err := a.UnionFindAuthBind(AuthTypeQRCode, api.DingDingQRCodeAPI.GetAppID(), []string{AuthTypeStaff, AuthTypeQRCode}, userQRInfo.OpenID, userQRInfo.UnionID, userQRInfo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
authBindEx.UserHint = &auth2.UserBasic{
|
||||
UserID2: tmp_userID.UserID,
|
||||
Mobile: utils.Interface2String(userInfo["mobile"]),
|
||||
Email: utils.Interface2String(userInfo["email"]),
|
||||
Name: utils.Interface2String(userInfo["name"]),
|
||||
}
|
||||
func (a *QRCodeAuther) VerifySecret(dummy, code string) (authBindEx *auth2.AuthBindEx, err error) {
|
||||
globals.SugarLogger.Debugf("dingding qrcode VerifySecret code:%s", code)
|
||||
|
||||
userQRInfo, err := api.DingDingQRCodeAPI.GetUserInfoByCode(code)
|
||||
if err == nil {
|
||||
globals.SugarLogger.Debugf("dingding qrcode VerifySecret code:%s, userQRInfo:%s", code, utils.Format4Output(userQRInfo, false))
|
||||
if authBindEx, err = a.UnionFindAuthBind(AuthTypeQRCode, api.DingDingQRCodeAPI.GetAppID(), []string{AuthTypeStaff, AuthTypeQRCode}, userQRInfo.OpenID, userQRInfo.UnionID, userQRInfo); err == nil {
|
||||
authBindEx.UserHint = &auth2.UserBasic{
|
||||
Name: userQRInfo.Nickname,
|
||||
}
|
||||
}
|
||||
}
|
||||
return authBindEx, err
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"git.rosy.net.cn/jx-callback/business/auth2"
|
||||
"git.rosy.net.cn/jx-callback/business/auth2/authprovider"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
)
|
||||
|
||||
@@ -22,6 +23,8 @@ func init() {
|
||||
}
|
||||
|
||||
func (a *StaffAuther) VerifySecret(dummy, code string) (authBindEx *auth2.AuthBindEx, err error) {
|
||||
globals.SugarLogger.Debugf("dingding staff VerifySecret code:%s", code)
|
||||
|
||||
userID, err := api.DingDingAPI.GetUserID(code)
|
||||
if err == nil {
|
||||
userDetail, err2 := api.DingDingAPI.GetUserDetail(userID.UserID)
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
package douyin
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/baseapi/platformapi/tiktok"
|
||||
"git.rosy.net.cn/baseapi/platformapi/weixinapi"
|
||||
"git.rosy.net.cn/jx-callback/business/auth2"
|
||||
"git.rosy.net.cn/jx-callback/business/auth2/authprovider"
|
||||
"git.rosy.net.cn/jx-callback/business/auth2/authprovider/weixin"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
AuthTypeTiktokMini = "tiktokmini" // 抖音小程序
|
||||
)
|
||||
|
||||
type TiktokMiniAuther struct {
|
||||
authprovider.DefAuther
|
||||
}
|
||||
|
||||
var (
|
||||
AutherObjMini *TiktokMiniAuther
|
||||
)
|
||||
|
||||
func init() {
|
||||
AutherObjMini = new(TiktokMiniAuther)
|
||||
auth2.RegisterAuther(AuthTypeTiktokMini, AutherObjMini)
|
||||
}
|
||||
|
||||
func (a *TiktokMiniAuther) VerifySecret(dummy, code string) (authBindEx *auth2.AuthBindEx, err error) {
|
||||
//appID, realCode := splitCode(code)
|
||||
//sessionInfo, err := getTikTokApp(appID).GetTiktokOauth(realCode)
|
||||
sessionInfo, err := api.TiktokApi.GetTiktokOauth(code)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sessionKey := sessionInfo.Data.SessionKey
|
||||
if authBindEx, err = a.UnionFindAuthBind(AuthTypeTiktokMini, api.TiktokApi.GetAppID(), []string{AuthTypeTiktokMini}, sessionInfo.Data.OpenId, sessionInfo.Data.Unionid, sessionInfo); err == nil {
|
||||
authBindEx.UserData = sessionKey
|
||||
}
|
||||
return authBindEx, err
|
||||
}
|
||||
|
||||
// 特殊接口
|
||||
func (a *TiktokMiniAuther) DecryptData(authInfo *auth2.AuthInfo, jsCode, encryptedData, iv string) (decryptedDataBase64 string, err error) {
|
||||
var sessionKey string
|
||||
appID, jsCode := weixin.SplitJsCode(jsCode)
|
||||
if jsCode != "" {
|
||||
sessionInfo, err := getWxApp(appID).SNSCode2Session(jsCode)
|
||||
if err == nil {
|
||||
// if authBindEx, err := a.UnionFindAuthBind(AuthTypeMini, getWxApp(appID).GetAppID(), []string{AuthTypeMini}, sessionInfo.OpenID, "", nil); err == nil {
|
||||
// if authBindEx.UserID != authInfo.GetID() {
|
||||
// return "", fmt.Errorf("jsCode与token不匹配")
|
||||
// }
|
||||
// } else {
|
||||
// return "", err
|
||||
// }
|
||||
sessionKey = sessionInfo.SessionKey
|
||||
} else {
|
||||
return "", err
|
||||
}
|
||||
} else {
|
||||
if authInfo.AuthBindInfo.Type != AuthTypeTiktokMini {
|
||||
// return "", ErrAuthTypeShouldBeMini
|
||||
}
|
||||
sessionKey = authInfo.AuthBindInfo.UserData.(string)
|
||||
}
|
||||
decryptedData, err := weixinapi.SNSDecodeMiniProgramData(encryptedData, sessionKey, iv)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(decryptedData), nil
|
||||
}
|
||||
|
||||
func (a *TiktokMiniAuther) GetUserType() (userType int8) {
|
||||
return model.UserTypeStoreBoss
|
||||
}
|
||||
|
||||
func getWxApp(appID string) (miniApi *weixinapi.API) {
|
||||
miniApi = api.WeixinMiniAPI
|
||||
if len(appID) > 0 && appID == api.WeixinMiniAppID2 {
|
||||
miniApi = api.WeixinMiniAPI2
|
||||
}
|
||||
if len(appID) > 0 && appID == api.WeixinMiniAppIDsc {
|
||||
miniApi = api.WeixinMiniAPIsc
|
||||
}
|
||||
return miniApi
|
||||
}
|
||||
|
||||
func getTikTokApp(appID string) (TikTokMini *tiktok.API) {
|
||||
TikTokMini = api.TiktokApi
|
||||
if len(appID) > 0 && appID == api.TiktokJXDJApiID {
|
||||
TikTokMini = api.TiktokJXDJApi
|
||||
}
|
||||
return TikTokMini
|
||||
}
|
||||
func splitCode(code string) (appID, realCode string) {
|
||||
str := strings.Split(code, "&")
|
||||
if len(str) == 2 {
|
||||
appID = str[1]
|
||||
realCode = str[0]
|
||||
} else {
|
||||
globals.SugarLogger.Warnf("splitCode abnormal code:%s", code)
|
||||
}
|
||||
return appID, realCode
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
package kuaishou
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/jx-callback/business/auth2"
|
||||
"git.rosy.net.cn/jx-callback/business/auth2/authprovider"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
)
|
||||
|
||||
const (
|
||||
AuthTypeKuaiShouMini = "kuaishoumini" // 快手小程序
|
||||
)
|
||||
|
||||
type KuaiShouMiniAuther struct {
|
||||
authprovider.DefAuther
|
||||
}
|
||||
|
||||
var (
|
||||
AutherObjMini *KuaiShouMiniAuther
|
||||
)
|
||||
|
||||
func init() {
|
||||
AutherObjMini = new(KuaiShouMiniAuther)
|
||||
auth2.RegisterAuther(AuthTypeKuaiShouMini, AutherObjMini)
|
||||
}
|
||||
|
||||
func (a *KuaiShouMiniAuther) VerifySecret(dummy, code string) (authBindEx *auth2.AuthBindEx, err error) {
|
||||
//appID, realCode := splitCode(code)
|
||||
//sessionInfo, err := getTikTokApp(appID).GetTiktokOauth(realCode)
|
||||
sessionInfo, openId, err := api.KuaiShouApi.AuthLoginKuaiShou(code)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if authBindEx, err = a.UnionFindAuthBind(AuthTypeKuaiShouMini, api.KuaiShouApi.GetAppID(), []string{AuthTypeKuaiShouMini}, openId, "", sessionInfo); err == nil {
|
||||
authBindEx.UserData = sessionInfo
|
||||
}
|
||||
return authBindEx, err
|
||||
}
|
||||
|
||||
//func (a *KuaiShouMiniAuther) DecryptData(authInfo *auth2.AuthInfo, jsCode, encryptedData, iv string) (decryptedDataBase64 string, err error) {
|
||||
// var sessionKey string
|
||||
// appID, jsCode := weixin.SplitJsCode(jsCode)
|
||||
// if jsCode != "" {
|
||||
// sessionInfo, err := getWxApp(appID).SNSCode2Session(jsCode)
|
||||
// if err == nil {
|
||||
// // if authBindEx, err := a.UnionFindAuthBind(AuthTypeMini, getWxApp(appID).GetAppID(), []string{AuthTypeMini}, sessionInfo.OpenID, "", nil); err == nil {
|
||||
// // if authBindEx.UserID != authInfo.GetID() {
|
||||
// // return "", fmt.Errorf("jsCode与token不匹配")
|
||||
// // }
|
||||
// // } else {
|
||||
// // return "", err
|
||||
// // }
|
||||
// sessionKey = sessionInfo.SessionKey
|
||||
// } else {
|
||||
// return "", err
|
||||
// }
|
||||
// } else {
|
||||
// if authInfo.AuthBindInfo.Type != AuthTypeKuaiShouMini {
|
||||
// // return "", ErrAuthTypeShouldBeMini
|
||||
// }
|
||||
// sessionKey = authInfo.AuthBindInfo.UserData.(string)
|
||||
// }
|
||||
// decryptedData, err := weixinapi.SNSDecodeMiniProgramData(encryptedData, sessionKey, iv)
|
||||
// if err != nil {
|
||||
// return "", err
|
||||
// }
|
||||
// return string(decryptedData), nil
|
||||
//}
|
||||
//
|
||||
//func (a *KuaiShouMiniAuther) GetUserType() (userType int8) {
|
||||
// return model.UserTypeStoreBoss
|
||||
//}
|
||||
//
|
||||
//func getWxApp(appID string) (miniApi *weixinapi.API) {
|
||||
// miniApi = api.WeixinMiniAPI
|
||||
// if len(appID) > 0 && appID == api.WeixinMiniAppID2 {
|
||||
// miniApi = api.WeixinMiniAPI2
|
||||
// }
|
||||
// if len(appID) > 0 && appID == api.WeixinMiniAppIDsc {
|
||||
// miniApi = api.WeixinMiniAPIsc
|
||||
// }
|
||||
// return miniApi
|
||||
//}
|
||||
//
|
||||
//func getTikTokApp(appID string) (TikTokMini *tiktok.API) {
|
||||
// TikTokMini = api.TiktokApi
|
||||
// if len(appID) > 0 && appID == api.TiktokJXDJApiID {
|
||||
// TikTokMini = api.TiktokJXDJApi
|
||||
// }
|
||||
// return TikTokMini
|
||||
//}
|
||||
//func splitCode(code string) (appID, realCode string) {
|
||||
// str := strings.Split(code, "&")
|
||||
// if len(str) == 2 {
|
||||
// appID = str[1]
|
||||
// realCode = str[0]
|
||||
// } else {
|
||||
// globals.SugarLogger.Warnf("splitCode abnormal code:%s", code)
|
||||
// }
|
||||
// return appID, realCode
|
||||
//}
|
||||
@@ -3,6 +3,7 @@ package mobile
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/auth2"
|
||||
@@ -44,7 +45,9 @@ func init() {
|
||||
|
||||
// 特殊接口
|
||||
func (a *Auther) SendVerifyCode(mobileNumber string) (verifyCode string, err error) {
|
||||
verifyCode = a.GenerateVerifyCode(mobileNumber)
|
||||
verifyCode = fmt.Sprintf("%06d", rand.Intn(1000000))
|
||||
globals.SugarLogger.Debugf("SendVerifyCode code: %v", verifyCode)
|
||||
// a.GenerateVerifyCode(mobileNumber)
|
||||
smsClient := aliyunsmsclient.New("http://dysmsapi.aliyuncs.com/")
|
||||
response, err := smsClient.Execute(globals.AliKey, globals.AliSecret, mobileNumber, globals.SMSSignName, globals.SMSMobileVerifyTemplate, string(utils.MustMarshal(map[string]interface{}{
|
||||
"code": verifyCode,
|
||||
@@ -68,10 +71,13 @@ func (a *Auther) SendVerifyCode(mobileNumber string) (verifyCode string, err err
|
||||
}
|
||||
|
||||
func (a *Auther) VerifySecret(mobileNumber, code string) (authBindEx *auth2.AuthBindEx, err error) {
|
||||
globals.SugarLogger.Debugf("VerifySecret mobileNumber:%s, code:%s", mobileNumber, code)
|
||||
def := &authprovider.DefAuther{}
|
||||
err = ErrVerifyCodeIsWrong
|
||||
if (code == auth2.InternalAuthSecret ||
|
||||
auth2.TestMobileMap[mobileNumber] == 1 && code == TestVerifyCode) ||
|
||||
a.VerifyCode(mobileNumber, code) {
|
||||
savedVerifyCode := def.LoadVerifyCode(mobileNumber)
|
||||
if code == auth2.InternalAuthSecret ||
|
||||
auth2.TestMobileMap[mobileNumber] == 1 && code == TestVerifyCode || (code != "" && savedVerifyCode != "" && code == savedVerifyCode) {
|
||||
// || a.VerifyCode(mobileNumber, code)
|
||||
err = nil
|
||||
}
|
||||
return nil, err
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"git.rosy.net.cn/jx-callback/business/auth2/authprovider"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -34,6 +35,7 @@ func init() {
|
||||
}
|
||||
|
||||
func (a *Auther) VerifySecret(userID, passMD5 string) (authBindEx *auth2.AuthBindEx, err error) {
|
||||
globals.SugarLogger.Debugf("localpass VerifySecret userID:%s", userID)
|
||||
var authBind *model.AuthBind
|
||||
if authBind, err = dao.GetAuthBind(dao.GetDB(), model.AuthBindTypeAuth, AuthType, userID); err == nil {
|
||||
if err = a.checkPassword(authBind, passMD5); err == nil {
|
||||
|
||||
@@ -7,15 +7,15 @@ import (
|
||||
"git.rosy.net.cn/jx-callback/business/auth2"
|
||||
"git.rosy.net.cn/jx-callback/business/auth2/authprovider"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
)
|
||||
|
||||
const (
|
||||
AuthTypeWeixin = "wxqrcode" // 微信扫码
|
||||
AuthTypeMP = "weixinsns" // 公众号
|
||||
AuthTypeWXNative = "wxnative" // 微信APP
|
||||
AuthTypeWxApp = "weixinapp" //app微信登录(商家版)
|
||||
AuthTypeWxAppCaishi = "weixinappcs" //app微信登录(用户版)
|
||||
AuthTypeWeixin = "wxqrcode" // 微信扫码
|
||||
AuthTypeMP = "weixinsns" // 公众号
|
||||
AuthTypeWXNative = "wxnative" // 微信APP
|
||||
AuthTypeWxApp = "weixinapp" //app微信登录
|
||||
)
|
||||
|
||||
type Auther struct {
|
||||
@@ -24,11 +24,10 @@ type Auther struct {
|
||||
}
|
||||
|
||||
var (
|
||||
AutherObjWX *Auther
|
||||
AutherObjMP *Auther
|
||||
AutherObjNative *Auther
|
||||
AutherObjApp *Auther
|
||||
AutherObjCaiShiApp *Auther
|
||||
AutherObjWX *Auther
|
||||
AutherObjMP *Auther
|
||||
AutherObjNative *Auther
|
||||
AutherObjApp *Auther
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -55,22 +54,15 @@ func init() {
|
||||
authType: AuthTypeWxApp,
|
||||
}
|
||||
auth2.RegisterAuther(AuthTypeWxApp, AutherObjApp)
|
||||
|
||||
AutherObjCaiShiApp = &Auther{
|
||||
authType: AuthTypeWxAppCaishi,
|
||||
}
|
||||
auth2.RegisterAuther(AuthTypeWxAppCaishi, AutherObjCaiShiApp)
|
||||
}
|
||||
|
||||
func (a *Auther) VerifySecret(id, secret string) (authBindEx *auth2.AuthBindEx, err error) {
|
||||
globals.SugarLogger.Debugf("weixin VerifySecret id:%s secret:%s", secret, secret)
|
||||
var openID, accessToken string
|
||||
_, jsCode := SplitJsCode(secret)
|
||||
if a.authType != AuthTypeWXNative {
|
||||
state := id
|
||||
code := jsCode
|
||||
code := secret
|
||||
if state == "" {
|
||||
//temp := a.getAPI()
|
||||
//fmt.Printf("secret=%s,appid=%s", temp.GetSecret(), temp.GetAppID())
|
||||
token, err2 := a.getAPI().SNSRetrieveToken(code)
|
||||
if err = err2; err == nil {
|
||||
openID = token.OpenID
|
||||
@@ -86,7 +78,7 @@ func (a *Auther) VerifySecret(id, secret string) (authBindEx *auth2.AuthBindEx,
|
||||
if err == nil {
|
||||
wxUserinfo, err2 := a.getAPI().SNSGetUserInfo(accessToken, openID)
|
||||
if err = err2; err == nil {
|
||||
if authBindEx, err = a.UnionFindAuthBind(a.authType, a.getAPI().GetAppID(), []string{AuthTypeWeixin, AuthTypeMP, AuthTypeMini, AuthTypeWXNative, AuthTypeWxApp, AuthTypeWxAppCaishi}, wxUserinfo.OpenID, wxUserinfo.UnionID, wxUserinfo); err == nil {
|
||||
if authBindEx, err = a.UnionFindAuthBind(a.authType, a.getAPI().GetAppID(), []string{AuthTypeWeixin, AuthTypeMP, AuthTypeMini, AuthTypeWXNative, AuthTypeWxApp}, wxUserinfo.OpenID, wxUserinfo.UnionID, wxUserinfo); err == nil {
|
||||
authBindEx.UserHint = &auth2.UserBasic{
|
||||
Name: wxUserinfo.NickName,
|
||||
Avatar: wxUserinfo.HeadImgURL,
|
||||
@@ -104,23 +96,9 @@ func (a *Auther) getAPI() *weixinapi.API {
|
||||
if a.authType == AuthTypeWxApp {
|
||||
return api.WeixinApp
|
||||
}
|
||||
if a.authType == AuthTypeWxAppCaishi {
|
||||
return api.WeixinApp2
|
||||
}
|
||||
return api.WeixinAPI
|
||||
}
|
||||
|
||||
func (a *Auther) GetUserType() (userType int8) {
|
||||
return model.UserTypeStoreBoss
|
||||
}
|
||||
|
||||
func GetAPI(appID string) *weixinapi.API {
|
||||
miniApi := api.WeixinMiniAPI
|
||||
if len(appID) > 0 && appID == api.WeixinMiniAppID2 {
|
||||
miniApi = api.WeixinMiniAPI2
|
||||
}
|
||||
if len(appID) > 0 && appID == api.WeixinMiniAppIDsc {
|
||||
miniApi = api.WeixinMiniAPIsc
|
||||
}
|
||||
return miniApi
|
||||
}
|
||||
|
||||
@@ -34,6 +34,8 @@ func init() {
|
||||
}
|
||||
|
||||
func (a *MiniAuther) VerifySecret(dummy, jsCode string) (authBindEx *auth2.AuthBindEx, err error) {
|
||||
globals.SugarLogger.Debugf("weixin mini VerifySecret jsCode:%s", jsCode)
|
||||
|
||||
appID, jsCode := SplitJsCode(jsCode)
|
||||
sessionInfo, err := getWxApp(appID).SNSCode2Session(jsCode)
|
||||
if err == nil {
|
||||
@@ -48,15 +50,16 @@ func (a *MiniAuther) VerifySecret(dummy, jsCode string) (authBindEx *auth2.AuthB
|
||||
|
||||
// 特殊接口
|
||||
func (a *MiniAuther) DecryptData(authInfo *auth2.AuthInfo, jsCode, encryptedData, iv string) (decryptedDataBase64 string, err error) {
|
||||
globals.SugarLogger.Debugf("weixin mini DecryptData jsCode:%s, encryptedData:%s, iv:%s", jsCode, encryptedData, iv)
|
||||
var sessionKey string
|
||||
appID, jsCode := SplitJsCode(jsCode)
|
||||
if jsCode != "" {
|
||||
sessionInfo, err := getWxApp(appID).SNSCode2Session(jsCode)
|
||||
if err == nil {
|
||||
// if authBindEx, err := a.UnionFindAuthBind(AuthTypeMini, getWxApp(appID).GetAppID(), []string{AuthTypeMini}, sessionInfo.OpenID, "", nil); err == nil {
|
||||
// if authBindEx.UserID != authInfo.GetID() {
|
||||
// return "", fmt.Errorf("jsCode与token不匹配")
|
||||
// }
|
||||
// if authBindEx.UserID != authInfo.GetID() {
|
||||
// return "", fmt.Errorf("jsCode与token不匹配")
|
||||
// }
|
||||
// } else {
|
||||
// return "", err
|
||||
// }
|
||||
@@ -66,7 +69,7 @@ func (a *MiniAuther) DecryptData(authInfo *auth2.AuthInfo, jsCode, encryptedData
|
||||
}
|
||||
} else {
|
||||
if authInfo.AuthBindInfo.Type != AuthTypeMini {
|
||||
// return "", ErrAuthTypeShouldBeMini
|
||||
return "", ErrAuthTypeShouldBeMini
|
||||
}
|
||||
sessionKey = authInfo.AuthBindInfo.UserData.(string)
|
||||
}
|
||||
@@ -85,15 +88,6 @@ func (a *MiniAuther) GetUserType() (userType int8) {
|
||||
|
||||
func getWxApp(appID string) (miniApi *weixinapi.API) {
|
||||
miniApi = api.WeixinMiniAPI
|
||||
if len(appID) > 0 && appID == api.WeixinMiniAppID2 {
|
||||
miniApi = api.WeixinMiniAPI2
|
||||
}
|
||||
if len(appID) > 0 && appID == api.WeixinMiniAppIDsc {
|
||||
miniApi = api.WeixinMiniAPIsc
|
||||
}
|
||||
//if len(appID) > 0 && appID == api.WeixinMiniPrintAppId {
|
||||
// miniApi = api.WeixinMiniAPIPrint
|
||||
//}
|
||||
return miniApi
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package casbinauth
|
||||
|
||||
import (
|
||||
jxmodel "git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"github.com/astaxie/beego/client/orm"
|
||||
"github.com/casbin/casbin/model"
|
||||
"github.com/casbin/casbin/persist"
|
||||
@@ -92,6 +93,7 @@ func (a *Adapter) clearAll(o orm.Ormer) (err error) {
|
||||
|
||||
// SavePolicy saves policy to database.
|
||||
func (a *Adapter) SavePolicy(model model.Model) error {
|
||||
globals.SugarLogger.Debugf("SavePolicy")
|
||||
o := orm.NewOrm()
|
||||
|
||||
a.clearAll(o)
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,266 +0,0 @@
|
||||
package bidding
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"git.rosy.net.cn/baseapi/platformapi/ali_logistics_query"
|
||||
"git.rosy.net.cn/baseapi/platformapi/dingdingapi"
|
||||
"git.rosy.net.cn/baseapi/platformapi/tonglianpayapi"
|
||||
"git.rosy.net.cn/baseapi/platformapi/weixinapi"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/ddmsg"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
"time"
|
||||
)
|
||||
|
||||
func LoadingLogistics(paramLogistic []*model.UpdateMaterialLogistic) []error {
|
||||
var param []*model.UpdateMaterialLogistic
|
||||
if len(paramLogistic) == 0 || paramLogistic == nil {
|
||||
param = GetLogisticOrder()
|
||||
} else {
|
||||
param = paramLogistic
|
||||
}
|
||||
|
||||
var db = dao.GetDB()
|
||||
var errList = make([]error, 0, 0)
|
||||
|
||||
for _, v := range param {
|
||||
// 更新订单状态
|
||||
goodsOrder, err := partner.CurOrderManager.LoadOrder(v.OrderId, model.VendorIDJX)
|
||||
if err != nil {
|
||||
errList = append(errList, err)
|
||||
continue
|
||||
}
|
||||
if time.Since(goodsOrder.CreatedAt) >= 3*24*time.Hour {
|
||||
goodsOrder.Status = model.OrderStatusFinished
|
||||
goodsOrder.VendorStatus = utils.Int2Str(model.WaybillStatusDelivered)
|
||||
goodsOrder.StatusTime = time.Now()
|
||||
goodsOrder.OrderFinishedAt = time.Now()
|
||||
if _, err := dao.UpdateEntity(db, goodsOrder, "Status", "VendorStatus", "StatusTime", "OrderFinishedAt"); err != nil {
|
||||
errList = append(errList, err)
|
||||
continue
|
||||
}
|
||||
|
||||
payList, _ := dao.GetOrderPayList(db, goodsOrder.VendorOrderID, goodsOrder.VendorID)
|
||||
for _, pl := range payList {
|
||||
if pl.OriginalData != "" {
|
||||
originalData := &tonglianpayapi.CallBackResult{}
|
||||
json.Unmarshal([]byte(pl.OriginalData), originalData)
|
||||
|
||||
if err = api.WeixinMiniAPI2.SNSDeliveryGoodsOrder(&weixinapi.DeliveryOrder{
|
||||
TransactionId: originalData.ChnlTrxID,
|
||||
ReceivedTime: time.Now().Unix(),
|
||||
}); err != nil {
|
||||
ddmsg.SendUserMessage(dingdingapi.MsgTyeText, "2452A93EEB9111EC9B06525400E86DC0", "微信物料送达推送", fmt.Sprintf("物料商城下单,送达错误:%s,请注意查看,err:%s", goodsOrder.VendorOrderID, err.Error()))
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
return nil
|
||||
|
||||
// GetLogisticsInfo 免费物流查询资源不可用,暂时不管
|
||||
//for _, logistics := range param {
|
||||
// // 获取当前订单物流状态
|
||||
// statusList, err := orderman.FixedOrderManager.GetLogisticsOrderStatusList(logistics.OrderId, logistics.LogisticId, 9)
|
||||
// if err != nil {
|
||||
// errList = append(errList, err)
|
||||
// continue
|
||||
// }
|
||||
//
|
||||
// // 获取当前订单三方配送物流
|
||||
// logisticsList, err := api.LogisticsApi.GetLogisticsInfo(logistics.LogisticId)
|
||||
// if err != nil {
|
||||
// errList = append(errList, err)
|
||||
// continue
|
||||
// }
|
||||
//
|
||||
// // 新订单,本地暂无物流信息,全部更新远端物流信息到本地
|
||||
// if len(logisticsList.Info[0].LogisticsTraceDetailList) == model.NO {
|
||||
// errList = append(errList, errors.New("运单号[%s]:已经过期/新订单暂无物流推送信息"))
|
||||
// continue
|
||||
// }
|
||||
// var orderStatus = make([]*model.OrderStatus, 0, 0)
|
||||
// goodsOrderStatus := 0
|
||||
// for _, v := range logisticsList.Info[0].LogisticsTraceDetailList {
|
||||
// orderStatusToLocal := &model.OrderStatus{
|
||||
// VendorOrderID: logisticsList.Info[0].MailNo,
|
||||
// VendorID: model.VendorIDTotalWl,
|
||||
// OrderType: model.OrderTypeWaybill,
|
||||
// RefVendorOrderID: logistics.OrderId,
|
||||
// RefVendorID: model.VendorIDJX,
|
||||
// VendorStatus: v.SubLogisticsStatus,
|
||||
// StatusTime: time.Time{},
|
||||
// DuplicatedCount: 0,
|
||||
// Remark: v.Desc,
|
||||
// ModelTimeInfo: model.ModelTimeInfo{CreatedAt: time.Now(), UpdatedAt: time.Now()},
|
||||
// }
|
||||
//
|
||||
// switch v.SubLogisticsStatus {
|
||||
// case ali_logistics_query.LogisticsStatusRECEVIE:
|
||||
// orderStatusToLocal.Status = model.WaybillStatusNew // 新订单
|
||||
// goodsOrderStatus = model.OrderStatusNew // 新订单
|
||||
// case ali_logistics_query.LogisticsStatusWAIT_ACCEPT:
|
||||
// orderStatusToLocal.Status = model.WaybillStatusAccepted // 分配骑手
|
||||
// goodsOrderStatus = model.OrderStatusAccepted // 拣货完成等待骑手
|
||||
// case ali_logistics_query.LogisticsStatusACCEPT:
|
||||
// orderStatusToLocal.Status = model.WaybillStatusCourierArrived // 兼容骑手取货状态
|
||||
// goodsOrderStatus = model.OrderStatusFinishedPickup
|
||||
// case ali_logistics_query.LogisticsStatusTRANSPORT, ali_logistics_query.LogisticsStatusSEND_ON, ali_logistics_query.LogisticsStatusARRIVE_CITY, ali_logistics_query.LogisticsStatusDELIVERING:
|
||||
// orderStatusToLocal.Status = model.WaybillStatusDelivering // 配送中
|
||||
// goodsOrderStatus = model.OrderStatusDelivering
|
||||
// case ali_logistics_query.LogisticsStatusAGENT_SIGN, ali_logistics_query.LogisticsStatusSIGN, ali_logistics_query.LogisticsStatusSTA_SIGN:
|
||||
// orderStatusToLocal.Status = model.WaybillStatusDelivered // 配送结束
|
||||
// goodsOrderStatus = model.OrderStatusFinished
|
||||
// default: // 剩余状态全部为异常状态,除非新加状态
|
||||
// orderStatusToLocal.Status = model.WaybillStatusUnknown // 异常配送
|
||||
// goodsOrderStatus = model.OrderStatusDeliverFailed // 投递失败
|
||||
// }
|
||||
// orderStatusToLocal.StatusTime = utils.Timestamp2Time(v.Time)
|
||||
// orderStatus = append(orderStatus, orderStatusToLocal)
|
||||
// }
|
||||
//
|
||||
// if len(statusList) == 0 || statusList == nil { // 本地订单状态为空不存在
|
||||
// for _, v := range orderStatus {
|
||||
// if err := dao.CreateEntity(db, v); err != nil {
|
||||
// errList = append(errList, err)
|
||||
// continue
|
||||
// }
|
||||
// }
|
||||
// } else {
|
||||
// for _, v := range orderStatus {
|
||||
// if statusList[len(statusList)-1].StatusTime.Unix() > v.StatusTime.Unix() && checkOrderStatus(statusList[len(statusList)-1].VendorStatus) {
|
||||
// continue
|
||||
// }
|
||||
// if err := dao.CreateEntity(db, v); err != nil {
|
||||
// errList = append(errList, err)
|
||||
// continue
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // 获取当前订单运单状态
|
||||
// wayBill, err := dao.GetWaybills(db, logistics.OrderId, nil)
|
||||
// if err != nil {
|
||||
// errList = append(errList, err)
|
||||
// continue
|
||||
// }
|
||||
// status := orderStatus[len(orderStatus)-1].Status
|
||||
// vendorStatus := orderStatus[len(orderStatus)-1].VendorStatus
|
||||
// statusTime := orderStatus[len(orderStatus)-1].StatusTime
|
||||
// if len(wayBill) == 0 || wayBill == nil {
|
||||
// wayBillObj := &model.Waybill{
|
||||
// VendorWaybillID: logistics.LogisticId,
|
||||
// WaybillVendorID: model.VendorIDTotalWl,
|
||||
// VendorOrderID: logistics.OrderId,
|
||||
// OrderVendorID: model.VendorIDJX,
|
||||
// CourierName: logisticsList.Info[0].Courier,
|
||||
// CourierMobile: logisticsList.Info[0].CourierPhone,
|
||||
// Status: status,
|
||||
// VendorStatus: vendorStatus,
|
||||
// ActualFee: logistics.LogisticFee,
|
||||
// DesiredFee: logistics.LogisticFee,
|
||||
// DeliveryFlag: model.OrderDeliveryFlagMaskScheduleDisabled,
|
||||
// WaybillCreatedAt: time.Now(),
|
||||
// StatusTime: statusTime,
|
||||
// ModelTimeInfo: model.ModelTimeInfo{CreatedAt: time.Now(), UpdatedAt: time.Now()},
|
||||
// WaybillFinishedAt: time.Now(),
|
||||
// }
|
||||
// if err := dao.CreateEntity(db, wayBillObj); err != nil {
|
||||
// errList = append(errList, err)
|
||||
// continue
|
||||
// }
|
||||
// } else {
|
||||
// wayBill[0].UpdatedAt = time.Now()
|
||||
// wayBill[0].Status = status
|
||||
// wayBill[0].VendorStatus = vendorStatus
|
||||
// wayBill[0].StatusTime = statusTime
|
||||
// wayBill[0].WaybillFinishedAt = time.Now()
|
||||
// if _, err := dao.UpdateEntity(db, wayBill[0], "Status", "UpdatedAt", "VendorStatus", "StatusTime"); err != nil {
|
||||
// errList = append(errList, err)
|
||||
// continue
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // 更新订单状态
|
||||
// goodsOrder, err := partner.CurOrderManager.LoadOrder(logistics.OrderId, model.VendorIDJX)
|
||||
// if err != nil {
|
||||
// errList = append(errList, err)
|
||||
// continue
|
||||
// }
|
||||
// goodsOrder.Status = goodsOrderStatus
|
||||
// goodsOrder.VendorStatus = vendorStatus
|
||||
// goodsOrder.StatusTime = statusTime
|
||||
// if orderStatus[len(orderStatus)-1].Status >= model.OrderStatusEndBegin {
|
||||
// goodsOrder.OrderFinishedAt = time.Now()
|
||||
// }
|
||||
// if _, err := dao.UpdateEntity(db, goodsOrder, "Status", "VendorStatus", "StatusTime", "OrderFinishedAt"); err != nil {
|
||||
// errList = append(errList, err)
|
||||
// continue
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//return errList
|
||||
}
|
||||
|
||||
func checkOrderStatus(orderStatus string) bool {
|
||||
switch orderStatus {
|
||||
case ali_logistics_query.LogisticsStatusRECEVIE:
|
||||
return true
|
||||
case ali_logistics_query.LogisticsStatusWAIT_ACCEPT:
|
||||
return true
|
||||
case ali_logistics_query.LogisticsStatusACCEPT:
|
||||
return true
|
||||
case ali_logistics_query.LogisticsStatusTRANSPORT, ali_logistics_query.LogisticsStatusSEND_ON, ali_logistics_query.LogisticsStatusARRIVE_CITY, ali_logistics_query.LogisticsStatusDELIVERING:
|
||||
return true
|
||||
case ali_logistics_query.LogisticsStatusAGENT_SIGN, ali_logistics_query.LogisticsStatusSIGN, ali_logistics_query.LogisticsStatusSTA_SIGN:
|
||||
return true
|
||||
case ali_logistics_query.LogisticsStatusSTA_INBOUND, ali_logistics_query.LogisticsStatusRETURN_SIGN, ali_logistics_query.LogisticsStatusFAILED, ali_logistics_query.LogisticsStatusREFUSE_SIGN, ali_logistics_query.LogisticsStatusDELIVER_ABNORMAL:
|
||||
return true
|
||||
case ali_logistics_query.LogisticsStatusRETENTION, ali_logistics_query.LogisticsStatusISSUE, ali_logistics_query.LogisticsStatusRETURN, ali_logistics_query.LogisticsStatusDAMAGE, ali_logistics_query.LogisticsStatusCANCEL_ORDER:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// GetLogisticOrder 查询未完成的物料订单,更新物流信息
|
||||
func GetLogisticOrder() []*model.UpdateMaterialLogistic {
|
||||
var (
|
||||
timeNow = time.Now()
|
||||
startTime = timeNow.AddDate(0, -1, 0)
|
||||
endTime = timeNow
|
||||
goodsList = make([]*model.GoodsOrder, 0, 0)
|
||||
)
|
||||
|
||||
sql := ` SELECT * FROM goods_order g WHERE g.order_created_at >= ? AND g.order_created_at < ? AND g.store_id = ? AND order_type = ? AND g.status < ? ` // 一个月内状态未完成的订单
|
||||
sqlParam := []interface{}{
|
||||
startTime, endTime, "666666", 1, model.OrderStatusEndBegin,
|
||||
}
|
||||
if err := dao.GetRows(dao.GetDB(), &goodsList, sql, sqlParam...); err != nil {
|
||||
globals.SugarLogger.Debugf("loading jx material order err :%s", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(goodsList) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
logisticsList := make([]*model.UpdateMaterialLogistic, 0, len(goodsList))
|
||||
for _, v := range goodsList {
|
||||
logistics := &model.UpdateMaterialLogistic{
|
||||
OrderId: v.VendorOrderID,
|
||||
LogisticId: v.VendorWaybillID,
|
||||
LogisticFee: v.BaseFreightMoney,
|
||||
}
|
||||
logisticsList = append(logisticsList, logistics)
|
||||
}
|
||||
return logisticsList
|
||||
}
|
||||
@@ -1,230 +0,0 @@
|
||||
package bidding
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"git.rosy.net.cn/baseapi/platformapi/mtwmapi"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// GetStatisticsList 京西数据查询
|
||||
func GetStatisticsList(start, end time.Time, storeIds []int, offset, pageSize int) (*model.PagedInfo, error) {
|
||||
return dao.GetStatistics(dao.GetDB(), start, end, storeIds, offset, pageSize)
|
||||
}
|
||||
|
||||
// GetMTInfo 更新美团门店信息
|
||||
func GetMTInfo() []error {
|
||||
var db = dao.GetDB()
|
||||
var errList = make([]error, 0, 0)
|
||||
// 获取当前一月有效订单的门店信息
|
||||
effectiveStores, err := dao.StoreInformationStatistics(db)
|
||||
if err != nil {
|
||||
return append(errList, err)
|
||||
}
|
||||
|
||||
var mtApi *mtwmapi.API
|
||||
for _, v := range effectiveStores {
|
||||
if v.VendorOrgCode == globals.Mtwm2Code {
|
||||
mtApi = api.Mtwm2API
|
||||
mtApi.SetToken(v.MtwmToken)
|
||||
} else {
|
||||
mtApi = api.MtwmAPI
|
||||
}
|
||||
|
||||
statistics := &model.ActivityStation{
|
||||
StoreID: v.JxStoreID,
|
||||
VendorID: model.VendorIDMTWM,
|
||||
VendorStoreID: v.VendorStoreID,
|
||||
BrandID: v.VendorOrgCode,
|
||||
//Activity1: 0,
|
||||
//Activity2: 0,
|
||||
//Activity: 0,
|
||||
//StoreSkuNum: 0,
|
||||
//StoreRating: 0,
|
||||
//DeliveryFee: "",
|
||||
//DeliveryFee2: "",
|
||||
PromotionFee: "暂无法获取",
|
||||
//BusinessHours: "",
|
||||
}
|
||||
dao.WrapAddIDCULEntity(statistics, "system")
|
||||
down, up := getActivityCount(mtApi, v.VendorStoreID)
|
||||
statistics.Activity1 = int64(down)
|
||||
statistics.Activity2 = int64(up)
|
||||
statistics.Activity = int64(down + up)
|
||||
score, err := mtApi.CommentScore(v.VendorStoreID)
|
||||
if err != nil {
|
||||
errList = append(errList, fmt.Errorf("%s获取评分错误:%s", v.VendorStoreID, err.Error()))
|
||||
}
|
||||
if score != nil {
|
||||
statistics.StoreRating = score.AvgPoiScore
|
||||
} else {
|
||||
statistics.StoreRating = 0
|
||||
}
|
||||
|
||||
// 获取门店营业时长
|
||||
detail, _ := mtApi.PoiMGet([]string{v.VendorStoreID})
|
||||
if detail != nil {
|
||||
statistics.BusinessHours, err = getStoreShippingTime(detail[0].ShippingTime)
|
||||
if err != nil {
|
||||
errList = append(errList, fmt.Errorf("%s获取营业时长错误:%s", v.VendorStoreID, err.Error()))
|
||||
statistics.BusinessHours = err.Error()
|
||||
}
|
||||
statistics.DeliveryFee2 = utils.Float64ToStr(detail[0].ShippingFee)
|
||||
}
|
||||
// 获取门店起送价
|
||||
result, err := mtApi.ShippingList(v.VendorStoreID)
|
||||
if err != nil {
|
||||
errList = append(errList, fmt.Errorf("%s获取起送价错误:%s", v.VendorStoreID, err.Error()))
|
||||
statistics.DeliveryFee = err.Error()
|
||||
}
|
||||
shippingList := make([]ShippingList, 0, 0)
|
||||
for _, v2 := range result {
|
||||
shippingList = append(shippingList, ShippingList{
|
||||
TimeRange: utils.Interface2String(v2["time_range"]),
|
||||
MinPrice: utils.MustInterface2Float64(v2["min_price"]),
|
||||
ShippingFee: utils.MustInterface2Float64(v2["shipping_fee"]),
|
||||
})
|
||||
}
|
||||
statistics.DeliveryFee = utils.Format4Output(shippingList, false)
|
||||
if len(result) == 0 {
|
||||
statistics.DeliveryFee = ""
|
||||
}
|
||||
|
||||
dao.CreateEntity(db, statistics)
|
||||
}
|
||||
|
||||
return errList
|
||||
}
|
||||
|
||||
// 获取门店折扣活动商品数量
|
||||
func getActivityCount(api *mtwmapi.API, vendorStoreId string) (int, int) {
|
||||
threefoldDown := 0 // 0-3 折活动数量
|
||||
threefoldUp := 0 // 3.01-9 折活动
|
||||
// 获取美团活动
|
||||
directList, _ := api.RetailDiscountList(vendorStoreId, mtwmapi.RetailActTypeDirectDown) // 折扣活动
|
||||
for _, v := range directList {
|
||||
if v.ActPrice/v.OriginalPrice*10 >= 3.01 {
|
||||
threefoldUp++
|
||||
} else {
|
||||
threefoldDown++
|
||||
}
|
||||
}
|
||||
secKillList, _ := api.RetailDiscountList(vendorStoreId, mtwmapi.RetailActTypeSecKill) // 爆品活动
|
||||
if secKillList != nil {
|
||||
threefoldDown = threefoldDown + len(secKillList)
|
||||
}
|
||||
|
||||
return threefoldDown, threefoldUp
|
||||
}
|
||||
|
||||
func getStoreShippingTime(storeTime string) (string, error) {
|
||||
time2 := strings.Split(storeTime, ";")
|
||||
aa := int(time.Now().Weekday())
|
||||
if aa == 0 {
|
||||
aa = 7
|
||||
}
|
||||
if len(time2) == 1 {
|
||||
aa = 1
|
||||
}
|
||||
intervals, err := parseIntervals(time2[aa-1])
|
||||
if err != nil {
|
||||
fmt.Printf("解析错误: %v\n", err)
|
||||
return "", err
|
||||
}
|
||||
|
||||
merged := mergeIntervals(intervals)
|
||||
|
||||
totalMinutes := 0
|
||||
for _, iv := range merged {
|
||||
totalMinutes += iv.end - iv.start
|
||||
}
|
||||
return fmt.Sprintf("%.2f", float64(totalMinutes)/float64(60)), err
|
||||
}
|
||||
|
||||
// timeToMinutes 将 "HH:MM" 转为当天第几分钟(0 ~ 1439)
|
||||
func timeToMinutes(t string) (int, error) {
|
||||
parts := strings.Split(t, ":")
|
||||
if len(parts) != 2 {
|
||||
return 0, fmt.Errorf("invalid time format: %s", t)
|
||||
}
|
||||
h, err := strconv.Atoi(parts[0])
|
||||
if err != nil || h < 0 || h > 23 {
|
||||
return 0, fmt.Errorf("invalid hour in %s", t)
|
||||
}
|
||||
m, err := strconv.Atoi(parts[1])
|
||||
if err != nil || m < 0 || m > 59 {
|
||||
return 0, fmt.Errorf("invalid minute in %s", t)
|
||||
}
|
||||
return h*60 + m, nil
|
||||
}
|
||||
|
||||
// parseIntervals 解析 "00:00-01:00,01:05-23:59" → []interval
|
||||
type interval struct {
|
||||
start, end int // minutes since 00:00
|
||||
}
|
||||
|
||||
func parseIntervals(s string) ([]interval, error) {
|
||||
var intervals []interval
|
||||
for _, seg := range strings.Split(s, ",") {
|
||||
seg = strings.TrimSpace(seg)
|
||||
if seg == "" {
|
||||
continue
|
||||
}
|
||||
parts := strings.Split(seg, "-")
|
||||
if len(parts) != 2 {
|
||||
return nil, fmt.Errorf("invalid interval format: %s", seg)
|
||||
}
|
||||
startMins, err := timeToMinutes(strings.TrimSpace(parts[0]))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
endMins, err := timeToMinutes(strings.TrimSpace(parts[1]))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if startMins > endMins {
|
||||
return nil, fmt.Errorf("start after end in interval: %s", seg)
|
||||
}
|
||||
intervals = append(intervals, interval{start: startMins, end: endMins})
|
||||
}
|
||||
return intervals, nil
|
||||
}
|
||||
|
||||
// mergeIntervals "git.rosy.net.cn/重叠/相邻区间(如 [0,60], [65,1439] → 保留两个;若 [0,60], [60,120] → 可合并为 [0,120])
|
||||
func mergeIntervals(ints []interval) []interval {
|
||||
if len(ints) == 0 {
|
||||
return ints
|
||||
}
|
||||
// 排序
|
||||
sort.Slice(ints, func(i, j int) bool {
|
||||
return ints[i].start < ints[j].start
|
||||
})
|
||||
|
||||
merged := make([]interval, 0, len(ints))
|
||||
curr := ints[0]
|
||||
for i := 1; i < len(ints); i++ {
|
||||
if ints[i].start <= curr.end { // 重叠或紧邻(如 end=60, next.start=60 → 合并)
|
||||
if ints[i].end > curr.end {
|
||||
curr.end = ints[i].end
|
||||
}
|
||||
} else {
|
||||
merged = append(merged, curr)
|
||||
curr = ints[i]
|
||||
}
|
||||
}
|
||||
merged = append(merged, curr)
|
||||
return merged
|
||||
}
|
||||
|
||||
type ShippingList struct {
|
||||
TimeRange string `json:"time_range"` // 配送生效时间范围
|
||||
MinPrice float64 `json:"min_price"` // 最小起送价
|
||||
ShippingFee float64 `json:"shipping_fee"` // 配送费
|
||||
}
|
||||
@@ -1,124 +0,0 @@
|
||||
package cs
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/baseapi/platformapi/weimobapi"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/authz/autils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxstore/cms"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
)
|
||||
|
||||
const (
|
||||
minCSOrderPayment = 0 // 供货订单的最小金额(单位为元)
|
||||
maxUnitPrice = 3000 // 为防止误填单价,限制单价最高(单位为分)
|
||||
)
|
||||
|
||||
func OnCallbackMsg(msg *weimobapi.CallbackMsg) (response *weimobapi.CallbackResponse) {
|
||||
orderID := utils.Int64ToStr(msg.OrderNo)
|
||||
jxutils.CallMsgHandler(func() {
|
||||
response = onOrderMsg(msg)
|
||||
}, jxutils.ComposeUniversalOrderID(orderID, model.VendorIDWSC))
|
||||
return response
|
||||
}
|
||||
|
||||
func onOrderMsg(msg *weimobapi.CallbackMsg) (response *weimobapi.CallbackResponse) {
|
||||
if msg.Event == weimobapi.MsgEventOrderStatusChange {
|
||||
if utils.ForceInterface2Int64(msg.MsgBody["orderStatus"]) == weimobapi.MsgOrderStatusFinished {
|
||||
if orderDetail, err := api.WeimobAPI.QueryOrderDetail2(msg.OrderNo, false); err == nil {
|
||||
if orderDetail.OrderStatus == weimobapi.OrderStatusFinished && orderDetail.PaymentAmount >= minCSOrderPayment {
|
||||
changeStoreSkusByOrder(orderDetail)
|
||||
}
|
||||
} else {
|
||||
response = weimobapi.Err2CallbackResponse(err, "")
|
||||
}
|
||||
}
|
||||
}
|
||||
return response
|
||||
}
|
||||
|
||||
func changeStoreSkusByOrder(order *weimobapi.OrderDetail) {
|
||||
receiverMobile := order.DeliveryDetail.LogisticsDeliveryDetail.ReceiverMobile
|
||||
ctx := jxcontext.NewWithUserName(nil, utils.LimitStringLen(utils.Int64ToStr(order.OrderNo), 32), nil, nil)
|
||||
if storeList, err := GetStoreList4Mobile(dao.GetDB(), []string{receiverMobile}); err == nil {
|
||||
if len(storeList) >= 1 {
|
||||
var skuBindInfos []*cms.StoreSkuBindInfo
|
||||
storeID := storeList[0].ID
|
||||
for _, v := range order.ItemList {
|
||||
nameID := int(utils.Str2Int64WithDefault(v.SkuCode, 0))
|
||||
unitPrice := v.CostPrice
|
||||
if nameID > 0 && (unitPrice > 0 && unitPrice < maxUnitPrice) {
|
||||
skuBindInfos = append(skuBindInfos, &cms.StoreSkuBindInfo{
|
||||
StoreID: storeID,
|
||||
NameID: nameID,
|
||||
UnitPrice: int(jxutils.StandardPrice2Int(unitPrice)),
|
||||
IsFocus: 1,
|
||||
IsSale: 1,
|
||||
})
|
||||
} else {
|
||||
globals.SugarLogger.Infof("[运营],微商城订单:%d,商品:%s没有设置正确的SkuName编码或单价,当前商家编码:%s,市场价:%s", order.OrderNo, v.SkuNum, v.SkuCode, jxutils.IntPrice2StandardString(jxutils.StandardPrice2Int(unitPrice)))
|
||||
}
|
||||
}
|
||||
if len(skuBindInfos) > 0 {
|
||||
var nameIDs []int
|
||||
for _, v := range skuBindInfos {
|
||||
nameIDs = append(nameIDs, v.NameID)
|
||||
}
|
||||
if skuNamesInfo, err := cms.GetSkuNames(ctx, "", false, false, map[string]interface{}{
|
||||
"nameIDs": string(utils.MustMarshal(nameIDs)),
|
||||
}, 0, 0); err == nil {
|
||||
for _, skuName := range skuNamesInfo.SkuNames {
|
||||
if skuName.Status != model.SkuStatusNormal {
|
||||
cms.UpdateSkuName(ctx, skuName.ID, map[string]interface{}{
|
||||
"status": model.SkuStatusNormal,
|
||||
}, false)
|
||||
}
|
||||
for _, sku := range skuName.Skus {
|
||||
if sku.Status != model.SkuStatusNormal {
|
||||
cms.UpdateSku(ctx, sku.ID, map[string]interface{}{
|
||||
"status": model.SkuStatusNormal,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
cms.UpdateStoreSkus(ctx, 0, storeID, skuBindInfos, true, true)
|
||||
} else {
|
||||
globals.SugarLogger.Debugf("changeStoreSkusByOrder orderID:%d, storeID:%d is empty", order.OrderNo, storeID)
|
||||
}
|
||||
} else {
|
||||
globals.SugarLogger.Infof("[运营],微商城订单:%d,手机:%s找不到唯一一个本地门店%d", order.OrderNo, receiverMobile, len(storeList))
|
||||
}
|
||||
} else {
|
||||
globals.SugarLogger.Warnf("changeStoreSkusByOrder orderNo:%d, receiverMobile:%s failed with err:%v", order.OrderNo, receiverMobile, err)
|
||||
}
|
||||
}
|
||||
|
||||
func GetStoreList4Mobile(db *dao.DaoDB, mobileList []string) (storeList []*model.Store, err error) {
|
||||
sql := `
|
||||
SELECT t1.*
|
||||
FROM store t1
|
||||
WHERE t1.deleted_at = ? /*AND t1.change_price_type = ?*/`
|
||||
sqlParams := []interface{}{
|
||||
utils.DefaultTimeValue,
|
||||
// model.StoreChangePriceTypeBossDisabled,
|
||||
}
|
||||
if len(mobileList) > 0 {
|
||||
questionMarks := dao.GenQuestionMarks(len(mobileList))
|
||||
sql += " AND (t1.tel1 IN (" + questionMarks + ") OR t1.tel2 IN (" + questionMarks + `)
|
||||
OR (SELECT
|
||||
COUNT(*)
|
||||
FROM casbin_rule t2
|
||||
JOIN user t3 ON t3.user_id = t2.v0 AND t3.mobile IN (` + questionMarks + `)
|
||||
WHERE t2.v1 = CONCAT(?, t1.id)
|
||||
) > 0)
|
||||
`
|
||||
sqlParams = append(sqlParams, mobileList, mobileList, mobileList, autils.NewStoreBossRole(-1).GetFullName())
|
||||
}
|
||||
err = dao.GetRows(db, &storeList, sql, sqlParams...)
|
||||
return storeList, err
|
||||
}
|
||||
@@ -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 enterprise
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/baseapi/platformapi/ebaiapi"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestOOO(t *testing.T) {
|
||||
product := map[string]interface{}{
|
||||
"apply_quantity": 1,
|
||||
"apply_refund_time": 1711447475000,
|
||||
"apply_refund_user_amount": 143,
|
||||
"commodity_type": 2,
|
||||
"custom_sku_id": "25381",
|
||||
"custom_sku_spec_id": "",
|
||||
"discount_detail": map[string]interface{}{
|
||||
"agent_discount_amount": 0,
|
||||
"discount_total_amount": 577,
|
||||
"merchant_discount_amount": 563,
|
||||
"platform_discount_amount": 14,
|
||||
"total_price": 720,
|
||||
"user_discount_amount": 0,
|
||||
},
|
||||
"free_gift": false,
|
||||
"fund_calculate_type": 0,
|
||||
"gift_related_sub_biz_order_id_list": nil,
|
||||
"is_combine": false,
|
||||
"last_refund_status": 0,
|
||||
"platform_sku_id": 16319366072214214,
|
||||
"refund_order_id": 2403269635888396215,
|
||||
"refund_quantity": 1,
|
||||
"refund_status": 50,
|
||||
"refund_user_amount": 143,
|
||||
"refund_weight": 350,
|
||||
"sku_name": "【尽享好价】西红柿 番茄约300~350g/组",
|
||||
"sku_spec_id": "null",
|
||||
"sub_biz_order_id": "4006435770425226215",
|
||||
"upc": "upc-25381",
|
||||
"virtual_type": "0",
|
||||
}
|
||||
skuList := aa(product)
|
||||
globals.SugarLogger.Debugf("=====skulist := %s", utils.Format4Output(skuList, false))
|
||||
|
||||
}
|
||||
|
||||
func aa(product map[string]interface{}) (skuList []*model.OrderSku) {
|
||||
skuList = make([]*model.OrderSku, 0, 0)
|
||||
if product["virtual_type"] == ebaiapi.OrderVirtualType {
|
||||
skuName := product["sku_name"].(string)
|
||||
_, _, _, specUnit, _, specQuality := jxutils.SplitSkuName(skuName)
|
||||
number := int(utils.MustInterface2Int64(product["apply_quantity"]))
|
||||
sku := &model.OrderSku{
|
||||
VendorOrderID: "1",
|
||||
VendorID: model.VendorIDEBAI,
|
||||
Count: number,
|
||||
SkuID: int(utils.Str2Int64WithDefault(utils.Interface2String(product[ebaiapi.KeyCustomSkuID]), 0)),
|
||||
VendorSkuID: utils.Int2Str(product["platform_sku_id"].(int)),
|
||||
SkuName: skuName,
|
||||
Weight: int(utils.Interface2Int64WithDefault(product["refund_weight"], 0)) / number, // 退单这里的total_weight有BUG,这里的total_weight还是没有退单时的值
|
||||
VendorPrice: utils.MustInterface2Int64(product["refund_user_amount"]),
|
||||
}
|
||||
//sku.SalePrice, _, sku.StoreSubName = getSkuSalePrice(product)
|
||||
sku.SalePrice = utils.Interface2Int64WithDefault(product["discount_detail"].(map[string]interface{})["total_price"], 0)
|
||||
if sku.Weight == 0 {
|
||||
sku.Weight = jxutils.FormatSkuWeight(specQuality, specUnit) // 订单信息里没有重量,只有名字里尝试找
|
||||
}
|
||||
skuList = append(skuList, sku)
|
||||
}
|
||||
return skuList
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
package enterprise
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/baseapi/platformapi/enterprise_wechat"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/model/legacymodel"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
var EnterpriseSuite = new(enterprise_wechat.SuiteTicketInfo)
|
||||
|
||||
// 初始化加载全局变量
|
||||
func Init() {
|
||||
var config []*legacymodel.Config
|
||||
sql := `SELECT * FROM config WHERE thirdparty = ? `
|
||||
if err := dao.GetRows(dao.GetDB(), &config, sql, []interface{}{"enterprise"}...); err != nil {
|
||||
globals.SugarLogger.Debug("enterprice init config err = ", err)
|
||||
}
|
||||
if len(config) >= model.YES {
|
||||
EnterpriseSuite.SuiteId = config[0].RefreshToken
|
||||
EnterpriseSuite.SuiteTicket = config[0].Token
|
||||
EnterpriseSuite.InfoType = ""
|
||||
time, _ := strconv.ParseInt(config[0].Date, 10, 64)
|
||||
EnterpriseSuite.TimeStamp = time
|
||||
}
|
||||
}
|
||||
|
||||
func UpdateEnterpriseSuite(data *enterprise_wechat.SuiteTicketInfo) error {
|
||||
if data.SuiteTicket != "" && data.TimeStamp > 0 {
|
||||
EnterpriseSuite = data
|
||||
}
|
||||
// 修改数据库
|
||||
db := dao.GetDB()
|
||||
config := &legacymodel.Config{
|
||||
Thirdparty: "enterprise",
|
||||
Token: data.SuiteTicket,
|
||||
Date: string(data.TimeStamp),
|
||||
LastOperator: model.AdminName,
|
||||
RefreshToken: data.SuiteId,
|
||||
}
|
||||
return dao.CreateOrUpdate(db, config)
|
||||
}
|
||||
@@ -1,484 +0,0 @@
|
||||
package enterprise
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"git.rosy.net.cn/baseapi/platformapi/ebaiapi"
|
||||
"git.rosy.net.cn/baseapi/platformapi/jdapi"
|
||||
"git.rosy.net.cn/baseapi/platformapi/mtwmapi"
|
||||
|
||||
//"git.rosy.net.cn/baseapi/platformapi/mtwmapi"
|
||||
tao "git.rosy.net.cn/baseapi/platformapi/tao_vegetable"
|
||||
domain585 "git.rosy.net.cn/baseapi/platformapi/tao_vegetable/sdk/ability585/domain"
|
||||
request585 "git.rosy.net.cn/baseapi/platformapi/tao_vegetable/sdk/ability585/request"
|
||||
product_listV2_request "git.rosy.net.cn/baseapi/platformapi/tiktok_shop/sdk-golang/api/product_listV2/request"
|
||||
product_listV2_response "git.rosy.net.cn/baseapi/platformapi/tiktok_shop/sdk-golang/api/product_listV2/response"
|
||||
sku_syncStock_request "git.rosy.net.cn/baseapi/platformapi/tiktok_shop/sdk-golang/api/sku_syncStock/request"
|
||||
"git.rosy.net.cn/baseapi/platformapi/tiktok_shop/tiktok_api"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxstore/cms"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api/apimanager"
|
||||
beego "github.com/astaxie/beego/server/web"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// 该函数主要用于对比京西平台商品和各个平台门店商品的差异
|
||||
// 对比上下架状态以及商品价格差异,相同的不做修改,不同的以京西系统商品为主
|
||||
func CompareJxVendorSku(jxStoreId int, vendorIds []int) (string, error) {
|
||||
var (
|
||||
db = dao.GetDB()
|
||||
errListToStr = new(strings.Builder)
|
||||
)
|
||||
skuList, err := dao.GetStoresSkusInfo(db, []int{jxStoreId}, nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// 门店商品列表平
|
||||
skuMap := make(map[string]*model.StoreSkuBind, 0)
|
||||
skuIdList := make([]string, 0, len(skuList))
|
||||
for _, v := range skuList {
|
||||
localSkuId := utils.Int2Str(v.SkuID)
|
||||
skuMap[localSkuId] = v
|
||||
skuIdList = append(skuIdList, localSkuId)
|
||||
}
|
||||
|
||||
// 有效的三方平台
|
||||
storeMap, err := dao.GetStoresMapList(db, vendorIds, []int{jxStoreId}, []int{model.StoreStatusOpened, model.StoreStatusClosed, model.StoreStatusHaveRest}, model.StoreStatusDisabled, 1, "", "", "")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
for _, sm := range storeMap {
|
||||
switch sm.VendorID {
|
||||
case model.VendorIDJD:
|
||||
if errs := JdSyncSkuPriceAndStatus(db, sm, skuMap); err != nil {
|
||||
errListToStr.WriteString(errs.Error())
|
||||
globals.SugarLogger.Debugf("京东同步商品异常信息: %v", errs)
|
||||
}
|
||||
continue
|
||||
case model.VendorIDMTWM:
|
||||
if errs := MtWmSyncSkuPriceAndStatus(db, sm, skuMap); errs != nil {
|
||||
errListToStr.WriteString(errs.Error())
|
||||
globals.SugarLogger.Debugf("美团同步商品异常信息: %v", errs)
|
||||
}
|
||||
continue
|
||||
case model.VendorIDEBAI:
|
||||
if errs := EBaiSyncSkuPriceAndStatus(db, sm, skuMap); errs != nil {
|
||||
errListToStr.WriteString(errs.Error())
|
||||
globals.SugarLogger.Debugf("饿百同步商品异常信息: %v", errs)
|
||||
}
|
||||
continue
|
||||
case model.VendorIDDD:
|
||||
if errs := TiktokSyncSkuPriceAndStatus(db, sm, skuMap); errs != nil {
|
||||
errListToStr.WriteString(errs.Error())
|
||||
globals.SugarLogger.Debugf("抖音同步商品异常信息: %v", errs)
|
||||
}
|
||||
continue
|
||||
case model.VendorIDTaoVegetable:
|
||||
if errs := TaoSyncSkuPriceAndStatus(db, sm, skuMap, skuIdList); errs != nil {
|
||||
errListToStr.WriteString(errs.Error())
|
||||
globals.SugarLogger.Debugf("淘宝同步商品异常信息: %v", errs)
|
||||
}
|
||||
continue
|
||||
default:
|
||||
return errListToStr.String(), fmt.Errorf("无法识别的平台id")
|
||||
}
|
||||
}
|
||||
|
||||
return "", err
|
||||
}
|
||||
|
||||
// MtWmSyncSkuPriceAndStatus 校验美团平台和京西系统商品差异
|
||||
func MtWmSyncSkuPriceAndStatus(db *dao.DaoDB, sm *model.StoreMap, skuMap map[string]*model.StoreSkuBind) (err error) {
|
||||
var (
|
||||
mtApi = apimanager.CurAPIManager.GetAPI(sm.VendorID, sm.VendorOrgCode).(*mtwmapi.API)
|
||||
i = model.NO
|
||||
foodListData = make([]*mtwmapi.AppFood, 0, 0)
|
||||
errs = make([]string, 0, 0)
|
||||
vendorStatus = 0
|
||||
)
|
||||
|
||||
if len(skuMap) == 0 || sm.IsSync != model.YES {
|
||||
return fmt.Errorf("门店未打开同步或者未关注商品")
|
||||
}
|
||||
|
||||
if sm.VendorOrgCode == globals.Mtwm2Code {
|
||||
mtApi = mtwmapi.New(beego.AppConfig.DefaultString("mtwmAppID2", ""), beego.AppConfig.DefaultString("mtwmSecret2", ""), beego.AppConfig.DefaultString("mtwmCallbackURL2", ""), "")
|
||||
mtApi.SetToken(sm.MtwmToken)
|
||||
} else {
|
||||
mtApi = partner.CurAPIManager.GetAPI(model.VendorIDMTWM, sm.VendorOrgCode).(*mtwmapi.API)
|
||||
}
|
||||
|
||||
for {
|
||||
foodList, err := mtApi.RetailListAll(sm.VendorStoreID, i)
|
||||
if err != nil {
|
||||
globals.SugarLogger.Debugf("美团商品价格和上下架状态获取平台商品异常 :%v", err)
|
||||
break
|
||||
}
|
||||
foodListData = append(foodListData, foodList...)
|
||||
if len(foodList) < 100 {
|
||||
break
|
||||
}
|
||||
i++
|
||||
}
|
||||
|
||||
for _, vsl := range foodListData {
|
||||
if sku, ok := skuMap[vsl.AppFoodCode]; ok {
|
||||
// 同步商品价格
|
||||
if utils.Float64TwoInt(vsl.Price*float64(100)) != sku.MtwmPrice {
|
||||
_, err = cms.CurVendorSync.SyncStoresSkus2(jxcontext.AdminCtx, nil, 0, db, []int{sm.VendorID}, []int{sku.StoreID}, false, []int{sku.SkuID}, []int{27379}, model.SyncFlagPriceMask, true, true)
|
||||
if err != nil {
|
||||
errs = append(errs, fmt.Sprintf("skuCode:%d,修改美团价格错误:%v", sku.SkuID, err))
|
||||
}
|
||||
}
|
||||
// 同步商品上下架状态
|
||||
// SPU(可能包含多个SKU)上下架状态,字段取值范围:0-全部sku上架,1-全部sku下架。以下功能灰度中:若同时传递sku_is_sold_out,则优先根据sku_is_sold_out传参判断单个sku的上下架状态。
|
||||
// 本地sku.Status 0-不可售, 1-可售
|
||||
if vsl.IsSoldOut == sku.Status {
|
||||
if sku.Status == model.SkuStatusNormal {
|
||||
vendorStatus = mtwmapi.SellStatusOnline
|
||||
} else {
|
||||
vendorStatus = mtwmapi.SellStatusOffline
|
||||
}
|
||||
|
||||
param := []*mtwmapi.BareStoreFoodInfo{
|
||||
&mtwmapi.BareStoreFoodInfo{
|
||||
AppFoodCode: utils.Int64ToStr(sku.MtwmID),
|
||||
Skus: nil,
|
||||
},
|
||||
}
|
||||
foodErrList, err := mtApi.RetailSellStatus(jxcontext.AdminCtx.GetTrackInfo(), sm.VendorStoreID, param, vendorStatus)
|
||||
if err != nil {
|
||||
errs = append(errs, fmt.Sprintf("skuCode:%d,修改美团可售状态错误%v", sku.SkuID, err))
|
||||
}
|
||||
for _, fel := range foodErrList {
|
||||
errs = append(errs, fmt.Sprintf("skuCode:%s,修改美团可售状态错误:%s", fel.AppFoodCode, fel.ErrorMsg))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
param := []*mtwmapi.BareStoreFoodInfo{
|
||||
&mtwmapi.BareStoreFoodInfo{
|
||||
AppFoodCode: vsl.AppFoodCode,
|
||||
Skus: nil,
|
||||
},
|
||||
}
|
||||
foodErrList, err := mtApi.RetailSellStatus(jxcontext.AdminCtx.GetTrackInfo(), sm.VendorStoreID, param, mtwmapi.SellStatusOffline)
|
||||
if err != nil {
|
||||
errs = append(errs, fmt.Sprintf("skuCode:%d,修改美团可售状态错误%v", vsl.AppFoodCode, err))
|
||||
}
|
||||
for _, fel := range foodErrList {
|
||||
errs = append(errs, fmt.Sprintf("skuCode:%s,修改美团可售状态错误:%s", fel.AppFoodCode, fel.ErrorMsg))
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(errs) == model.NO {
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("%s", strings.Join(errs, ","))
|
||||
}
|
||||
|
||||
// EBaiSyncSkuPriceAndStatus 校验饿了么平台和京西系统商品差异
|
||||
func EBaiSyncSkuPriceAndStatus(db *dao.DaoDB, sm *model.StoreMap, skuMap map[string]*model.StoreSkuBind) (err error) {
|
||||
var (
|
||||
ebaiApi = apimanager.CurAPIManager.GetAPI(sm.VendorID, sm.VendorOrgCode).(*ebaiapi.API)
|
||||
//skuIdOffset = 0
|
||||
foodListData = make([]*ebaiapi.SkuInfo, 0, 0)
|
||||
errs = make([]string, 0, 0)
|
||||
)
|
||||
|
||||
if len(skuMap) == 0 || sm.IsSync != model.YES {
|
||||
return fmt.Errorf("门店未打开同步或者未关注商品")
|
||||
}
|
||||
|
||||
for {
|
||||
page := 1
|
||||
param := &ebaiapi.SkuListParams{
|
||||
Page: page,
|
||||
PageSize: 100,
|
||||
//SkuIdOffset: skuIdOffset,
|
||||
}
|
||||
foodList, err := ebaiApi.SkuList(utils.Int2Str(sm.StoreID), param)
|
||||
if err != nil {
|
||||
globals.SugarLogger.Debugf("饿了么商品价格和上下架状态获取平台商品异常 :%v", err)
|
||||
break
|
||||
}
|
||||
|
||||
foodListData = append(foodListData, foodList.List...)
|
||||
if len(foodList.List) < 100 {
|
||||
break
|
||||
}
|
||||
//skuIdOffset = foodList.SkuIdOffset
|
||||
page += 1
|
||||
}
|
||||
globals.SugarLogger.Debugf("======len foodListData:= %d", len(foodListData))
|
||||
globals.SugarLogger.Debugf("======len skuMap:= %d", len(skuMap))
|
||||
for _, vsl := range foodListData {
|
||||
if sku, ok := skuMap[vsl.CustomSkuId]; ok {
|
||||
// 同步商品价格
|
||||
if vsl.SalePrice != sku.EbaiPrice {
|
||||
_, err = cms.CurVendorSync.SyncStoresSkus2(jxcontext.AdminCtx, nil, 0, db, []int{sm.VendorID}, []int{sku.StoreID}, false, []int{sku.SkuID}, []int{27379}, model.SyncFlagPriceMask, true, true)
|
||||
}
|
||||
// 同步商品上下架状态
|
||||
// 1为上架,0为下架
|
||||
// 本地sku.Status 0-不可售, 1-可售
|
||||
if vsl.Status != utils.Int2Str(sku.Status) {
|
||||
// 平台上架本地下架,将平台商品下架
|
||||
if sku.Status == model.StoreSkuBindStatusNormal {
|
||||
ebailResult, err := ebaiApi.SkuOnline(jxcontext.AdminCtx.GetTrackInfo(), utils.Int2Str(sm.StoreID), []int64{sku.EbaiID}, nil, nil)
|
||||
if err != nil {
|
||||
errs = append(errs, fmt.Sprintf("skuCode:%d,修改饿百可售状态错误%v", sku.SkuID, err))
|
||||
}
|
||||
for _, fel := range ebailResult.FailedList {
|
||||
errs = append(errs, fmt.Sprintf("skuCode:%d,修改饿百可售状态错误:%s", fel.SkuID, fel.ErrorMsg))
|
||||
}
|
||||
} else {
|
||||
err = ebaiApi.SkuOfflineOne(jxcontext.AdminCtx.GetTrackInfo(), utils.Int2Str(sm.StoreID), sku.EbaiID, "", "")
|
||||
if err != nil {
|
||||
errs = append(errs, fmt.Sprintf("skuCode:%d,修改饿百不可售状态错误%v", sku.SkuID, err))
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_, err = ebaiApi.SkuDelete(jxcontext.AdminCtx.GetTrackInfo(), utils.Int2Str(sm.StoreID), nil, []string{vsl.CustomSkuId})
|
||||
|
||||
//err = ebaiApi.SkuOfflineOne(jxcontext.AdminCtx.GetTrackInfo(), utils.Int2Str(sm.StoreID), utils.Str2Int64(vsl.CustomSkuId), "", "")
|
||||
if err != nil {
|
||||
errs = append(errs, fmt.Sprintf("skuCode:%d,修改饿百不可售状态错误%v", sku.SkuID, err))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(errs) == model.NO {
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("%s", strings.Join(errs, ","))
|
||||
}
|
||||
|
||||
// TaoSyncSkuPriceAndStatus 校验淘宝平台和京西系统商品差异
|
||||
func TaoSyncSkuPriceAndStatus(db *dao.DaoDB, sm *model.StoreMap, skuMap map[string]*model.StoreSkuBind, skuIdList []string) (err error) {
|
||||
var (
|
||||
taoApi = apimanager.CurAPIManager.GetAPI(sm.VendorID, sm.VendorOrgCode).(*tao.API)
|
||||
length = len(skuIdList) / 100
|
||||
foodListData = make([]domain585.AlibabaWdkSkuQuerySkuDo, 0, 0)
|
||||
onlineStatus int64 = 0
|
||||
)
|
||||
if len(skuMap) == 0 || sm.IsSync != model.YES {
|
||||
return fmt.Errorf("门店未打开同步或者未关注商品")
|
||||
}
|
||||
if len(skuIdList)%100 != 0 {
|
||||
length += 1
|
||||
}
|
||||
|
||||
// 获取平台商品列表
|
||||
for i := 0; i < length; i++ {
|
||||
skuCods := skuIdList[i*100 : (i+1)*100]
|
||||
foodList, _ := taoApi.QueryStoreSKu(&request585.AlibabaWdkSkuQueryRequest{Param: &domain585.AlibabaWdkSkuQuerySkuQueryDo{
|
||||
OuCode: utils.String2Pointer(sm.VendorStoreID),
|
||||
SkuCodes: &skuCods,
|
||||
}})
|
||||
for _, fl := range *foodList {
|
||||
if *fl.Success {
|
||||
foodListData = append(foodListData, *fl.Model)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 比较商品差异
|
||||
errs := make([]string, 0, 0)
|
||||
for _, vsl := range foodListData {
|
||||
if sku, ok := skuMap[*vsl.SkuCode]; ok {
|
||||
// 同步商品价格
|
||||
if utils.Float64TwoInt(utils.Str2Float64(*vsl.SalePrice)*float64(100)) != sku.TaoPrice {
|
||||
_, err = cms.CurVendorSync.SyncStoresSkus2(jxcontext.AdminCtx, nil, 0, db, []int{sm.VendorID}, []int{sku.StoreID}, false, []int{sku.SkuID}, []int{27379}, model.SyncFlagPriceMask, true, true)
|
||||
if err != nil {
|
||||
errs = append(errs, fmt.Sprintf("淘宝对比商品价格异常skuid:%d,错误%v", sku.SkuID, err))
|
||||
}
|
||||
}
|
||||
// 同步商品上下架状态
|
||||
// 是否线上可售 是 0:否 1:是。
|
||||
// 本地sku.Status 0-不可售, 1-可售
|
||||
if int(*vsl.OnlineSaleFlag) != sku.Status {
|
||||
// 平台上架本地下架,将平台商品下架
|
||||
param := &request585.AlibabaWdkSkuUpdateRequest{}
|
||||
updateSkuList := make([]domain585.AlibabaWdkSkuUpdateSkuDo, 0, 0)
|
||||
if sku.Status == model.SkuStatusNormal {
|
||||
onlineStatus = tao.CreateOnlineSaleFlag
|
||||
} else {
|
||||
onlineStatus = tao.CreateOfflineSaleFlag
|
||||
}
|
||||
updateSkuList = append(updateSkuList, domain585.AlibabaWdkSkuUpdateSkuDo{
|
||||
OuCode: utils.String2Pointer(utils.Int64ToStr(sku.TaoID)),
|
||||
SkuCode: utils.String2Pointer(utils.Int2Str(sku.SkuID)),
|
||||
OnlineSaleFlag: utils.Int64ToPointer(onlineStatus),
|
||||
SubTitle: utils.String2Pointer("小时达"),
|
||||
AllowAppSale: utils.Int64ToPointer(onlineStatus),
|
||||
//CleanSkuMemberPrice: utils.Int64ToPointer(model.YES),
|
||||
})
|
||||
param.ParamList = &updateSkuList
|
||||
|
||||
result, err := taoApi.UpdateStoreSku(param)
|
||||
if err != nil {
|
||||
errs = append(errs, fmt.Sprintf("skuCode:%d,修改饿百可售状态错误%v", sku.SkuID, err))
|
||||
}
|
||||
for _, fel := range *result {
|
||||
if fel.ErrMsg != "" {
|
||||
errs = append(errs, fmt.Sprintf("skuCode:%s,修改饿百可售状态错误:%s", fel.SkuID, fel.ErrMsg))
|
||||
}
|
||||
}
|
||||
//_, err = cms.CurVendorSync.SyncStoresSkus2(jxcontext.AdminCtx, nil, 0, db, []int{sm.VendorID}, []int{sku.StoreID}, false, []int{sku.SkuID}, []int{27379}, 56, true, true)
|
||||
//if err != nil {
|
||||
// errs = append(errs, fmt.Sprintf("%v", err))
|
||||
//}
|
||||
}
|
||||
} else {
|
||||
// 平台上架本地下架,将平台商品下架
|
||||
param := &request585.AlibabaWdkSkuUpdateRequest{}
|
||||
updateSkuList := make([]domain585.AlibabaWdkSkuUpdateSkuDo, 0, 0)
|
||||
onlineStatus = tao.CreateOfflineSaleFlag
|
||||
updateSkuList = append(updateSkuList, domain585.AlibabaWdkSkuUpdateSkuDo{
|
||||
OuCode: vsl.OuCode,
|
||||
SkuCode: vsl.SkuCode,
|
||||
OnlineSaleFlag: utils.Int64ToPointer(onlineStatus),
|
||||
SubTitle: utils.String2Pointer("小时达"),
|
||||
AllowAppSale: utils.Int64ToPointer(onlineStatus),
|
||||
//CleanSkuMemberPrice: utils.Int64ToPointer(model.YES),
|
||||
})
|
||||
param.ParamList = &updateSkuList
|
||||
result, err := taoApi.UpdateStoreSku(param)
|
||||
if err != nil {
|
||||
errs = append(errs, fmt.Sprintf("skuCode:%d,修改饿百可售状态错误%v", sku.SkuID, err))
|
||||
}
|
||||
for _, fel := range *result {
|
||||
if fel.ErrMsg != "" {
|
||||
errs = append(errs, fmt.Sprintf("skuCode:%s,修改饿百可售状态错误:%s", fel.SkuID, fel.ErrMsg))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(errs) == model.NO {
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("%s", strings.Join(errs, ","))
|
||||
}
|
||||
|
||||
// TiktokSyncSkuPriceAndStatus 校验抖音平台和京西系统商品差异
|
||||
func TiktokSyncSkuPriceAndStatus(db *dao.DaoDB, sm *model.StoreMap, skuMap map[string]*model.StoreSkuBind) (err error) {
|
||||
var (
|
||||
tiktokApi = apimanager.CurAPIManager.GetAPI(sm.VendorID, sm.VendorOrgCode).(*tiktok_api.API)
|
||||
page = 0
|
||||
foodListData = make([]product_listV2_response.DataItem, 0, 0)
|
||||
errs = make([]string, 0, 0)
|
||||
)
|
||||
if len(skuMap) == 0 || sm.IsSync != model.YES {
|
||||
return fmt.Errorf("门店未打开同步或者未关注商品")
|
||||
}
|
||||
for {
|
||||
param := &product_listV2_request.ProductListV2Param{
|
||||
Page: int64(page),
|
||||
Size: 100,
|
||||
StoreId: utils.Str2Int64(sm.VendorStoreID),
|
||||
}
|
||||
foodList, err := tiktokApi.GetSkuDetailList(param)
|
||||
if err != nil {
|
||||
globals.SugarLogger.Debugf("抖音商品价格和上下架状态获取平台商品异常 :%v", err)
|
||||
break
|
||||
}
|
||||
|
||||
foodListData = append(foodListData, foodList.Data...)
|
||||
if len(foodList.Data) < 100 {
|
||||
break
|
||||
}
|
||||
page += 1
|
||||
}
|
||||
|
||||
for _, vsl := range foodListData {
|
||||
if sku, ok := skuMap[vsl.OuterProductId]; ok {
|
||||
// 同步商品价格
|
||||
if vsl.DiscountPrice != int64(sku.DdPrice) {
|
||||
_, err = cms.CurVendorSync.SyncStoresSkus2(jxcontext.AdminCtx, nil, 0, db, []int{sm.VendorID}, []int{sku.StoreID}, false, []int{sku.SkuID}, []int{27379}, model.SyncFlagPriceMask, true, true)
|
||||
if err != nil {
|
||||
errs = append(errs, fmt.Sprintf("抖音对比商品价格异常skuid:%d,错误%v", sku.SkuID, err))
|
||||
}
|
||||
}
|
||||
// 同步商品上下架状态
|
||||
// 0-在线 1-下线
|
||||
// 本地sku.Status 0-不可售,1-可售
|
||||
if vsl.Status == int64(sku.Status) {
|
||||
if sku.Status == model.SkuStatusNormal {
|
||||
param := &sku_syncStock_request.SkuSyncStockParam{
|
||||
ProductId: sku.DdID,
|
||||
Incremental: false,
|
||||
StockNum: 99999,
|
||||
OutSkuId: int64(sku.SkuID),
|
||||
}
|
||||
if err = tiktokApi.UpdateSkuStock(param); err != nil {
|
||||
errs = append(errs, fmt.Sprintf("抖音对比商品上架异常skuid:%d,错误%v", sku.SkuID, err))
|
||||
}
|
||||
} else {
|
||||
param := &sku_syncStock_request.SkuSyncStockParam{
|
||||
ProductId: sku.DdID,
|
||||
Incremental: false,
|
||||
StockNum: 0,
|
||||
OutSkuId: int64(sku.SkuID),
|
||||
}
|
||||
if err = tiktokApi.UpdateSkuStock(param); err != nil {
|
||||
errs = append(errs, fmt.Sprintf("抖音对比商品下架异常skuid:%d,错误%v", sku.SkuID, err))
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
param := &sku_syncStock_request.SkuSyncStockParam{
|
||||
ProductId: sku.DdID,
|
||||
Incremental: false,
|
||||
StockNum: 0,
|
||||
OutSkuId: int64(sku.SkuID),
|
||||
}
|
||||
if err = tiktokApi.UpdateSkuStock(param); err != nil {
|
||||
errs = append(errs, fmt.Sprintf("抖音对比商品下架异常skuid:%d,错误%v", sku.SkuID, err))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(errs) == model.NO {
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("%s", strings.Join(errs, ","))
|
||||
}
|
||||
|
||||
// JdSyncSkuPriceAndStatus 校验京东平台和京西系统商品差异
|
||||
func JdSyncSkuPriceAndStatus(db *dao.DaoDB, sm *model.StoreMap, skuMap map[string]*model.StoreSkuBind) (err error) {
|
||||
var (
|
||||
jdsApi = apimanager.CurAPIManager.GetAPI(sm.VendorID, sm.VendorOrgCode).(*jdapi.API)
|
||||
)
|
||||
skuVendibilityList := make([]*jdapi.StockVendibility, 0, 0)
|
||||
for _, v := range skuMap {
|
||||
skuVendibilityList = append(skuVendibilityList, &jdapi.StockVendibility{
|
||||
OutSkuId: utils.Int2Str(v.SkuID),
|
||||
DoSale: v.Status == model.SkuStatusNormal,
|
||||
})
|
||||
}
|
||||
|
||||
count := len(skuVendibilityList) / 50
|
||||
if len(skuVendibilityList)%50 != 0 {
|
||||
count += 1
|
||||
}
|
||||
|
||||
for i := 1; i <= count; i++ {
|
||||
if i == count {
|
||||
jdsApi.BatchUpdateVendibility(jxcontext.AdminCtx.GetTrackInfo(), "", sm.VendorStoreID, skuVendibilityList[(i-1)*50:], jxcontext.AdminCtx.GetUserName())
|
||||
} else {
|
||||
jdsApi.BatchUpdateVendibility(jxcontext.AdminCtx.GetTrackInfo(), "", sm.VendorStoreID, skuVendibilityList[(i-1)*50:i*50], jxcontext.AdminCtx.GetUserName())
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Errorf("京东运行结束")
|
||||
}
|
||||
@@ -1,182 +0,0 @@
|
||||
package enterprise_session
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
enterprise "git.rosy.net.cn/baseapi/platformapi/enterprise_wechat"
|
||||
"git.rosy.net.cn/jx-callback/business/auth2"
|
||||
"git.rosy.net.cn/jx-callback/business/authz"
|
||||
"git.rosy.net.cn/jx-callback/business/authz/autils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxstore/cms"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type CreateSession struct {
|
||||
}
|
||||
|
||||
// 创建老板的业务群
|
||||
func (c *CreateSession) CreateBossToStaffAndCreateSession(token string, storeId int) (map[string]interface{}, error) {
|
||||
// 获取老本的电话和门店信息
|
||||
authInfo, err := auth2.GetTokenInfo(token)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
store, err := dao.GetStoreDetail2(dao.GetDB(), storeId, "", 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if store.Tel1 != authInfo.Mobile || store.Tel1 == "" {
|
||||
return nil, errors.New("不是门店老板,不创建群聊")
|
||||
}
|
||||
|
||||
// 检测用户是否存在
|
||||
if _, err := CheckUserExist(store); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 获取创建群聊所需基础人员id
|
||||
enterpriseIdList, err := CheckBoosGroupChat(store)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := make(map[string]interface{}, 0)
|
||||
result["enterpriseIdList"] = enterpriseIdList
|
||||
result["chatName"] = "京西菜市" + store.Name + "群"
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// 检测用户是否存在
|
||||
func CheckUserExist(store *dao.StoreDetail2) (string, error) {
|
||||
enterpriseUserId, err := api.EnterpriseChatHeadApi.GetUserIdByMobile(store.Tel1)
|
||||
if strings.Contains(fmt.Sprintf("%v", err), "user no exist") || strings.Contains(fmt.Sprintf("%v", err), "46004") {
|
||||
boss := &enterprise.CreateBoos2JXStaffReq{
|
||||
Userid: store.Tel1 + "_" + strconv.Itoa(store.ID),
|
||||
Name: store.LicenceOwnerName,
|
||||
Alias: "",
|
||||
Mobile: store.Tel1,
|
||||
Department: nil, // 四川省
|
||||
Order: nil,
|
||||
Gender: "1",
|
||||
Email: "",
|
||||
IsLeaderInDept: nil,
|
||||
Enable: 0,
|
||||
AvatarMediaid: "",
|
||||
Telephone: "",
|
||||
Address: store.Address,
|
||||
Extattr: enterprise.Extattr{},
|
||||
MainDepartment: 0,
|
||||
ToInvite: true,
|
||||
ExternalPosition: "",
|
||||
ExternalProfile: enterprise.ExternalProfile{},
|
||||
}
|
||||
if boss.Name == "" {
|
||||
boss.Name = store.Name + "(老板名称不存在)"
|
||||
}
|
||||
|
||||
// 查询本门店所属省code
|
||||
parentCityName := ""
|
||||
if store.CityCode == 0 {
|
||||
return "", errors.New("门店位置不能为空")
|
||||
}
|
||||
parentCityName, err = GetCityCode(store.CityCode)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
// 查询企业微信所有省份部门分类
|
||||
departmentList, err := api.EnterpriseChatHeadApi.GetAllDepartmentList()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
for _, v := range departmentList {
|
||||
if !strings.Contains(v.Name, parentCityName[:6]) {
|
||||
continue
|
||||
}
|
||||
boss.Department = []int{v.ID}
|
||||
break
|
||||
}
|
||||
|
||||
// 创建老板为京西员工,并存放在对应的省份里面
|
||||
if err := api.EnterpriseChatHeadApi.CreateBoss2JxStaff(boss); err != nil {
|
||||
return "", err
|
||||
}
|
||||
enterpriseUserId = boss.Userid
|
||||
}
|
||||
|
||||
return enterpriseUserId, err
|
||||
}
|
||||
|
||||
func GetCityCode(cityCode int) (string, error) {
|
||||
for i := 0; i < 4; i++ {
|
||||
place, err := dao.GetPlaceByCode(dao.GetDB(), cityCode)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if place.Level == model.YES && place.ParentCode == 0 {
|
||||
return place.Name, nil
|
||||
}
|
||||
cityCode = place.ParentCode
|
||||
}
|
||||
return "", errors.New("未查询到目标城市")
|
||||
}
|
||||
|
||||
// 获取当前门店企业内部人员信息
|
||||
func CheckBoosGroupChat(store *dao.StoreDetail2) ([]string, error) {
|
||||
// 获取门店角色
|
||||
roleNames := []string{"StoreBoss"}
|
||||
storeIDs := []int{store.ID}
|
||||
var roleList []*authz.RoleInfo
|
||||
for _, roleName := range roleNames {
|
||||
if roleName == authz.StoreRoleBoss {
|
||||
for _, storeID := range storeIDs {
|
||||
roleList = append(roleList, autils.NewRole(roleName, storeID))
|
||||
}
|
||||
} else {
|
||||
roleList = append(roleList, autils.NewRole(roleName, 0))
|
||||
}
|
||||
}
|
||||
retVal, err := cms.GetRolesUserList(nil, roleList)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 获取角色系统userId
|
||||
systemUserId := make([]string, 0, 0)
|
||||
for _, v := range retVal {
|
||||
if len(v) == 0 {
|
||||
return nil, errors.New("门店负责人为空,数据异常.联系管理员")
|
||||
}
|
||||
systemUserId = append(systemUserId, v...)
|
||||
}
|
||||
|
||||
// 根据userId获取系统用户电话号码
|
||||
userList, _, err := dao.GetUsers(dao.GetDB(), 0, "", systemUserId, nil, nil, 0, 50)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
enterpriseList := make([]string, 0, 0)
|
||||
// 获取用户企业微信用户id
|
||||
for _, v := range userList {
|
||||
enterpriseId, err := api.EnterpriseChatHeadApi.GetUserIdByMobile(*v.Mobile)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
enterpriseList = append(enterpriseList, enterpriseId)
|
||||
}
|
||||
return enterpriseList, nil
|
||||
}
|
||||
|
||||
// 获取企业微信token
|
||||
func GetEnterpriseTokenInfo() (string, string) {
|
||||
api.EnterpriseChatMin.CheckAccessTokenExpiresIn()
|
||||
api.EnterpriseChatHeadApi.CheckAccessTokenExpiresIn()
|
||||
return api.EnterpriseChatMin.ReturnToken(), api.EnterpriseChatHeadApi.ReturnToken()
|
||||
// 企业微信api
|
||||
//return api.EnterpriseChatHeadApi.ReturnToken()
|
||||
}
|
||||
@@ -1,188 +0,0 @@
|
||||
package auto_delivery
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"git.rosy.net.cn/baseapi/platformapi/tao_vegetable"
|
||||
"git.rosy.net.cn/jx-callback/business/jxcallback/scheduler/defsch"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"math/big"
|
||||
"strings"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
)
|
||||
|
||||
var riderListInfo = make(map[string][]map[string]string, 0)
|
||||
|
||||
func Init() {
|
||||
if len(riderListInfo) != 0 {
|
||||
return
|
||||
}
|
||||
db := dao.GetDB()
|
||||
// 骑手列表
|
||||
configRiderList, err := dao.QueryConfigs(db, "riderList", "Sys", "")
|
||||
if err != nil {
|
||||
globals.SugarLogger.Errorf("抖音自动刷单获取骑手列表错误:%v", err)
|
||||
return
|
||||
}
|
||||
list := make(map[string][]map[string]string, 0)
|
||||
if len(configRiderList[0].Value) > 0 {
|
||||
if err := json.Unmarshal([]byte(configRiderList[0].Value), &list); err != nil {
|
||||
globals.SugarLogger.Errorf("抖音自动刷单获取骑手列表错误:%v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 获取刷单地址
|
||||
addressList, err := dao.QueryConfigs(db, "refundAddress", "Sys", "")
|
||||
if err != nil {
|
||||
globals.SugarLogger.Errorf("抖音自动刷单获取刷单地址列表错误:%v", err)
|
||||
return
|
||||
}
|
||||
|
||||
for _, v := range strings.Split(addressList[0].Value, ",") {
|
||||
if _, ok := list[v]; ok && len(list[v]) >= 200 {
|
||||
continue
|
||||
}
|
||||
riderList, err := dao.GetAddressRiderInfo(db, v)
|
||||
if err != nil {
|
||||
globals.SugarLogger.Errorf("初始化各省份骑手信息错误:[%v]", err)
|
||||
return
|
||||
}
|
||||
addressRiderList := make([]map[string]string, 0)
|
||||
for i := 0; i < len(riderList); i++ {
|
||||
if len(riderList[i].CourierMobile) == 11 {
|
||||
riderMap := make(map[string]string, 1)
|
||||
riderMap[riderList[i].CourierName] = riderList[i].CourierMobile
|
||||
addressRiderList = append(addressRiderList, riderMap)
|
||||
}
|
||||
if len(addressRiderList) >= 200 {
|
||||
list[v] = addressRiderList
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
listStr, err := json.Marshal(list)
|
||||
if err != nil {
|
||||
globals.SugarLogger.Errorf("Marshal 骑手信息错误:[%v]", err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := dao.UpdateOperatorConfig(string(listStr), "Sys", "riderList"); err != nil {
|
||||
globals.SugarLogger.Errorf("UpdateOperatorConfig 骑手配置信息错误:[%v]", err)
|
||||
return
|
||||
}
|
||||
riderListInfo = list
|
||||
}
|
||||
|
||||
// AutoSettingFakeDelivery 抖音自动设置骑手, 推送假订单
|
||||
func AutoSettingFakeDelivery() {
|
||||
db := dao.GetDB()
|
||||
|
||||
// 查询需要刷单的门店
|
||||
configList, err := dao.QueryConfigs(db, "storeIdList", "Sys", "")
|
||||
if err != nil {
|
||||
globals.SugarLogger.Errorf("抖音自动刷单获取刷单门店列表错误:%v", err)
|
||||
return
|
||||
}
|
||||
if len(configList) != model.YES {
|
||||
globals.SugarLogger.Errorf("newConfig 刷单门店设置异常")
|
||||
return
|
||||
}
|
||||
|
||||
// 获取刷单门店订单
|
||||
storeList := strings.Split(configList[0].Value, ",")
|
||||
for _, v := range storeList {
|
||||
if !strings.Contains(v, "-") {
|
||||
globals.SugarLogger.Errorf("newConfig 刷单门店配置异常")
|
||||
return
|
||||
}
|
||||
storeIdAndVendorId := strings.Split(v, "-")
|
||||
if len(storeIdAndVendorId) == model.NO {
|
||||
continue
|
||||
}
|
||||
orderList, err := dao.GetOrderListByStoreList(db, []int64{utils.Str2Int64(storeIdAndVendorId[0])}, utils.Str2Int(storeIdAndVendorId[1]))
|
||||
if err != nil {
|
||||
globals.SugarLogger.Errorf("获取门店刷单记录错误")
|
||||
continue
|
||||
}
|
||||
if len(orderList) == model.NO {
|
||||
continue
|
||||
}
|
||||
|
||||
// 1.根据订单客户地址获取骑手列表
|
||||
riderKey := ""
|
||||
storeDetail, _ := dao.GetStoreDetail(db, utils.Str2Int(storeIdAndVendorId[0]), 0, "")
|
||||
if strings.Contains(storeDetail.Address, "重庆") || strings.Contains(storeDetail.Address, "上海") || strings.Contains(storeDetail.Address, "北京") || strings.Contains(storeDetail.Address, "天津") {
|
||||
riderKey = strings.Split(storeDetail.Address, "市")[0]
|
||||
} else if strings.Contains(storeDetail.Address, "省") {
|
||||
riderKey = strings.Split(storeDetail.Address, "省")[0]
|
||||
} else {
|
||||
place, err := dao.GetParentCodeByCode(db, storeDetail.CityCode)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if strings.Contains(place.Name, "省") {
|
||||
riderKey = strings.Split(place.Name, "省")[0]
|
||||
} else {
|
||||
riderKey = strings.Split(place.Name, "市")[0]
|
||||
}
|
||||
}
|
||||
|
||||
for _, order := range orderList {
|
||||
if len(riderListInfo[riderKey]) == model.NO {
|
||||
// 骑手列表
|
||||
configRiderList, err := dao.QueryConfigs(db, "riderList", "Sys", "")
|
||||
if err != nil {
|
||||
globals.SugarLogger.Errorf("抖音自动刷单获取骑手列表错误:%v", err)
|
||||
return
|
||||
}
|
||||
if err := json.Unmarshal([]byte(configRiderList[0].Value), &riderListInfo); err != nil {
|
||||
globals.SugarLogger.Errorf("抖音自动刷单获取骑手列表错误:%v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
randNumber, _ := rand.Int(rand.Reader, big.NewInt(int64(len(riderListInfo[riderKey]))))
|
||||
randTime := randNumber.Int64()
|
||||
if randTime < 0 {
|
||||
randTime = 1
|
||||
}
|
||||
if randTime >= int64(len(riderListInfo[riderKey])) {
|
||||
randTime = int64(len(riderListInfo[riderKey])) - 1
|
||||
}
|
||||
if (order.PhoneAscription == "" || strings.Split(order.PhoneAscription, "-")[0] != model.PhoneAscriptionAddressYes) && order.VendorID == model.VendorIDDD {
|
||||
continue
|
||||
}
|
||||
// 自动拣货
|
||||
if order.Status < model.OrderStatusFinishedPickup { // 未拣货
|
||||
handler := partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID)
|
||||
flag := model.IsOrderDeliveryByStore(order) || model.IsOrderDeliveryBySelf(order)
|
||||
if err := handler.PickupGoods(order, flag, jxcontext.AdminCtx.GetUserName()); err != nil {
|
||||
partner.CurOrderManager.OnOrderMsg(order, tao_vegetable.OrderStatusPickedUp, fmt.Sprintf("自动拣货错误:[%v]", err))
|
||||
break
|
||||
}
|
||||
partner.CurOrderManager.OnOrderMsg(order, tao_vegetable.OrderStatusPickedUp, "fake自动拣货,已拣货")
|
||||
}
|
||||
//自动发单
|
||||
if len(riderListInfo[riderKey]) == 0 {
|
||||
globals.SugarLogger.Errorf("riderListInfo[riderKey][randTime] :%s,%s,%d", riderListInfo[riderKey][randTime], riderKey, randTime)
|
||||
break
|
||||
}
|
||||
for riderName, riderPhone := range riderListInfo[riderKey][randTime] {
|
||||
if err := defsch.FixedScheduler.SelfDeliveringAndUpdateStatus(jxcontext.AdminCtx, order.VendorOrderID, order.VendorID, jxcontext.AdminCtx.GetUserName(), riderName, riderPhone); err != nil {
|
||||
partner.CurOrderManager.OnOrderMsg(order, tao_vegetable.OrderStatusPickedUp, fmt.Sprintf("自动发货错误:[%v]", err))
|
||||
break
|
||||
}
|
||||
partner.CurOrderManager.OnOrderMsg(order, tao_vegetable.OrderStatusCallRider, "自动发货,出库")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
package orderman
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/netprinter"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/weixinmsg"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/partner/purchase/jd"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
)
|
||||
|
||||
func (c *OrderManager) OnNewFakeJdOrder(vendorOrderID string) (err error) {
|
||||
utils.CallFuncAsync(func() {
|
||||
orderInfo, err := api.FakeJdAPI.FakeQuerySingleOrderRaw(vendorOrderID)
|
||||
if err == nil {
|
||||
order := jd.Map2Order(orderInfo)
|
||||
jxutils.RefreshOrderSkuRelated(order)
|
||||
err = c.notifyNewFakeJdOrder(order)
|
||||
}
|
||||
if err != nil {
|
||||
globals.SugarLogger.Warnf("OnNewFakeJdOrder failed with err:%v", err)
|
||||
}
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *OrderManager) notifyNewFakeJdOrder(order *model.GoodsOrder) (err error) {
|
||||
db := dao.GetDB()
|
||||
storeDetail, err := dao.GetStoreDetailByVendorStoreID(db, order.VendorStoreID, model.VendorIDJD, "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
realStoreID := storeDetail.ID
|
||||
if storeDetail.LinkStoreID != 0 {
|
||||
realStoreID = storeDetail.LinkStoreID
|
||||
}
|
||||
notifyWxNewFakeJdOrder(order, realStoreID)
|
||||
netprinter.PrintOrderByOrder4Store(jxcontext.AdminCtx, order, realStoreID, "", nil)
|
||||
return err
|
||||
}
|
||||
|
||||
func notifyWxNewFakeJdOrder(order *model.GoodsOrder, storeID int) (err error) {
|
||||
sb := new(strings.Builder)
|
||||
sb.WriteString("老板,你有新订单了\n")
|
||||
sb.WriteString(fmt.Sprintf("订单号:%s\n", order.VendorOrderID))
|
||||
sb.WriteString("送达时间:")
|
||||
if order.BusinessType == model.BusinessTypeDingshida {
|
||||
sb.WriteString(utils.Time2Str(order.ExpectedDeliveredTime))
|
||||
} else {
|
||||
sb.WriteString("立即达")
|
||||
}
|
||||
sb.WriteString("\n")
|
||||
sb.WriteString(fmt.Sprintf("买家:%s\n", order.ConsigneeName))
|
||||
sb.WriteString(fmt.Sprintf("电话:%s\n", order.ConsigneeMobile))
|
||||
sb.WriteString(fmt.Sprintf("收货地址:%s\n", order.ConsigneeAddress))
|
||||
sb.WriteString("商品详情:\n")
|
||||
for _, sku := range order.Skus {
|
||||
sb.WriteString(fmt.Sprintf("\t%s*%d\n", sku.SkuName, sku.Count))
|
||||
}
|
||||
title := fmt.Sprintf("你有到家菜市新订单%d", order.OrderSeq)
|
||||
content := sb.String()
|
||||
_, err = weixinmsg.SendStoreMessage(jxcontext.AdminCtx, title, content, []int{storeID}, nil, "", model.MessageTypeStore, true, true)
|
||||
return err
|
||||
}
|
||||
@@ -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,252 +0,0 @@
|
||||
package orderman
|
||||
|
||||
import (
|
||||
"math"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
)
|
||||
|
||||
const (
|
||||
TotalRate = 200 // 总费率(千分之200)= 第三方平台费+京西品牌费+京西服务费,现阶段都是合计200‰
|
||||
MaxFreightMoneyFromJxByShop = 7 // 商家自送实际转美团/达达后由商家承担的运费金额上限
|
||||
)
|
||||
|
||||
// 处理正向订单结账信息
|
||||
func (c *OrderManager) SaveOrderFinancialInfo(order *model.OrderFinancial, operation string) (err error) {
|
||||
db := dao.GetDB()
|
||||
txDB, _ := dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil || err != nil {
|
||||
dao.Rollback(db, txDB)
|
||||
if r != nil {
|
||||
panic(r)
|
||||
}
|
||||
}
|
||||
}()
|
||||
if operation == partner.UpdatedPeration {
|
||||
// db := orm.NewOrm()
|
||||
err = utils.CallFuncLogError(func() error {
|
||||
_, err = dao.ExecuteSQL(db, "DELETE FROM order_financial WHERE vendor_order_id = ? AND vendor_id = ?", order.VendorOrderID, order.VendorID)
|
||||
return err
|
||||
}, "SaveOrderFinancialInfo delete order_financial, orderID:%s", order.VendorOrderID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = utils.CallFuncLogError(func() error {
|
||||
_, err = dao.ExecuteSQL(db, "DELETE FROM order_sku_financial WHERE vendor_order_id = ? AND vendor_id = ? AND is_afs_order = 0", order.VendorOrderID, order.VendorID)
|
||||
return err
|
||||
}, "SaveOrderFinancialInfo delete order_sku_financial, orderID:%s", order.VendorOrderID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = utils.CallFuncLogError(func() error {
|
||||
_, err = dao.ExecuteSQL(db, "DELETE FROM order_discount_financial WHERE vendor_order_id = ? AND vendor_id = ?", order.VendorOrderID, order.VendorID)
|
||||
return err
|
||||
}, "SaveOrderFinancialInfo delete order_discount_financial, orderID:%s", order.VendorOrderID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
for _, activity := range order.Discounts {
|
||||
if err = dao.CreateEntity(db, activity); err != nil {
|
||||
if !dao.IsDuplicateError(err) {
|
||||
return err
|
||||
}
|
||||
dao.Rollback(db, txDB)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
order.ShopMoneyByCal = order.SalePriceMoney - order.TotalDiscountMoney - order.PointsDeductionMoney + order.PmFreightDiscountMoney - order.DistanceFreightMoney - order.FreightTipsMoney - order.DonationMoney + order.SelfDeliveryDiscountMoney + order.PmSubsidyMoney + order.SkuBoxMoney + order.BoxMoney - order.PmMoney
|
||||
order.JxPmMoney = utils.Float64TwoInt64(float64(order.ShopMoney+order.PmMoney)*TotalRate/1000) - order.PmMoney // 京西平台费 = 总金额*20%-第三方平台费
|
||||
if order.JxPmMoney < 0 { // 如果算出京西平台费为负数,则置0
|
||||
order.JxPmMoney = 0
|
||||
}
|
||||
|
||||
order.JxShopMoney = order.ShopMoney - order.JxPmMoney + order.JxSubsidyMoney - order.JxFreightMoneyByShop
|
||||
// 订单结算金额拆分计算,拆分到单条sku
|
||||
// 先获取订单主体优惠金额
|
||||
platOrderGoodsDiscountMoney := order.PmSubsidyMoney - order.PmSkuSubsidyMoney + order.SelfDeliveryDiscountMoney
|
||||
// 结算平台扣除项汇总---平台佣金,商家设置运费减免,远距离费,小费,公益捐款、、、、
|
||||
deductionsByPm := order.FreightDiscountMoney + order.DistanceFreightMoney + order.FreightTipsMoney + order.DonationMoney + order.PmMoney
|
||||
// 结算京西扣除项汇总---京西佣金,京西配送运费
|
||||
deductionsByJx := order.JxPmMoney + order.JxFreightMoneyByShop
|
||||
for _, sku := range order.Skus[1:] {
|
||||
// 用户支付菜品金额,用户为这一条sku支付的菜品金额
|
||||
sku.UserMoney = utils.Float64TwoInt64(float64(order.SalePriceMoney-order.DiscountMoney-order.PointsDeductionMoney+order.BoxMoney+order.SkuBoxMoney) * float64(sku.SalePrice*int64(sku.Count)+sku.SkuBoxMoney) / float64(order.SalePriceMoney+order.SkuBoxMoney)) // 林峰确认,比如49-2满减,算餐盒费满49元,不算餐盒费不足49元,是可以参加满减活动的,那么餐盒费也应该和商品金额一起进行折算
|
||||
order.Skus[0].UserMoney += sku.UserMoney
|
||||
// 计算平台订单主体补贴拆分到单条sku的金额 + sku.PmSubsidyMoneyForSku
|
||||
sku.PmSubsidyMoney = sku.PmSkuSubsidyMoney + utils.Float64TwoInt64(float64(platOrderGoodsDiscountMoney*sku.SalePrice*int64(sku.Count)+sku.SkuBoxMoney)/float64(order.SalePriceMoney+order.SkuBoxMoney))
|
||||
order.Skus[0].PmSubsidyMoney += sku.PmSubsidyMoney
|
||||
// 计算京西满减补贴拆分到单条sku的金额 + sku.JxSubsidyMoneyForSku
|
||||
sku.JxSubsidyMoney = sku.JxSkuSubsidyMoney + utils.Float64TwoInt64(float64(order.JxSubsidyMoney-order.PmSkuSubsidyMoney)*float64(sku.SalePrice*int64(sku.Count)+sku.SkuBoxMoney)/float64(order.SalePriceMoney+order.SkuBoxMoney))
|
||||
order.Skus[0].JxSubsidyMoney += sku.JxSubsidyMoney
|
||||
// 计算单条sku需要承担的平台扣费金额
|
||||
sku.PmDeductionsMoney = utils.Float64TwoInt64(float64(deductionsByPm) * (float64(sku.UserMoney + sku.PmSubsidyMoney)) / (float64(order.SalePriceMoney + order.BoxMoney + order.SkuBoxMoney - order.DiscountMoney - order.PointsDeductionMoney + order.PmSubsidyMoney)))
|
||||
order.Skus[0].PmDeductionsMoney += sku.PmDeductionsMoney
|
||||
// 计算单条sku平台应该结算给京西的金额
|
||||
sku.ShopMoneyByCal = sku.UserMoney + sku.PmSubsidyMoney - sku.PmDeductionsMoney
|
||||
order.Skus[0].ShopMoneyByCal += sku.ShopMoneyByCal
|
||||
// j计算单条sku需要承担的京西扣费金额
|
||||
sku.JxDeductionsMoney = utils.Float64TwoInt64(float64(deductionsByJx*sku.ShopMoneyByCal) / float64(order.ShopMoney))
|
||||
order.Skus[0].JxDeductionsMoney += sku.JxDeductionsMoney
|
||||
// 计算单条sku京西应该结算给商家的金额
|
||||
sku.JxShopMoney = sku.ShopMoneyByCal + sku.JxSubsidyMoney - sku.JxDeductionsMoney
|
||||
order.Skus[0].JxShopMoney += sku.JxShopMoney
|
||||
if sku.SkuID >= math.MaxInt32 {
|
||||
sku.SkuID = sku.JxSkuID
|
||||
}
|
||||
if err = dao.CreateEntity(db, sku); err != nil {
|
||||
if !dao.IsDuplicateError(err) {
|
||||
return err
|
||||
}
|
||||
dao.Rollback(db, txDB)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
if len(order.Skus) > 0 {
|
||||
sku := order.Skus[0]
|
||||
if sku.SkuID > math.MaxInt32 {
|
||||
sku.SkuID = sku.JxSkuID
|
||||
}
|
||||
sku.UserMoney = order.SalePriceMoney - order.DiscountMoney - sku.UserMoney
|
||||
sku.PmSubsidyMoney = platOrderGoodsDiscountMoney + order.SelfDeliveryDiscountMoney - sku.PmSubsidyMoney
|
||||
sku.JxSubsidyMoney = order.JxSubsidyMoney - sku.JxSubsidyMoney
|
||||
sku.PmDeductionsMoney = deductionsByPm - sku.PmDeductionsMoney
|
||||
sku.ShopMoneyByCal = order.ShopMoney - sku.ShopMoneyByCal
|
||||
sku.JxDeductionsMoney = deductionsByJx - sku.JxDeductionsMoney
|
||||
sku.JxShopMoney = order.JxShopMoney - sku.JxShopMoney
|
||||
if err = dao.CreateEntity(db, sku); err != nil {
|
||||
if !dao.IsDuplicateError(err) {
|
||||
return err
|
||||
}
|
||||
dao.Rollback(db, txDB)
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
globals.SugarLogger.Warnf("On SaveOrderSkuFinancialInfo order.VendorOrderID:%s err: order have no sku", order.VendorOrderID)
|
||||
}
|
||||
// 加上京西对单条sku的补贴,再存数据库
|
||||
order.JxSubsidyMoney += order.JxSkuSubsidyMoney
|
||||
if err = dao.CreateEntity(db, order); err != nil {
|
||||
if !dao.IsDuplicateError(err) {
|
||||
return err
|
||||
}
|
||||
dao.Rollback(db, txDB)
|
||||
return nil
|
||||
}
|
||||
dao.Commit(db, txDB)
|
||||
return err
|
||||
}
|
||||
|
||||
// 处理售后订单结账信息
|
||||
func (c *OrderManager) SaveAfsOrderFinancialInfo(afsOrder *model.AfsOrder) (err error) {
|
||||
db := dao.GetDB()
|
||||
txDB, _ := dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil || err != nil {
|
||||
dao.Rollback(db, txDB)
|
||||
if r != nil {
|
||||
panic(r)
|
||||
}
|
||||
}
|
||||
}()
|
||||
// 平台结算扣除汇总--平台补贴,售后产生运费,平台收包装费,同城运费、、、
|
||||
deductionsByPm := afsOrder.PmSubsidyMoney + afsOrder.AfsFreightMoney + afsOrder.BoxMoney + afsOrder.TongchengFreightMoney
|
||||
afsOrder.RefundMoneyByCal = afsOrder.SkuUserMoney + afsOrder.FreightUserMoney + deductionsByPm - afsOrder.PmRefundMoney
|
||||
// order.TotalMoney += order.SkuJxMoney // 退款单京西补贴部分先不作计算
|
||||
if err = dao.CreateEntity(db, afsOrder); err != nil {
|
||||
if !dao.IsDuplicateError(err) {
|
||||
return err
|
||||
}
|
||||
dao.Rollback(db, txDB)
|
||||
return nil
|
||||
}
|
||||
|
||||
// 京西结算扣除汇总,先不作计算,计算单条sku最终扣款金额(+该条sku承担的平台结算扣除金额)
|
||||
for _, orderSku := range afsOrder.Skus[1:] {
|
||||
orderSku.RefundMoneyByCal = orderSku.PmSkuSubsidyMoney +
|
||||
utils.Float64TwoInt64(float64(afsOrder.RefundMoneyByCal-afsOrder.PmSkuSubsidyMoney)*float64(orderSku.UserMoney+orderSku.PmSubsidyMoney-orderSku.PmSkuSubsidyMoney)/float64(afsOrder.SkuUserMoney+afsOrder.PmSubsidyMoney-afsOrder.PmSkuSubsidyMoney))
|
||||
afsOrder.Skus[0].RefundMoneyByCal += orderSku.RefundMoneyByCal
|
||||
if err = dao.CreateEntity(db, orderSku); err != nil {
|
||||
if !dao.IsDuplicateError(err) {
|
||||
return err
|
||||
}
|
||||
dao.Rollback(db, txDB)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
if len(afsOrder.Skus) > 0 {
|
||||
orderSku := afsOrder.Skus[0]
|
||||
orderSku.RefundMoneyByCal = afsOrder.RefundMoneyByCal - orderSku.RefundMoneyByCal
|
||||
if err = dao.CreateEntity(db, orderSku); err != nil {
|
||||
if !dao.IsDuplicateError(err) {
|
||||
globals.SugarLogger.Warnf("On SaveAfsOrderFinancialInfo afsOrder.AfsOrderID:%s err: SaveAfsOrderSku is err", afsOrder.AfsOrderID)
|
||||
return err
|
||||
}
|
||||
dao.Rollback(db, txDB)
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
globals.SugarLogger.Warnf("On SaveAfsOrderFinancialInfo afsOrder.AfsOrderID:%s err: afsOrder have no sku", afsOrder.AfsOrderID)
|
||||
}
|
||||
dao.Commit(db, txDB)
|
||||
return err
|
||||
}
|
||||
|
||||
// 转自送实际使用美团/达达配送,调用此方法
|
||||
func (c *OrderManager) UpdataOrderFinancialInfo(orderFinancial *model.OrderFinancial, wayBill *model.Waybill) (err error) {
|
||||
// 通过本地数据库去取是否转美团/达达,并计算运费,写在上级调用函数里面传递过来
|
||||
//wayBill, err2 := partner.CurOrderManager.LoadWaybill(orderFinancial.VendorOrderID, orderFinancial.VendorID)
|
||||
//if err = err2; err == nil {
|
||||
// orderFinancial.JxFreightMoney = wayBill.DesiredFee
|
||||
//}
|
||||
db := dao.GetDB()
|
||||
txDB, _ := dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil || err != nil {
|
||||
dao.Rollback(db, txDB)
|
||||
if r != nil {
|
||||
panic(r)
|
||||
}
|
||||
}
|
||||
}()
|
||||
orderFinancial.JxFreightMoney = wayBill.DesiredFee
|
||||
if (orderFinancial.JxFreightMoney - orderFinancial.SelfDeliveryDiscountMoney) > MaxFreightMoneyFromJxByShop {
|
||||
orderFinancial.JxFreightMoneyByShop = orderFinancial.SelfDeliveryDiscountMoney + MaxFreightMoneyFromJxByShop
|
||||
} else if (orderFinancial.JxFreightMoney - orderFinancial.SelfDeliveryDiscountMoney) < 0 {
|
||||
orderFinancial.JxFreightMoneyByShop = orderFinancial.SelfDeliveryDiscountMoney
|
||||
} else {
|
||||
orderFinancial.JxFreightMoneyByShop = orderFinancial.JxFreightMoney
|
||||
}
|
||||
orderFinancial.JxShopMoney -= orderFinancial.JxFreightMoneyByShop
|
||||
// orderFinancial.JxFreightMoneyByShop 的改变直接影响到单条sku的京西结算金额的改变
|
||||
jxDecMoney := orderFinancial.JxFreightMoneyByShop
|
||||
for _, sku := range orderFinancial.Skus[1:] {
|
||||
// 重新计算单条sku京西应该结算的金额
|
||||
skuJxDecMoney := utils.Float64TwoInt64(float64(jxDecMoney*sku.SalePrice*int64(sku.Count)+sku.SkuBoxMoney) / float64(orderFinancial.SalePriceMoney+orderFinancial.SkuBoxMoney))
|
||||
sku.JxDeductionsMoney += skuJxDecMoney
|
||||
sku.JxShopMoney -= skuJxDecMoney
|
||||
jxDecMoney -= skuJxDecMoney
|
||||
if _, err = dao.UpdateEntity(db, sku); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if len(orderFinancial.Skus) > 0 {
|
||||
sku := orderFinancial.Skus[0]
|
||||
sku.JxDeductionsMoney += jxDecMoney
|
||||
sku.JxShopMoney -= jxDecMoney
|
||||
if _, err = dao.UpdateEntity(db, sku); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err = dao.CreateEntity(db, orderFinancial); err != nil {
|
||||
return err
|
||||
}
|
||||
dao.Commit(db, txDB)
|
||||
// orderFinancial 和 OrderSkuFinancial 数据计算完毕,准备进行更新
|
||||
return err
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,447 +0,0 @@
|
||||
package orderman
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxcallback/scheduler"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"github.com/astaxie/beego/client/orm"
|
||||
)
|
||||
|
||||
func (c *OrderManager) LoadAfsOrder(vendorAfsOrderID string, vendorID int) (afsOrder *model.AfsOrder, err error) {
|
||||
return c.loadAfsOrder(dao.GetDB(), vendorAfsOrderID, vendorID)
|
||||
}
|
||||
|
||||
func (c *OrderManager) loadAfsOrder(db *dao.DaoDB, vendorAfsOrderID string, vendorID int) (afsOrder *model.AfsOrder, err error) {
|
||||
afsOrder = &model.AfsOrder{
|
||||
AfsOrderID: vendorAfsOrderID,
|
||||
VendorID: vendorID,
|
||||
}
|
||||
if err = dao.GetEntity(db, afsOrder, "AfsOrderID", "VendorID"); err != nil {
|
||||
afsOrder = nil
|
||||
}
|
||||
return afsOrder, err
|
||||
}
|
||||
|
||||
func (c *OrderManager) OnAfsOrderAdjust(afsOrder *model.AfsOrder, orderStatus *model.OrderStatus) (err error) {
|
||||
return c.onAfsOrderNew(afsOrder, orderStatus, true)
|
||||
}
|
||||
|
||||
func (c *OrderManager) OnAfsOrderNew(afsOrder *model.AfsOrder, orderStatus *model.OrderStatus) (err error) {
|
||||
return c.onAfsOrderNew(afsOrder, orderStatus, false)
|
||||
}
|
||||
|
||||
func (c *OrderManager) onAfsOrderNew(afsOrder *model.AfsOrder, orderStatus *model.OrderStatus, isAdjust bool) (err error) {
|
||||
db := dao.GetDB()
|
||||
c.setAfsOrderID(db, orderStatus)
|
||||
if afsOrder.AfsOrderID == "" {
|
||||
afsOrder.AfsOrderID = orderStatus.VendorOrderID
|
||||
}
|
||||
if afsOrder.VendorStatus == "" {
|
||||
afsOrder.VendorStatus = orderStatus.VendorStatus
|
||||
}
|
||||
if afsOrder.Status == model.OrderStatusUnknown {
|
||||
afsOrder.Status = orderStatus.Status
|
||||
}
|
||||
if order, _ := c.LoadOrder(afsOrder.VendorOrderID, afsOrder.VendorID); order != nil {
|
||||
if order.ConsigneeMobile2 == "" {
|
||||
if handler := partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID); handler != nil {
|
||||
if order2, _ := handler.GetOrder(order.VendorOrgCode, order.VendorOrderID, order.VendorStoreID); order2 != nil && order.ConsigneeMobile != order2.ConsigneeMobile {
|
||||
order.ConsigneeMobile = order2.ConsigneeMobile
|
||||
c.UpdateOrderFields(order, []string{"ConsigneeMobile"})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//
|
||||
txDB, _ := dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil || err != nil {
|
||||
dao.Rollback(db, txDB)
|
||||
panic(r)
|
||||
}
|
||||
}()
|
||||
|
||||
isDuplicated, err := addOrderOrWaybillStatus(orderStatus, db)
|
||||
if err != nil || (isDuplicated && orderStatus.VendorID != model.VendorIDJX) {
|
||||
if err == nil {
|
||||
dao.Commit(db, txDB)
|
||||
}
|
||||
return err
|
||||
}
|
||||
existAfsOrder, err := c.loadAfsOrder(db, afsOrder.AfsOrderID, afsOrder.VendorID)
|
||||
if err != nil {
|
||||
if !dao.IsNoRowsError(err) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if existAfsOrder != nil {
|
||||
if existAfsOrder.Status < model.AfsOrderStatusFinished {
|
||||
// todo 可能导致状态回绕
|
||||
existAfsOrder.Status = afsOrder.Status
|
||||
existAfsOrder.VendorStatus = afsOrder.VendorStatus
|
||||
if _, err = dao.UpdateEntity(db, existAfsOrder, "Status", "VendorStatus", "AfsFinishedAt"); err != nil {
|
||||
return err
|
||||
}
|
||||
afsOrder = existAfsOrder
|
||||
}
|
||||
|
||||
} else {
|
||||
// 全退都要先全删除再建
|
||||
if afsOrder.RefundType == model.AfsTypeFullRefund {
|
||||
isAdjust = true
|
||||
}
|
||||
if err = c.SaveAfsOrder(db, afsOrder, isAdjust); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
dao.Commit(db, txDB)
|
||||
scheduler.CurrentScheduler.OnAfsOrderNew(afsOrder, false)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *OrderManager) SaveAfsOrder(db *dao.DaoDB, afsOrder *model.AfsOrder, isDeleteFirst bool) (err error) {
|
||||
if db == nil {
|
||||
db = dao.GetDB()
|
||||
}
|
||||
if err = c.updateAfsOrderOtherInfo(db, afsOrder); err != nil {
|
||||
return err
|
||||
}
|
||||
txDB, _ := dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil || err != nil {
|
||||
dao.Rollback(db, txDB)
|
||||
if r != nil {
|
||||
panic(r)
|
||||
}
|
||||
}
|
||||
}()
|
||||
if isDeleteFirst {
|
||||
err = utils.CallFuncLogError(func() error {
|
||||
_, err = dao.DeleteEntity(db, afsOrder, "VendorOrderID", "VendorID")
|
||||
return err
|
||||
}, "SaveAfsOrder delete AfsOrder, afsOrderID:%s", afsOrder.AfsOrderID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = utils.CallFuncLogError(func() error {
|
||||
_, err = dao.DeleteEntity(db, &model.OrderSkuFinancial{
|
||||
VendorOrderID: afsOrder.VendorOrderID,
|
||||
VendorID: afsOrder.VendorID,
|
||||
IsAfsOrder: 1,
|
||||
}, "VendorOrderID", "VendorID", "IsAfsOrder")
|
||||
return err
|
||||
}, "SaveAfsOrder delete OrderSkuFinancial, afsOrderID:%s", afsOrder.AfsOrderID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// 平台结算扣除汇总--平台补贴,售后产生运费,平台收包装费,同城运费、、、
|
||||
deductionsByPm := afsOrder.PmSubsidyMoney + afsOrder.AfsFreightMoney + afsOrder.BoxMoney + afsOrder.TongchengFreightMoney
|
||||
afsOrder.RefundMoneyByCal = afsOrder.SkuUserMoney + afsOrder.FreightUserMoney + deductionsByPm - afsOrder.PmRefundMoney
|
||||
// order.TotalMoney += order.SkuJxMoney // 退款单京西补贴部分先不作计算
|
||||
if err = dao.CreateEntity(db, afsOrder); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 京西结算扣除汇总,先不作计算,计算单条sku最终扣款金额(+该条sku承担的平台结算扣除金额)
|
||||
for _, orderSku := range afsOrder.Skus[1:] {
|
||||
orderSku.RefundMoneyByCal = orderSku.PmSkuSubsidyMoney +
|
||||
utils.Float64TwoInt64(float64(afsOrder.RefundMoneyByCal-afsOrder.PmSkuSubsidyMoney)*float64(orderSku.UserMoney+orderSku.PmSubsidyMoney-orderSku.PmSkuSubsidyMoney)/float64(afsOrder.SkuUserMoney+afsOrder.PmSubsidyMoney-afsOrder.PmSkuSubsidyMoney))
|
||||
afsOrder.Skus[0].RefundMoneyByCal += orderSku.RefundMoneyByCal
|
||||
if err = dao.CreateEntity(db, orderSku); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if len(afsOrder.Skus) > 0 {
|
||||
orderSku := afsOrder.Skus[0]
|
||||
orderSku.RefundMoneyByCal = afsOrder.RefundMoneyByCal - orderSku.RefundMoneyByCal
|
||||
if err = dao.CreateEntity(db, orderSku); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
globals.SugarLogger.Warnf("On SaveAfsOrder afsOrder.AfsOrderID:%s err: afsOrder have no sku", afsOrder.AfsOrderID)
|
||||
}
|
||||
dao.Commit(db, txDB)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *OrderManager) OnAfsOrderStatusChanged(orderStatus *model.OrderStatus) (err error) {
|
||||
db := dao.GetDB()
|
||||
c.setAfsOrderID(db, orderStatus)
|
||||
txDB, _ := dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
dao.Rollback(db, txDB)
|
||||
panic(r)
|
||||
}
|
||||
}()
|
||||
isDuplicated, afsOrder, err := c.addAfsOrderStatus(db, orderStatus)
|
||||
if err != nil || isDuplicated {
|
||||
if err == nil {
|
||||
dao.Commit(db, txDB)
|
||||
} else {
|
||||
dao.Rollback(db, txDB)
|
||||
}
|
||||
return err
|
||||
}
|
||||
dao.Commit(db, txDB)
|
||||
scheduler.CurrentScheduler.OnAfsOrderStatusChanged(afsOrder, orderStatus, false)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *OrderManager) addAfsOrderStatus(db *dao.DaoDB, orderStatus *model.OrderStatus) (isDuplicated bool, order *model.AfsOrder, err error) {
|
||||
if db == nil {
|
||||
db = dao.GetDB()
|
||||
}
|
||||
isDuplicated, err = addOrderOrWaybillStatus(orderStatus, db)
|
||||
//if err == nil && !isDuplicated && (orderStatus.Status != model.OrderStatusUnknown && orderStatus.Status != model.OrderStatusMsg) {
|
||||
if err == nil && (orderStatus.Status != model.OrderStatusUnknown && orderStatus.Status != model.OrderStatusMsg) {
|
||||
order = &model.AfsOrder{
|
||||
AfsOrderID: orderStatus.VendorOrderID,
|
||||
VendorID: orderStatus.VendorID,
|
||||
}
|
||||
if err = db.Db.ReadForUpdate(order, "AfsOrderID", "VendorID"); err == nil {
|
||||
if orderStatus.Status > model.OrderStatusUnknown { // todo 要求status不能回绕
|
||||
order.VendorStatus = orderStatus.VendorStatus
|
||||
order.Status = orderStatus.Status
|
||||
updateFields := []string{
|
||||
"VendorStatus",
|
||||
"Status",
|
||||
}
|
||||
if orderStatus.VendorID == model.VendorIDDD {
|
||||
order.Flag = 0
|
||||
if strings.Contains(orderStatus.VendorStatus, "cancel_refund_afsOrder") {
|
||||
order.Flag = 3
|
||||
}
|
||||
updateFields = append(updateFields, "Flag")
|
||||
}
|
||||
if model.IsAfsOrderFinalStatus(orderStatus.Status) || orderStatus.Status == model.AfsOrderStatusNew {
|
||||
order.AfsFinishedAt = orderStatus.StatusTime
|
||||
if utils.IsTimeZero(order.AfsFinishedAt) {
|
||||
order.AfsFinishedAt = time.Now()
|
||||
}
|
||||
updateFields = append(updateFields, "AfsFinishedAt")
|
||||
if handler := partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID); handler != nil {
|
||||
if orderAfsInfo, err := handler.GetOrderAfsInfo(nil, order.VendorOrderID, order.AfsOrderID); err == nil && orderAfsInfo.AfsTotalShopMoney != 0 {
|
||||
order.AfsTotalShopMoney = orderAfsInfo.AfsTotalShopMoney
|
||||
updateFields = append(updateFields, "AfsTotalShopMoney")
|
||||
}
|
||||
}
|
||||
}
|
||||
_, err = dao.UpdateEntity(db, order, updateFields...)
|
||||
//utils.CallFuncLogError(func() error {
|
||||
// _, err = dao.UpdateEntity(db, order, updateFields...)
|
||||
// return err
|
||||
//}, "addAfsOrderStatus update orderID:%s, status:%v", order.VendorOrderID, orderStatus)
|
||||
} else {
|
||||
isDuplicated = true
|
||||
}
|
||||
} else {
|
||||
// 这是发现有部分订单已经完成,但是没有完成时间影响到导出结果错误
|
||||
if model.IsAfsOrderFinalStatus(orderStatus.Status) || orderStatus.Status == model.AfsOrderStatusNew && order.VendorID == model.VendorIDMTWM {
|
||||
if afsOrderObj, _ := partner.CurOrderManager.LoadAfsOrder(orderStatus.VendorOrderID, orderStatus.VendorID); afsOrderObj != nil {
|
||||
afsOrderObj.AfsFinishedAt = time.Now()
|
||||
afsOrderObj.Status = orderStatus.Status
|
||||
dao.UpdateEntity(db, afsOrderObj, "AfsFinishedAt", "Status")
|
||||
}
|
||||
}
|
||||
if dao.IsNoRowsError(err) { // todo 消息错序
|
||||
err = nil
|
||||
} else {
|
||||
globals.SugarLogger.Warnf("addAfsOrderStatus orderID:%s read failed with error:%v", order.VendorOrderID, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return isDuplicated, order, err
|
||||
}
|
||||
|
||||
func (c *OrderManager) updateAfsOrderSkuOtherInfo(db *dao.DaoDB, order *model.AfsOrder) (err error) {
|
||||
jxStoreID := jxutils.GetSaleStoreIDFromAfsOrder(order)
|
||||
opNumStr := "2"
|
||||
if jxStoreID == 0 {
|
||||
return nil
|
||||
}
|
||||
orderSkus := order.Skus
|
||||
var vendorSkuIDs []string
|
||||
skuIDMap := make(map[int]int)
|
||||
for _, v := range orderSkus {
|
||||
if v.VendorSkuID != "" {
|
||||
vendorSkuIDs = append(vendorSkuIDs, v.VendorSkuID)
|
||||
}
|
||||
|
||||
if skuID := jxutils.GetSkuIDFromOrderSkuFinancial(v); skuID > 0 {
|
||||
skuIDMap[skuID] = 1
|
||||
}
|
||||
}
|
||||
if len(vendorSkuIDs) > 0 {
|
||||
var vendorStoreID string
|
||||
if order.VendorID == model.VendorIDJDShop {
|
||||
vendorStoreID = model.JdShopMainVendorStoreID
|
||||
} else {
|
||||
vendorStoreID = order.VendorStoreID
|
||||
}
|
||||
l, err := dao.GetStoreSkuPriceAndWeight(db, vendorStoreID, order.VendorID, vendorSkuIDs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
skumapper := storeSkuPriceAndWeight2Map(l)
|
||||
|
||||
var actStoreSkuMap *jxutils.ActStoreSkuMap
|
||||
if len(skuIDMap) > 0 {
|
||||
if order2, err2 := c.LoadOrder(order.VendorOrderID, order.VendorID); err2 == nil {
|
||||
actStoreSkuList, err := dao.GetEffectiveActStoreSkuInfo(db, 0, []int{order.VendorID}, model.ActTypeAll, []int{jxStoreID}, jxutils.IntMap2List(skuIDMap), order2.OrderCreatedAt, order2.OrderCreatedAt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
actStoreSkuMap = jxutils.NewActStoreSkuMap(actStoreSkuList, false)
|
||||
}
|
||||
}
|
||||
for _, v := range orderSkus {
|
||||
v.AfsOrderID = order.AfsOrderID
|
||||
v.VendorID = order.VendorID
|
||||
v.VendorOrderID = order.VendorOrderID
|
||||
v.IsAfsOrder = 1
|
||||
v.VendorStoreID = order.VendorStoreID
|
||||
v.StoreID = order.StoreID
|
||||
v.JxStoreID = jxStoreID
|
||||
|
||||
intVendorSkuID := utils.Str2Int64WithDefault(v.VendorSkuID, 0)
|
||||
if intVendorSkuID != 0 && v.VendorSkuID != "-70000" { // todo hard code
|
||||
skuBindInfo := skumapper[v.VendorSkuID]
|
||||
if skuBindInfo == nil {
|
||||
globals.SugarLogger.Infof("updateAfsOrderSkuOtherInfo [运营%s]%s订单sku找不到门店价格(或商品映射),orderID:%s, StoreID:%d, VendorSkuID:%s, sku:%v", opNumStr, model.VendorChineseNames[order.VendorID], order.VendorOrderID, jxStoreID, v.VendorSkuID, v)
|
||||
} else {
|
||||
v.JxSkuID = skuBindInfo.SkuID
|
||||
v.ShopPrice = int64(skuBindInfo.Price)
|
||||
}
|
||||
}
|
||||
if actStoreSkuMap != nil {
|
||||
if skuID := jxutils.GetSkuIDFromOrderSkuFinancial(v); skuID > 0 && v.StoreSubName != "" {
|
||||
if actStoreSku := actStoreSkuMap.GetActStoreSku(jxStoreID, skuID, order.VendorID); actStoreSku != nil {
|
||||
v.StoreSubID = actStoreSku.ActID
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *OrderManager) updateAfsOrderOtherInfo(db *dao.DaoDB, afsOrder *model.AfsOrder) (err error) {
|
||||
if afsOrder.VendorStoreID != "" {
|
||||
if storeDetail, err := dao.GetStoreDetailByVendorStoreID(db, afsOrder.VendorStoreID, 0, ""); err == nil {
|
||||
afsOrder.JxStoreID = storeDetail.Store.ID
|
||||
}
|
||||
}
|
||||
order, err2 := c.LoadOrder(afsOrder.VendorOrderID, afsOrder.VendorID)
|
||||
if afsOrder.StoreID == 0 && afsOrder.JxStoreID == 0 {
|
||||
if err2 == nil {
|
||||
afsOrder.JxStoreID = order.JxStoreID
|
||||
if afsOrder.StoreID == 0 {
|
||||
afsOrder.StoreID = order.StoreID
|
||||
}
|
||||
if afsOrder.VendorStoreID == "" {
|
||||
afsOrder.VendorStoreID = order.VendorStoreID
|
||||
}
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
if handler := partner.GetPurchaseOrderHandlerFromVendorID(afsOrder.VendorID); handler != nil {
|
||||
if orderAfsInfo, err := handler.GetOrderAfsInfo(nil, afsOrder.VendorOrderID, afsOrder.AfsOrderID); err == nil && orderAfsInfo.AfsTotalShopMoney != 0 {
|
||||
afsOrder.AfsTotalShopMoney = orderAfsInfo.AfsTotalShopMoney
|
||||
}
|
||||
}
|
||||
if err = c.updateAfsOrderSkuOtherInfo(db, afsOrder); err == nil {
|
||||
jxutils.RefreshAfsOrderSkuRelated(afsOrder)
|
||||
if afsOrder.RefundType == model.AfsTypeFullRefund && afsOrder.VendorID == model.VendorIDJX && order.DeliveryType != model.OrderDeliveryTypeSelfTake {
|
||||
afsOrder.SkuUserMoney = order.ActualPayPrice
|
||||
}
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *OrderManager) UpdateAfsOrderFields(afsOrder *model.AfsOrder, fieldList []string) (err error) {
|
||||
db := orm.NewOrm()
|
||||
utils.CallFuncLogError(func() error {
|
||||
_, err = db.Update(afsOrder, fieldList...)
|
||||
return err
|
||||
}, "UpdateAfsOrderFields orderID:%s failed with error:%v", afsOrder.VendorOrderID, err)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *OrderManager) setAfsOrderID(db *dao.DaoDB, orderStatus *model.OrderStatus) {
|
||||
if dao.IsVendorThingIDEmpty(orderStatus.VendorOrderID) {
|
||||
index := 1
|
||||
if afsOrderList, err2 := dao.GetAfsOrders(db, orderStatus.RefVendorID, orderStatus.RefVendorOrderID, ""); err2 == nil {
|
||||
if len(afsOrderList) > 0 {
|
||||
list := strings.Split(afsOrderList[0].AfsOrderID, "-")
|
||||
if len(list) > 1 {
|
||||
index = int(utils.Str2Int64WithDefault(list[1], 0))
|
||||
//if afsOrderList[0].Status >= model.AfsOrderStatusFinished {
|
||||
index++
|
||||
//}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
globals.SugarLogger.Warnf("setAfsOrderID err2:%v", err2)
|
||||
}
|
||||
orderStatus.VendorOrderID = composeAfsOrderID(orderStatus.RefVendorOrderID, index)
|
||||
}
|
||||
}
|
||||
|
||||
func composeAfsOrderID(vendorOrderID string, index int) (afsOrderID string) {
|
||||
return strings.Join([]string{
|
||||
vendorOrderID,
|
||||
utils.Int2Str(index),
|
||||
}, "-")
|
||||
}
|
||||
|
||||
func (c *OrderManager) CreateAfsOrderFromOrder(vendorOrderID string, vendorID int) (afsOrder *model.AfsOrder, err error) {
|
||||
order, err := c.LoadOrder(vendorOrderID, vendorID)
|
||||
if err == nil {
|
||||
afsOrder = &model.AfsOrder{
|
||||
VendorID: vendorID,
|
||||
VendorOrderID: vendorOrderID,
|
||||
JxStoreID: order.JxStoreID,
|
||||
VendorStoreID: order.VendorStoreID,
|
||||
StoreID: order.StoreID,
|
||||
VendorOrgCode: order.VendorOrgCode,
|
||||
}
|
||||
} else {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, sku := range order.Skus {
|
||||
orderSkuFinancial := &model.OrderSkuFinancial{
|
||||
VendorID: sku.VendorID,
|
||||
VendorOrderID: sku.VendorOrderID,
|
||||
VendorSubOrderID: sku.VendorSubOrderID,
|
||||
// OrderFinancialID: sku.VendorOrderID,
|
||||
// ConfirmTime: afsOrder.AfsCreateAt,
|
||||
VendorStoreID: afsOrder.VendorStoreID,
|
||||
StoreID: afsOrder.StoreID,
|
||||
JxStoreID: afsOrder.JxStoreID,
|
||||
VendorSkuID: sku.VendorSkuID,
|
||||
SkuID: sku.SkuID,
|
||||
PromotionType: sku.PromotionType,
|
||||
Name: sku.SkuName,
|
||||
ShopPrice: sku.ShopPrice,
|
||||
SalePrice: sku.SalePrice,
|
||||
Count: sku.Count,
|
||||
// UserMoney: sku.UserMoney,
|
||||
// PmSubsidyMoney: sku.PmSubsidyMoney,
|
||||
IsAfsOrder: 1,
|
||||
}
|
||||
afsOrder.Skus = append(afsOrder.Skus, orderSkuFinancial)
|
||||
}
|
||||
return afsOrder, nil
|
||||
}
|
||||
@@ -1,223 +0,0 @@
|
||||
package orderman
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"git.rosy.net.cn/jx-callback/business/jxstore/cms"
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/weixinmsg"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/model/legacymodel"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
)
|
||||
|
||||
type tReplyConfig struct {
|
||||
DelayGapBegin int `json:"delayGapBegin"`
|
||||
DelayGapEnd int `json:"delayGapEnd"`
|
||||
Comments []string `json:"comments"`
|
||||
}
|
||||
|
||||
var (
|
||||
//replyConfig = map[int]*tReplyConfig{
|
||||
// 1: &tReplyConfig{
|
||||
// delayGapBegin: COMMENTS_SCORE_ONE_ORTWO_BEGIN_DELAY_TIME,
|
||||
// delayGapEnd: COMMENTS_SCORE_ONE_ORTWO_END_DELAY_TIME,
|
||||
// comments: []string{
|
||||
// "非常抱歉让您没有得到十分满意的购物体验,我们会及时与您联系进行确认并解决问题!",
|
||||
// },
|
||||
// },
|
||||
// 3: &tReplyConfig{
|
||||
// delayGapBegin: COMMENTS_SCORE_THREE_BEGIN_DELAY_TIME,
|
||||
// delayGapEnd: COMMENTS_SCORE_THREE_END_DELAY_TIME,
|
||||
// comments: []string{
|
||||
// "感谢您对我们的肯定,祝您生活愉快!欢迎再次光临,谢谢!",
|
||||
// fmt.Sprintf("感谢您对%s的关照,我们会更加精益求精。", globals.StoreName),
|
||||
// "感谢您的光临,您的支持是我们前进的动力!",
|
||||
// },
|
||||
// },
|
||||
// 4: &tReplyConfig{
|
||||
// delayGapBegin: COMMENTS_SCORE_FOUR_ORFIVE_BEGIN_DELAY_TIME,
|
||||
// delayGapEnd: COMMENTS_SCORE_FOUR_ORFIVE_END_DELAY_TIME,
|
||||
// comments: []string{
|
||||
// "感谢您的信赖!我们会不断提升菜品质量以及优质的服务,期待与您的再次相遇!",
|
||||
// "感谢您的支持,愿您天天好心情!",
|
||||
// "感谢您的认可!您的支持是我们前进的动力。",
|
||||
// "感谢您的肯定与支持!我们会坚持把最好的服务带给您,期待和您的再次相遇!",
|
||||
// },
|
||||
// },
|
||||
//}
|
||||
)
|
||||
|
||||
func (c *OrderManager) OnOrderComments(orderCommentList []*model.OrderComment) (err error) {
|
||||
db := dao.GetDB()
|
||||
for _, orderComment := range orderCommentList {
|
||||
comment2 := &legacymodel.JxBadComments{
|
||||
OrderId: orderComment.VendorOrderID,
|
||||
}
|
||||
err = dao.GetEntity(db, comment2, "OrderId")
|
||||
if err == nil || dao.IsNoRowsError(err) {
|
||||
isNewComment := false
|
||||
if dao.IsNoRowsError(err) {
|
||||
err = nil
|
||||
isNewComment = true
|
||||
if orderComment.IsReplied == 0 && time.Now().Sub(orderComment.CommentCreatedAt) < time.Duration(orderComment.ModifyDuration)*time.Hour {
|
||||
if storeDetail, err2 := dao.GetStoreDetail(db, orderComment.StoreID, orderComment.VendorID, ""); err2 == nil {
|
||||
if storeDetail.AutoReplyType == model.AutoReplyAll || orderComment.Score > cms.JX_BAD_COMMENTS_MAX_LEVEL && storeDetail.AutoReplyType == model.AutoReplyGoodComment {
|
||||
c.replyOrderComment(storeDetail.VendorOrgCode, orderComment)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if isNewComment /*&& orderComment.Score <= JX_BAD_COMMENTS_MAX_LEVEL*/ || !isNewComment && orderComment.Score > cms.JX_BAD_COMMENTS_MAX_LEVEL { // 如果是直接非差评,或补评仍然是差评,忽略
|
||||
if isNewComment {
|
||||
comment2.Createtime = utils.Time2Str(orderComment.CommentCreatedAt)
|
||||
comment2.Score = int(orderComment.Score)
|
||||
comment2.Scorecontent = orderComment.Content
|
||||
comment2.Vendertags = orderComment.TagList
|
||||
comment2.Msg = orderComment.OriginalMsg
|
||||
|
||||
comment2.Status = cms.COMMENT_NOT_RESOLVED
|
||||
comment2.OrderFlag = utils.Int2Str(orderComment.VendorID)
|
||||
comment2.Maxmodifytime = int(orderComment.ModifyDuration)
|
||||
comment2.VendorOrderId = orderComment.VendorOrderID2
|
||||
|
||||
var order *model.GoodsOrder
|
||||
if orderComment.VendorID == model.VendorIDMTWM && orderComment.VendorOrderID2 != "" {
|
||||
order, _ = partner.CurOrderManager.LoadOrder(orderComment.VendorOrderID2, orderComment.VendorID)
|
||||
} else {
|
||||
order, _ = partner.CurOrderManager.LoadOrder(orderComment.VendorOrderID, orderComment.VendorID)
|
||||
}
|
||||
|
||||
if order != nil {
|
||||
orderComment.StoreID = jxutils.GetSaleStoreIDFromOrder(order)
|
||||
if order.ConsigneeMobile2 != "" {
|
||||
orderComment.ConsigneeMobile = order.ConsigneeMobile2
|
||||
} else {
|
||||
if handler := partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID); handler != nil {
|
||||
if order2, _ := handler.GetOrder(order.VendorOrgCode, order.VendorOrderID, order.VendorStoreID); order2 != nil && order.ConsigneeMobile != order2.ConsigneeMobile {
|
||||
order.ConsigneeMobile = order2.ConsigneeMobile
|
||||
partner.CurOrderManager.UpdateOrderFields(order, []string{"ConsigneeMobile"})
|
||||
}
|
||||
}
|
||||
orderComment.ConsigneeMobile = order.ConsigneeMobile
|
||||
}
|
||||
} else {
|
||||
if storeDetail, err := dao.GetStoreDetailByVendorStoreID(db, orderComment.VendorStoreID, orderComment.VendorID, ""); err == nil {
|
||||
orderComment.StoreID = storeDetail.ID
|
||||
}
|
||||
}
|
||||
if orderComment.StoreID > 0 {
|
||||
comment2.Jxstoreid = utils.Int2Str(orderComment.StoreID)
|
||||
}
|
||||
comment2.Userphone = orderComment.ConsigneeMobile
|
||||
if comment2.Jxstoreid != "" && orderComment.Score <= cms.JX_MIDDLE_COMMENTS_MAX_LEVEL && time.Now().Sub(orderComment.CommentCreatedAt) < cms.MAX_REAPLY_TIME && order != nil {
|
||||
comment2.LastPushTime = utils.Time2Str(time.Now())
|
||||
comment2.PushNo = 1
|
||||
weixinmsg.PushJDBadCommentToWeiXin(comment2, orderComment.Score <= cms.JX_BAD_COMMENTS_MAX_LEVEL, order)
|
||||
}
|
||||
} else { // 修改评价,高于JX_BAD_COMMENTS_MAX_LEVEL
|
||||
//if orderComment.CommentCreatedAt.Sub(str2Time(comment2.Createtime)) == 0 ||
|
||||
// orderComment.CommentCreatedAt.Sub(str2Time(comment2.Updatetime)) == 0 {
|
||||
// comment2 = nil // 重复
|
||||
//} else {
|
||||
comment2.Updatetime = utils.Time2Str(orderComment.CommentCreatedAt)
|
||||
comment2.UpdatedMsg = orderComment.OriginalMsg
|
||||
comment2.UpdatedScore = int(orderComment.Score)
|
||||
comment2.UpdatedScorecontent = orderComment.Content
|
||||
comment2.UpdatedVendertags = orderComment.TagList
|
||||
comment2.Status = cms.COMMENT_RESOLVED
|
||||
comment2.VendorOrderId = orderComment.VendorOrderID2
|
||||
if comment2.Jxstoreid != "" && orderComment.Score <= cms.JX_MIDDLE_COMMENTS_MAX_LEVEL && time.Now().Sub(orderComment.CommentCreatedAt) < cms.MAX_REAPLY_TIME {
|
||||
comment2.LastPushTime = utils.Time2Str(time.Now())
|
||||
comment2.PushNo++
|
||||
|
||||
comment3 := *comment2
|
||||
comment3.Createtime = comment2.Updatetime
|
||||
comment3.Score = comment2.UpdatedScore
|
||||
comment3.Scorecontent = comment2.UpdatedScorecontent
|
||||
comment3.Vendertags = comment2.UpdatedVendertags
|
||||
|
||||
var order *model.GoodsOrder
|
||||
if orderComment.VendorID == model.VendorIDMTWM && orderComment.VendorOrderID2 != "" {
|
||||
order, _ = partner.CurOrderManager.LoadOrder(orderComment.VendorOrderID2, orderComment.VendorID)
|
||||
} else {
|
||||
order, _ = partner.CurOrderManager.LoadOrder(orderComment.VendorOrderID, orderComment.VendorID)
|
||||
}
|
||||
weixinmsg.PushJDBadCommentToWeiXin(&comment3, orderComment.Score <= cms.JX_BAD_COMMENTS_MAX_LEVEL, order)
|
||||
}
|
||||
//}
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
if comment2.OrderFlag == "1" {
|
||||
}
|
||||
if isNewComment {
|
||||
err = dao.CreateEntity(db, comment2)
|
||||
} else if comment2 != nil {
|
||||
_, err = dao.UpdateEntity(db, comment2)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if orderComment.VendorOrderID2 != "" {
|
||||
comment2.VendorOrderId = orderComment.VendorOrderID2
|
||||
_, err = dao.UpdateEntity(db, comment2)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
comment2.VendorOrderId = orderComment.VendorOrderID2
|
||||
_, err = dao.UpdateEntity(db, comment2, "VendorOrderId")
|
||||
}
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *OrderManager) replyOrderComment(vendorOrgCode string, orderComment *model.OrderComment) (err error) {
|
||||
score := int(orderComment.Score)
|
||||
if score <= 2 {
|
||||
score = 1
|
||||
} else if score >= 5 {
|
||||
score = 4
|
||||
}
|
||||
var config *tReplyConfig
|
||||
if configs, err := dao.QueryConfigs(dao.GetDB(), utils.Int2Str(score), model.ConfigTypeReply, ""); err == nil {
|
||||
json.Unmarshal([]byte(configs[0].Value), &config)
|
||||
}
|
||||
if config == nil {
|
||||
return
|
||||
}
|
||||
//config := replyConfig[score]
|
||||
delaySeconds := config.DelayGapBegin + rand.Intn(config.DelayGapEnd-config.DelayGapBegin)
|
||||
content := config.Comments[rand.Intn(len(config.Comments))]
|
||||
utils.AfterFuncWithRecover(time.Duration(delaySeconds)*time.Second, func() {
|
||||
if handler := partner.GetPurchaseOrderHandlerFromVendorID(orderComment.VendorID); handler != nil {
|
||||
if err = handler.ReplyOrderComment(jxcontext.AdminCtx, vendorOrgCode, orderComment, content); err != nil {
|
||||
globals.SugarLogger.Debugf("replyOrderComment orderID:%s, error:%v", orderComment.VendorOrderID, err)
|
||||
}
|
||||
} else {
|
||||
globals.SugarLogger.Warnf("replyOrderComment can not find handler orderID:%s", orderComment.VendorOrderID)
|
||||
}
|
||||
})
|
||||
// todo 这里直接延时,可以导致服务器重启时漏掉回复,但如果用管理任务,又会导致大量评价任务存在与任务列表中
|
||||
// task := tasksch.NewParallelTask(fmt.Sprintf("回复订单:%s评价", orderComment.VendorOrderID), nil, jxcontext.AdminCtx,
|
||||
// func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
// return retVal, err
|
||||
// }, []int{0})
|
||||
// tasksch.HandleTask(task, nil, true).Run()
|
||||
return err
|
||||
}
|
||||
|
||||
func str2Time(timeStr string) time.Time {
|
||||
if timeStr == "" {
|
||||
return utils.DefaultTimeValue
|
||||
}
|
||||
return utils.Str2Time(timeStr)
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
package orderman
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestSaveJdsOrders(t *testing.T) {
|
||||
type args struct {
|
||||
ctx *jxcontext.Context
|
||||
orderCreatedStart time.Time
|
||||
orderCreatedEnd time.Time
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantErr bool
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if err := SaveJdsOrders(tt.args.ctx, tt.args.orderCreatedStart, tt.args.orderCreatedEnd); (err != nil) != tt.wantErr {
|
||||
t.Errorf("SaveJdsOrders() error = %v, wantErr %v", err, tt.wantErr)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,177 +0,0 @@
|
||||
package orderman
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxcallback/scheduler"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
)
|
||||
|
||||
const (
|
||||
pendingOrderGapMax = 2 * 24 * time.Hour // 每次重启机子时,要检查几天内的订单状态
|
||||
maxTimeHandlePendingOrder = 2 * time.Second //处理pending order的最长时间
|
||||
maxSleepGapHandlePendingOrder = 5 * time.Millisecond // 每个pending order的最长时间间隙
|
||||
)
|
||||
|
||||
var (
|
||||
ErrCanNotFindOrder = errors.New("找不到相应订单")
|
||||
ErrCanNotFindWaybill = errors.New("找不到相应运单")
|
||||
)
|
||||
|
||||
var (
|
||||
FixedOrderManager *OrderManager
|
||||
)
|
||||
|
||||
// 所有公共接口调用前,要求在order里或status中设置合适的Status
|
||||
type OrderManager struct {
|
||||
}
|
||||
|
||||
func NewOrderManager() *OrderManager {
|
||||
return &OrderManager{}
|
||||
}
|
||||
|
||||
type IStatusTimer interface {
|
||||
GetStatusTime() time.Time
|
||||
}
|
||||
|
||||
type StatusTimerSlice []IStatusTimer
|
||||
|
||||
func (s StatusTimerSlice) Len() int {
|
||||
return len(s)
|
||||
}
|
||||
|
||||
func (s StatusTimerSlice) Less(i, j int) bool {
|
||||
return s[i].GetStatusTime().Sub(s[j].GetStatusTime()) < 0
|
||||
}
|
||||
|
||||
func (s StatusTimerSlice) Swap(i, j int) {
|
||||
tmp := s[i]
|
||||
s[i] = s[j]
|
||||
s[j] = tmp
|
||||
}
|
||||
|
||||
func init() {
|
||||
FixedOrderManager = NewOrderManager()
|
||||
partner.InitOrderManager(FixedOrderManager)
|
||||
}
|
||||
|
||||
// 美团回调错误信息
|
||||
func addOrderOrWaybillStatus(status *model.OrderStatus, db *dao.DaoDB) (isDuplicated bool, err error) {
|
||||
if status.OrderType == model.OrderTypeOrder {
|
||||
globals.SugarLogger.Debugf("addOrderStatus order:%v", status)
|
||||
} else if status.OrderType == model.OrderTypeWaybill {
|
||||
globals.SugarLogger.Debugf("addOrderStatus waybill:%v", status)
|
||||
} else {
|
||||
globals.SugarLogger.Debugf("addOrderStatus afsOrder:%v", status)
|
||||
}
|
||||
txDB, _ := dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil || err != nil {
|
||||
dao.Rollback(db, txDB)
|
||||
if r != nil {
|
||||
panic(r)
|
||||
}
|
||||
}
|
||||
}()
|
||||
status.ID = 0
|
||||
status.Remark = utils.LimitUTF8StringLen(status.Remark, 255)
|
||||
created, _, err := db.Db.ReadOrCreate(status, "VendorOrderID", "VendorID", "OrderType", "Status", "VendorStatus", "StatusTime")
|
||||
if err == nil {
|
||||
if !created {
|
||||
isDuplicated = true
|
||||
status.DuplicatedCount++
|
||||
utils.CallFuncLogError(func() error {
|
||||
_, err = db.Db.Update(status, "DuplicatedCount")
|
||||
return err
|
||||
}, "addOrderOrWaybillStatus update DuplicatedCount, status:%v", status)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
// todo 这里居然会有主键重复错误,逻辑上是不应该的
|
||||
globals.SugarLogger.Warnf("addOrderOrWaybillStatus status:%v, access db error:%v", status, err)
|
||||
} else {
|
||||
dao.Commit(db, txDB)
|
||||
}
|
||||
return isDuplicated, err
|
||||
}
|
||||
|
||||
func (c *OrderManager) GetStatusDuplicatedCount(status *model.OrderStatus) (duplicatedCount int) {
|
||||
if status == nil {
|
||||
return 0
|
||||
}
|
||||
db := dao.GetDB()
|
||||
if err := dao.GetEntity(db, status, "VendorOrderID", "VendorID", "OrderType", "VendorStatus", "StatusTime"); err == nil {
|
||||
return status.DuplicatedCount
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// todo 最好还是改成全事件回放算了
|
||||
func LoadPendingOrders() {
|
||||
orders, err := dao.LoadPendingOrders(dao.GetDB(), time.Now().Add(-pendingOrderGapMax), model.OrderStatusEndBegin)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
ordersCount := len(orders)
|
||||
if ordersCount > 0 {
|
||||
bills := FixedOrderManager.LoadPendingWaybills()
|
||||
var sortOrders StatusTimerSlice
|
||||
orderMap := make(map[string]*model.GoodsOrder)
|
||||
for _, order := range orders {
|
||||
if order.Status > model.OrderStatusNew {
|
||||
status := model.Order2Status(order)
|
||||
sortOrders = append(sortOrders, status)
|
||||
}
|
||||
// order.Status = model.OrderStatusNew // 就是要以实际order状态来调用scheduler.OnOrderNew
|
||||
order.StatusTime = order.OrderCreatedAt
|
||||
sortOrders = append(sortOrders, order)
|
||||
orderMap[jxutils.ComposeUniversalOrderID(order.VendorOrderID, order.VendorID)] = order
|
||||
}
|
||||
for _, bill := range bills {
|
||||
if bill.Status > model.WaybillStatusNew {
|
||||
bill2 := *bill
|
||||
sortOrders = append(sortOrders, &bill2)
|
||||
}
|
||||
bill.Status = model.WaybillStatusNew
|
||||
bill.StatusTime = bill.WaybillCreatedAt
|
||||
sortOrders = append(sortOrders, bill)
|
||||
}
|
||||
sort.Sort(sortOrders)
|
||||
sleepGap := maxTimeHandlePendingOrder / time.Duration(ordersCount)
|
||||
if sleepGap > maxSleepGapHandlePendingOrder {
|
||||
sleepGap = maxSleepGapHandlePendingOrder
|
||||
}
|
||||
lastTime := time.Now()
|
||||
for _, item := range sortOrders {
|
||||
if order, ok := item.(*model.GoodsOrder); ok {
|
||||
jxutils.CallMsgHandlerAsync(func() {
|
||||
scheduler.CurrentScheduler.OnOrderNew(order, true, true)
|
||||
}, jxutils.ComposeUniversalOrderID(order.VendorOrderID, order.VendorID))
|
||||
} else if status, ok := item.(*model.OrderStatus); ok {
|
||||
jxutils.CallMsgHandlerAsync(func() {
|
||||
order := orderMap[jxutils.ComposeUniversalOrderID(status.VendorOrderID, status.VendorID)]
|
||||
scheduler.CurrentScheduler.OnOrderStatusChanged(order, status, true)
|
||||
}, jxutils.ComposeUniversalOrderID(status.RefVendorOrderID, status.RefVendorID))
|
||||
} else {
|
||||
bill := item.(*model.Waybill)
|
||||
jxutils.CallMsgHandlerAsync(func() {
|
||||
scheduler.CurrentScheduler.OnWaybillStatusChanged(bill, true)
|
||||
}, jxutils.ComposeUniversalOrderID(bill.VendorOrderID, bill.OrderVendorID))
|
||||
}
|
||||
curTime := time.Now()
|
||||
timeout := sleepGap - curTime.Sub(lastTime)
|
||||
if timeout > 0 {
|
||||
time.Sleep(timeout)
|
||||
}
|
||||
lastTime = curTime
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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,289 +0,0 @@
|
||||
package orderman
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/dadaapi"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxcallback/scheduler"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"github.com/astaxie/beego/client/orm"
|
||||
)
|
||||
|
||||
var (
|
||||
waybillOrderStatusMap = map[int]int{
|
||||
model.WaybillStatusApplyFailedGetGoods: model.OrderStatusApplyFailedGetGoods,
|
||||
model.WaybillStatusAgreeFailedGetGoods: model.OrderStatusAgreeFailedGetGoods,
|
||||
model.WaybillStatusRefuseFailedGetGoods: model.OrderStatusRefuseFailedGetGoods,
|
||||
model.WaybillStatusDeliverFailed: model.OrderStatusDeliverFailed,
|
||||
}
|
||||
complaintReasonsMap = map[int]string{
|
||||
1: "骑手态度恶劣",
|
||||
2: "骑手接单后未取货",
|
||||
3: "骑手取货太慢",
|
||||
4: "骑手送货太慢",
|
||||
5: "货品未送达",
|
||||
6: "货品有损坏",
|
||||
7: "骑手违规收取顾客其他费用",
|
||||
69: "骑手恶意取消订单",
|
||||
71: "骑手提前点击取货/送达",
|
||||
}
|
||||
)
|
||||
|
||||
func (w *OrderManager) LoadPendingWaybills() []*model.Waybill {
|
||||
db := orm.NewOrm()
|
||||
var bills []*model.Waybill
|
||||
tillTime := time.Now().Add(-pendingOrderGapMax)
|
||||
_, err := db.Raw(`
|
||||
SELECT t1.*
|
||||
FROM waybill t1
|
||||
JOIN goods_order t2 ON t2.vendor_order_id = t1.vendor_order_id
|
||||
AND t2.vendor_id = t1.order_vendor_id
|
||||
AND t2.order_created_at >= ?
|
||||
AND t2.status < ?
|
||||
WHERE t1.waybill_created_at >= ?
|
||||
AND t1.status < ?
|
||||
`, tillTime, model.OrderStatusEndBegin, tillTime, model.WaybillStatusEndBegin).QueryRows(&bills)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return bills
|
||||
}
|
||||
|
||||
func (w *OrderManager) OnWaybillNew(bill2 *model.Waybill, db *dao.DaoDB) (isDuplicated bool, err error) {
|
||||
isDuplicated, err = addOrderOrWaybillStatus(model.Waybill2Status(bill2), db)
|
||||
if err == nil && !isDuplicated {
|
||||
bill2.ID = 0
|
||||
bill2.WaybillCreatedAt = bill2.StatusTime
|
||||
bill2.WaybillFinishedAt = utils.DefaultTimeValue
|
||||
billCopied := *bill2
|
||||
bill := &billCopied
|
||||
created, _, err2 := db.Db.ReadOrCreate(bill, "VendorWaybillID", "WaybillVendorID")
|
||||
if err = err2; err == nil {
|
||||
if !created {
|
||||
bill.DuplicatedCount++
|
||||
if bill2.VendorOrderID == bill2.VendorWaybillID { // 购物平台(比如京东)重新建的运单,单号始终是与订单相同的
|
||||
bill2.ID = bill.ID
|
||||
bill2.CreatedAt = bill.CreatedAt
|
||||
bill2.DuplicatedCount = bill.DuplicatedCount
|
||||
err = utils.CallFuncLogError(func() error {
|
||||
_, err = db.Db.Update(bill2) //更新所有字段
|
||||
return err
|
||||
}, "onWaybillNew Update1")
|
||||
} else {
|
||||
isDuplicated = true
|
||||
err = utils.CallFuncLogError(func() error {
|
||||
_, err = db.Db.Update(bill, "DuplicatedCount")
|
||||
return err
|
||||
}, "onWaybillNew Update2")
|
||||
}
|
||||
} else {
|
||||
*bill2 = *bill
|
||||
}
|
||||
} else {
|
||||
globals.SugarLogger.Warnf("onWaybillNew create bill:%v, error:%v", bill2, err)
|
||||
}
|
||||
}
|
||||
return isDuplicated, err
|
||||
}
|
||||
|
||||
func (w *OrderManager) OnWaybillStatusChanged(bill *model.Waybill) (err error) {
|
||||
var isDuplicated bool
|
||||
if bill.ActualFee == 0 {
|
||||
bill.ActualFee = bill.DesiredFee + bill.TipFee
|
||||
}
|
||||
bill.CourierMobile = jxutils.FormalizeMobile(bill.CourierMobile)
|
||||
db := dao.GetDB()
|
||||
txDB, _ := dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
dao.Rollback(db, txDB)
|
||||
panic(r)
|
||||
}
|
||||
}()
|
||||
duplicatedCount := 0
|
||||
if bill.Status == model.WaybillStatusNew {
|
||||
isDuplicated, err = w.OnWaybillNew(bill, db)
|
||||
if isDuplicated {
|
||||
duplicatedCount = 1
|
||||
}
|
||||
} else {
|
||||
existingBill, err2 := w.LoadWaybill(bill.VendorWaybillID, bill.WaybillVendorID)
|
||||
// todo
|
||||
if err2 == nil {
|
||||
bill.DeliveryFlag = existingBill.DeliveryFlag
|
||||
}
|
||||
if bill.Status == model.WaybillStatusAccepted { // 处理美团配送丢失新运单消息的情况
|
||||
if err2 != nil {
|
||||
if dao.IsNoRowsError(err2) || err2 == ErrCanNotFindWaybill {
|
||||
existingBill = bill
|
||||
billCopy := *bill
|
||||
billCopy.Status = model.WaybillStatusNew
|
||||
if isDuplicated, err = w.OnWaybillNew(&billCopy, db); err != nil {
|
||||
dao.Rollback(db, txDB)
|
||||
return err
|
||||
}
|
||||
dao.Commit(db, txDB)
|
||||
// 进运单调度器OnWaybillStatusChanged之前要确保事务是提交了的,否则会导致死锁
|
||||
// 加载数据到当前系统调度器当中
|
||||
scheduler.CurrentScheduler.OnWaybillStatusChanged(&billCopy, false)
|
||||
dao.Begin(db)
|
||||
} else {
|
||||
dao.Rollback(db, txDB)
|
||||
return err2
|
||||
}
|
||||
}
|
||||
// 运单消息错序,之前已经结束了,直接返回
|
||||
if existingBill.Status >= model.WaybillStatusEndBegin {
|
||||
dao.Commit(db, txDB)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
addParams := orm.Params{}
|
||||
if bill.Status >= model.WaybillStatusAccepted {
|
||||
//if bill.Status == model.WaybillStatusAccepted {等于10的时候没有运费
|
||||
if bill.DesiredFee > 0 {
|
||||
addParams["desired_fee"] = bill.DesiredFee
|
||||
}
|
||||
if bill.ActualFee > 0 {
|
||||
addParams["actual_fee"] = bill.ActualFee
|
||||
}
|
||||
//}
|
||||
//单独增加顺丰派送取消运单修改配送费逻辑
|
||||
if (bill.WaybillVendorID == model.VendorIDSFPS || bill.WaybillVendorID == model.VendorIDMTWM) && bill.Status == model.WaybillStatusCanceled {
|
||||
addParams["desired_fee"] = bill.DesiredFee
|
||||
addParams["actual_fee"] = bill.ActualFee
|
||||
}
|
||||
if bill.CourierMobile != "" {
|
||||
addParams["courier_name"] = bill.CourierName
|
||||
addParams["courier_mobile"] = bill.CourierMobile
|
||||
}
|
||||
if bill.Status >= model.WaybillStatusEndBegin {
|
||||
addParams["waybill_finished_at"] = bill.StatusTime
|
||||
}
|
||||
}
|
||||
duplicatedCount, err = w.addWaybillStatus(bill, db, addParams)
|
||||
if err != nil {
|
||||
dao.Rollback(db, txDB)
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
dao.Commit(db, txDB)
|
||||
if duplicatedCount == 0 {
|
||||
scheduler.CurrentScheduler.OnWaybillStatusChanged(bill, false)
|
||||
}
|
||||
} else {
|
||||
dao.Rollback(db, txDB)
|
||||
}
|
||||
if bill.VendorOrderID == bill.VendorWaybillID {
|
||||
if status, ok := waybillOrderStatusMap[bill.Status]; ok {
|
||||
fakeOrderStatus := &model.OrderStatus{
|
||||
VendorOrderID: bill.VendorOrderID,
|
||||
VendorID: bill.OrderVendorID,
|
||||
OrderType: model.OrderTypeOrder,
|
||||
RefVendorOrderID: bill.VendorOrderID,
|
||||
RefVendorID: bill.OrderVendorID,
|
||||
Status: status,
|
||||
VendorStatus: bill.VendorStatus,
|
||||
StatusTime: bill.StatusTime,
|
||||
Remark: bill.Remark + ",订单运费:" + fmt.Sprintf("%d", bill.DesiredFee),
|
||||
}
|
||||
w.OnOrderStatusChanged(bill.VendorOrgCode, fakeOrderStatus)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (w *OrderManager) addWaybillStatus(bill *model.Waybill, db *dao.DaoDB, addParams orm.Params) (duplicatedCount int, err error) {
|
||||
waybillStatus := model.Waybill2Status(bill)
|
||||
isDuplicated, err := addOrderOrWaybillStatus(waybillStatus, db)
|
||||
if err == nil && !isDuplicated {
|
||||
if waybillStatus.Status > model.WaybillStatusUnknown { // todo 这里应该和addOrderStatus一样的改法,状态不能回绕
|
||||
params := utils.MergeMaps(orm.Params{
|
||||
"status": bill.Status,
|
||||
"vendor_status": bill.VendorStatus,
|
||||
"status_time": bill.StatusTime,
|
||||
}, addParams)
|
||||
utils.CallFuncLogError(func() error {
|
||||
_, err = db.Db.QueryTable("waybill").Filter("vendor_waybill_id", bill.VendorWaybillID).Filter("waybill_vendor_id", bill.WaybillVendorID).Filter("status__lte", bill.Status).Update(params)
|
||||
return err
|
||||
}, "addWaybillStatus update waybill status, bill:%v", bill)
|
||||
} else {
|
||||
duplicatedCount = -1
|
||||
}
|
||||
} else {
|
||||
duplicatedCount = 1
|
||||
}
|
||||
return duplicatedCount, err
|
||||
}
|
||||
|
||||
func (c *OrderManager) LoadWaybill(vendorWaybillID string, waybillVendorID int) (bill *model.Waybill, err error) {
|
||||
db := orm.NewOrm()
|
||||
bill = &model.Waybill{
|
||||
VendorWaybillID: vendorWaybillID,
|
||||
WaybillVendorID: waybillVendorID,
|
||||
}
|
||||
if err = db.Read(bill, "VendorWaybillID", "WaybillVendorID"); err != nil {
|
||||
bill = nil
|
||||
if err == orm.ErrNoRows {
|
||||
err = ErrCanNotFindWaybill
|
||||
}
|
||||
}
|
||||
return bill, err
|
||||
}
|
||||
|
||||
func GetComplaintReasons() (complaintReasonList []*dadaapi.ComplaintReason) {
|
||||
for k, v := range complaintReasonsMap {
|
||||
complaintReason := &dadaapi.ComplaintReason{
|
||||
ID: k,
|
||||
Reason: v,
|
||||
}
|
||||
complaintReasonList = append(complaintReasonList, complaintReason)
|
||||
}
|
||||
return complaintReasonList
|
||||
}
|
||||
|
||||
func ComplaintRider(ctx *jxcontext.Context, vendorOrderID string, waybillVendorID string, complaintID int, waybillID string) (err error) {
|
||||
wayBillList, err := dao.GetComplaintList(dao.GetDB(), vendorOrderID, waybillID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(wayBillList) != model.YES {
|
||||
return fmt.Errorf("订单所属运单不存在,或运单为分配骑手,无法投诉")
|
||||
}
|
||||
|
||||
if err == nil && len(wayBillList) > 0 {
|
||||
switch wayBillList[0].WaybillVendorID {
|
||||
case model.VendorIDFengNiao, model.VendorIDDada, model.VendorIDMTPS, model.VendorIDUUPT, model.VendorIDSFPS:
|
||||
tripartiteDelivery := partner.GetDeliveryPlatformFromVendorID(wayBillList[0].WaybillVendorID)
|
||||
if tripartiteDelivery != nil {
|
||||
err = tripartiteDelivery.Handler.ComplaintRider(wayBillList[0], complaintID, complaintReasonsMap[complaintID])
|
||||
} else {
|
||||
err = fmt.Errorf("投诉三方配送获取运单失败")
|
||||
}
|
||||
case model.VendorIDMTWM, model.VendorIDDD, model.VendorIDJD, model.VendorIDEBAI, model.VendorIDTaoVegetable:
|
||||
platformDelivery := partner.GetPurchaseOrderHandlerFromVendorID(wayBillList[0].WaybillVendorID)
|
||||
if platformDelivery != nil {
|
||||
err = platformDelivery.ComplaintRider(wayBillList[0].VendorOrderID, complaintID, complaintReasonsMap[complaintID])
|
||||
} else {
|
||||
err = fmt.Errorf("投诉平台配送获取运单失败")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// GetComplaintList 获取投诉列表
|
||||
func GetComplaintList(orderId string) ([]*model.Waybill, error) {
|
||||
return dao.GetComplaintList(dao.GetDB(), orderId, "")
|
||||
}
|
||||
@@ -1,281 +0,0 @@
|
||||
package basesch
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
tiktokShop "git.rosy.net.cn/baseapi/platformapi/tiktok_shop/tiktok_api"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxcallback/scheduler"
|
||||
"git.rosy.net.cn/jx-callback/business/jxstore/cms"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
)
|
||||
|
||||
var (
|
||||
ctx *jxcontext.Context
|
||||
)
|
||||
var (
|
||||
FixedBaseScheduler *BaseScheduler
|
||||
)
|
||||
|
||||
type BaseScheduler struct {
|
||||
IsReallyCallPlatformAPI bool
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) AcceptOrRefuseOrder(order *model.GoodsOrder, isAcceptIt bool, userName string) (err error) {
|
||||
if /*order.LockStatus == model.OrderStatusUnknown && */ order.Status == model.OrderStatusNew || order.Status == model.OrderStatusWaitAccepted {
|
||||
if c.IsReallyCallPlatformAPI {
|
||||
err = utils.CallFuncLogErrorWithInfo(func() error {
|
||||
return partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID).AcceptOrRefuseOrder(order, isAcceptIt, userName)
|
||||
}, "AcceptOrRefuseOrder orderID:%s, isAcceptIt:%t", order.VendorOrderID, isAcceptIt)
|
||||
}
|
||||
} else {
|
||||
return scheduler.ErrOrderStatusAlreadySatisfyCurOperation
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) PickupGoods(order *model.GoodsOrder, isSelfDelivery bool, userName string) (err error) {
|
||||
if /*order.LockStatus == model.OrderStatusUnknown && */ order.Status == model.OrderStatusAccepted {
|
||||
if c.IsReallyCallPlatformAPI {
|
||||
handler := partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID)
|
||||
err = utils.CallFuncLogErrorWithInfo(func() (err error) {
|
||||
if err = handler.PickupGoods(order, isSelfDelivery, userName); err != nil {
|
||||
if status, err2 := handler.GetOrderStatus(order.VendorOrgCode, order.VendorOrderID); err2 == nil && status >= model.OrderStatusFinished {
|
||||
err = nil
|
||||
}
|
||||
}
|
||||
return err
|
||||
}, "PickupGoods orderID:%s", order.VendorOrderID)
|
||||
}
|
||||
} else {
|
||||
if order.LockStatus != model.OrderStatusUnknown || order.Status < model.OrderStatusAccepted {
|
||||
err = scheduler.ErrOrderStatusIsNotSuitable4CurOperation
|
||||
} else {
|
||||
err = scheduler.ErrOrderStatusAlreadySatisfyCurOperation
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) Swtich2SelfDeliver(order *model.GoodsOrder, userName string) (err error) {
|
||||
if /*order.LockStatus == model.OrderStatusUnknown && */ order.Status >= model.OrderStatusFinishedPickup && order.Status <= model.OrderStatusDelivering {
|
||||
if order.DeliveryFlag&model.OrderDeliveryFlagMaskPurcahseDisabled == 0 && c.IsReallyCallPlatformAPI {
|
||||
err = utils.CallFuncLogErrorWithInfo(func() error {
|
||||
return partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID).Swtich2SelfDeliver(order, userName)
|
||||
}, "Swtich2SelfDeliver orderID:%s", order.VendorOrderID)
|
||||
}
|
||||
if err == nil { // 因为有些平台转自送后,不会再发送订单在配送中消息过来,所以成功后就强制设置状态为配送中
|
||||
order.Status = model.OrderStatusDelivering
|
||||
order.DeliveryFlag |= model.OrderDeliveryFlagMaskPurcahseDisabled
|
||||
err = partner.CurOrderManager.UpdateOrderStatusAndDeliveryFlag(order)
|
||||
}
|
||||
} else {
|
||||
if order.LockStatus != model.OrderStatusUnknown || order.Status < model.OrderStatusFinishedPickup || order.VendorID == order.WaybillVendorID {
|
||||
err = scheduler.ErrOrderStatusIsNotSuitable4CurOperation
|
||||
} else {
|
||||
err = scheduler.ErrOrderStatusAlreadySatisfyCurOperation
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) Swtich2SelfDelivered(order *model.GoodsOrder, userName string) (err error) {
|
||||
if /*order.LockStatus == model.OrderStatusUnknown && */ order.Status == model.OrderStatusDelivering {
|
||||
if c.IsReallyCallPlatformAPI {
|
||||
err = utils.CallFuncLogError(func() error {
|
||||
return partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID).Swtich2SelfDelivered(order, userName)
|
||||
}, "Swtich2SelfDelivered orderID:%s", order.VendorOrderID)
|
||||
}
|
||||
} else {
|
||||
if order.LockStatus != model.OrderStatusUnknown || order.Status < model.OrderStatusDelivering {
|
||||
err = scheduler.ErrOrderStatusIsNotSuitable4CurOperation
|
||||
} else {
|
||||
err = scheduler.ErrOrderStatusAlreadySatisfyCurOperation
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) SelfDeliverDelivering(order *model.GoodsOrder, userName string) (err error) {
|
||||
if order.Status == model.OrderStatusFinishedPickup {
|
||||
if c.IsReallyCallPlatformAPI {
|
||||
err = utils.CallFuncLogError(func() error {
|
||||
// 下面这个写法暂存,可能会有问题
|
||||
if order.VendorID == model.VendorIDMTWM {
|
||||
// 转自送同时取消平台订单(美团才做这个操作)
|
||||
if _, err := partner.GetPurchasePlatformFromVendorID(order.VendorID).GetCancelDeliveryReason(order); err != nil {
|
||||
partner.CurOrderManager.OnOrderMsg(order, "订单转自送取消美团平台发单获取理由失败", err.Error())
|
||||
}
|
||||
// 取消美团外卖配送,转自送
|
||||
if err = partner.GetPurchasePlatformFromVendorID(order.VendorID).CancelLogisticsByWmOrderId(order, "101512", "已选择其他配送方式", order.VendorStoreID, order.VendorOrderID); err != nil {
|
||||
partner.CurOrderManager.OnOrderMsg(order, "取消美团外卖,转用三方配送", err.Error())
|
||||
}
|
||||
// 查询订单状态,
|
||||
orderStatus, _ := partner.GetPurchasePlatformFromVendorID(order.VendorID).OrderLogisticsStatus(order.VendorOrderID)
|
||||
status := 0
|
||||
if orderStatus != nil {
|
||||
status = orderStatus.LogisticsStatus
|
||||
}
|
||||
if status == 100 { // 美团取消配送单
|
||||
partner.CurOrderManager.OnOrderMsg(order, "美团外卖转自送成功.", "")
|
||||
return nil
|
||||
} else if strings.Contains(err.Error(), "包裹不存在") || strings.Contains(err.Error(), "运单不存在") || strings.Contains(err.Error(), "1071") || strings.Contains(err.Error(), "1014") || strings.Contains(err.Error(), "invalid character 'o' looking for beginning of value") {
|
||||
partner.CurOrderManager.OnOrderMsg(order, "美团外卖转自送可能成功,异常:", err.Error())
|
||||
err = nil
|
||||
return nil
|
||||
} else if strings.Contains(err.Error(), "商家没有接入众包配送,无法进行众包配送相关操作") {
|
||||
partner.CurOrderManager.OnOrderMsg(order, "商家无配送设置,转配送成功", err.Error())
|
||||
err = nil
|
||||
} else if strings.Contains(err.Error(), "无需重复取消") {
|
||||
partner.CurOrderManager.OnOrderMsg(order, "商家无配送设置,转配送成功", err.Error())
|
||||
err = nil
|
||||
} else {
|
||||
bill, _ := partner.CurOrderManager.LoadWaybill(order.VendorWaybillID, order.WaybillVendorID)
|
||||
err = c.CancelWaybill(bill, partner.CancelWaybillReasonOther, userName+":5"+partner.CancelWaybillReasonStrActive)
|
||||
partner.CurOrderManager.OnOrderMsg(order, "美团外卖运单无法取消,", err.Error())
|
||||
return err
|
||||
}
|
||||
} else if order.VendorID == model.VendorIDDD { //抖音配送
|
||||
localBill, _ := partner.CurOrderManager.LoadWaybill(order.VendorWaybillID, order.WaybillVendorID)
|
||||
// 获取抖音配送状态
|
||||
tiktokWayBillStatus, err2 := partner.GetPurchasePlatformFromVendorID(order.VendorID).OrderLogisticsStatus(order.VendorOrderID)
|
||||
if tiktokWayBillStatus != nil && tiktokWayBillStatus.LogisticsStatus >= tiktokShop.ShipmentStatusReceived && tiktokWayBillStatus.LogisticsStatus != tiktokShop.ShipmentStatusCanceled {
|
||||
//取消抖音配送转自送
|
||||
err = c.CancelWaybill(localBill, partner.CancelWaybillReasonDYPSCancel, partner.CancelWaybillReasonStrDYPSCancel+"抖音骑手已经接单,无法取消6")
|
||||
partner.CurOrderManager.OnOrderMsg(order, "取消抖音配送,转用门店自配送/三方配送", "抖音骑手已经接单,无法取消")
|
||||
return err
|
||||
} else if tiktokWayBillStatus != nil && tiktokWayBillStatus.LogisticsStatus == -1 { // 先转自送,自送不成功取消平台配送.
|
||||
if err := partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID).SelfDeliverDelivering(order, userName); err != nil {
|
||||
partner.CurOrderManager.OnOrderMsg(order, "抖音转自送,平台无运力", "tiktokWayBillStatus = -1")
|
||||
}
|
||||
} else if (err2 != nil && strings.Contains(err2.Error(), "当前状态获取不到运力信息")) || (tiktokWayBillStatus != nil && tiktokWayBillStatus.LogisticsStatus == tiktokShop.ShipmentStatusCanceled) {
|
||||
partner.GetPurchasePlatformFromVendorID(order.VendorID).SelfDeliverDelivering(order, "")
|
||||
} else if err = partner.GetPurchasePlatformFromVendorID(order.VendorID).CancelLogisticsByWmOrderId(order, "", "", order.VendorStoreID, order.VendorOrderID); err != nil {
|
||||
partner.CurOrderManager.OnOrderMsg(order, "取消抖音配送异常:", err.Error())
|
||||
if err = c.CancelWaybill(localBill, partner.CancelWaybillReasonDYPSCancel, partner.CancelWaybillReasonStrDYPSCancel+"7"); err != nil {
|
||||
partner.CurOrderManager.OnOrderMsg(order, "取消抖音平台运单错误,无法转自送", err.Error())
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
partner.GetPurchasePlatformFromVendorID(order.VendorID).SelfDeliverDelivering(order, "")
|
||||
}
|
||||
} else {
|
||||
if err := partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID).SelfDeliverDelivering(order, userName); err != nil && (err != scheduler.ErrOrderStatusAlreadySatisfyCurOperation) {
|
||||
partner.CurOrderManager.OnOrderMsg(order, "SelfDeliverDelivering 调用[SelfDeliverDelivering]转自送", err.Error())
|
||||
return err
|
||||
}
|
||||
}
|
||||
return err
|
||||
}, "SelfDeliverDelivering orderID:%s", order.VendorOrderID)
|
||||
if err == nil { // 因为有些平台设置配送中后,不会发送订单在配送中消息过来,所以成功后就强制设置状态为配送中
|
||||
order.Status = model.OrderStatusDelivering
|
||||
err = partner.CurOrderManager.UpdateOrderStatusAndDeliveryFlag(order)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if order.LockStatus != model.OrderStatusUnknown || order.Status < model.OrderStatusFinishedPickup {
|
||||
err = scheduler.ErrOrderStatusIsNotSuitable4CurOperation
|
||||
} else {
|
||||
err = scheduler.ErrOrderStatusAlreadySatisfyCurOperation
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) SelfDeliverDelivered(order *model.GoodsOrder, userName string) (err error) {
|
||||
if order.Status >= model.OrderStatusFinishedPickup && order.Status <= model.OrderStatusDelivering {
|
||||
if c.IsReallyCallPlatformAPI {
|
||||
err = utils.CallFuncLogError(func() error {
|
||||
if err = partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID).SelfDeliverDelivered(order, userName); err == nil {
|
||||
bill, _ := partner.CurOrderManager.LoadWaybill(order.VendorWaybillID, order.WaybillVendorID)
|
||||
if bill != nil && bill.WaybillVendorID != model.VendorJXFakeWL && bill.WaybillVendorID != model.VendorIDUnknown {
|
||||
c.CancelWaybill(bill, partner.CancelWaybillReasonOther, userName+":"+partner.CancelWaybillReasonStrActive+"8")
|
||||
}
|
||||
}
|
||||
return err
|
||||
}, "SelfDeliverDelivered orderID:%s", order.VendorOrderID)
|
||||
}
|
||||
} else {
|
||||
if order.LockStatus != model.OrderStatusUnknown || order.Status < model.OrderStatusDelivering {
|
||||
err = scheduler.ErrOrderStatusIsNotSuitable4CurOperation
|
||||
} else {
|
||||
err = scheduler.ErrOrderStatusAlreadySatisfyCurOperation
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) CreateWaybill(platformVendorID int, order *model.GoodsOrder, maxDeliveryFee int64) (bill *model.Waybill, err error) {
|
||||
if !model.IsOrderSolid(order) { // 如果订单是不完整的
|
||||
return nil, scheduler.ErrOrderIsNotSolid
|
||||
}
|
||||
|
||||
storeDetail, _ := dao.GetStoreDetail(dao.GetDB(), jxutils.GetSaleStoreIDFromOrder(order), order.VendorID, order.VendorOrgCode)
|
||||
var balance int
|
||||
|
||||
// 门店发单,如果是京西门店,直接使用京西余额,非京西门店使用门店余额,余额不足使用品牌余额!
|
||||
if order.CreateDeliveryType == model.YES {
|
||||
storeAcct, err := cms.GetStoreAcctBalance(ctx, jxutils.GetSaleStoreIDFromOrder(order)) // 获取门店余额
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
balance = storeAcct.AccountBalance
|
||||
} else {
|
||||
balance, _ = partner.CurStoreAcctManager.GetBrandBalance(storeDetail.BrandID)
|
||||
}
|
||||
|
||||
handlerInfo := partner.GetDeliveryPlatformFromVendorID(platformVendorID)
|
||||
if handlerInfo != nil && handlerInfo.Use4CreateWaybill {
|
||||
if _, ok := model.DeliveryBrandMarkMap[platformVendorID]; ok && storeDetail.BrandIsOpen != 0 && balance >= model.BrandBalanceLimit {
|
||||
if c.IsReallyCallPlatformAPI {
|
||||
// 如果门店是美团服务商且订单为美团订单
|
||||
if storeDetail.IsService == model.YES && order.VendorID == model.VendorIDMTWM {
|
||||
err = fmt.Errorf("京西ID:[%d],平台id[%s],平台[美团]:错误:[%s]", storeDetail.Store.ID, storeDetail.VendorStoreID, "此门店美团平台为服务商模式,不支持本系统提供的三方配送![仅美团,其余平台订单正常使用.]")
|
||||
} else {
|
||||
if order.VendorID == model.VendorIDEBAI && strings.Contains(order.ConsigneeAddress, EBaiOrderAddressHide) {
|
||||
return nil, fmt.Errorf("由于饿了么用户数据隐私保护,发三方配送前请先将订单转为自配送,获取详情地址")
|
||||
}
|
||||
// 生成三方运单
|
||||
bill, err = handlerInfo.Handler.CreateWaybill(order, maxDeliveryFee)
|
||||
if err != nil {
|
||||
globals.SugarLogger.Infof("CreateWaybill failed orderID:%s vendorID:%d with error:%v", order.VendorOrderID, platformVendorID, err)
|
||||
} else {
|
||||
order.DeliveryFlag |= model.WaybillVendorID2Mask(platformVendorID)
|
||||
err = partner.CurOrderManager.UpdateOrderStatusAndDeliveryFlag(order)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
err = fmt.Errorf("创建运单是门店余额不足十元,无法创建运单")
|
||||
}
|
||||
} else {
|
||||
err = scheduler.ErrDeliverProviderWrong
|
||||
}
|
||||
return bill, err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) CancelWaybill(bill *model.Waybill, cancelReasonID int, cancelReason string) (err error) {
|
||||
// 部分快递平台在取消成功后有时会不发运单取消消息过来(比如达达,904200512000442),为避免二次取消报错,添加状态判断
|
||||
if c.IsReallyCallPlatformAPI && bill.OrderVendorID != bill.WaybillVendorID && bill.Status != model.WaybillStatusCanceled {
|
||||
if handlerInfo := partner.GetDeliveryPlatformFromVendorID(bill.WaybillVendorID); handlerInfo != nil {
|
||||
if err = utils.CallFuncLogErrorWithInfo(func() error {
|
||||
if err := handlerInfo.Handler.CancelWaybill(bill, cancelReasonID, cancelReason+"9"); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}, "CancelWaybill bill:%v", bill); err == nil {
|
||||
bill.Status = model.WaybillStatusCanceled
|
||||
bill.DeliveryFlag |= model.WaybillDeliveryFlagMaskActiveCancel
|
||||
_, err = dao.UpdateEntity(nil, bill, "Status", "DeliveryFlag")
|
||||
}
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -1,577 +0,0 @@
|
||||
package basesch
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/jdshopapi"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/dingdingapi"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/baseapi/utils/errlist"
|
||||
"git.rosy.net.cn/jx-callback/business/jxstore/cms"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/ddmsg"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
)
|
||||
|
||||
const (
|
||||
autoSelfTakeCode = "135246"
|
||||
)
|
||||
|
||||
const (
|
||||
EBaiOrderAddressHide = "[隐私保护]顾客地址已隐藏"
|
||||
)
|
||||
|
||||
func (c *BaseScheduler) CreateWaybillOnProviders(ctx *jxcontext.Context, order *model.GoodsOrder, courierVendorIDs, excludeCourierVendorIDs []int, maxDeliveryFee int64, createOnlyOne bool) (bills []*model.Waybill, err error) {
|
||||
storeCourierList, err := dao.GetStoreCourierList2(dao.GetDB(), []int{jxutils.GetSaleStoreIDFromOrder(order)}, courierVendorIDs, model.StoreStatusOpened, []int{model.StoreAuditStatusOnline, model.StoreAuditStatusUpdated})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
courierVendorIDMap := jxutils.IntList2Map(courierVendorIDs)
|
||||
excludeCourierVendorIDMap := jxutils.IntList2Map(excludeCourierVendorIDs)
|
||||
errList := errlist.New()
|
||||
|
||||
store, _ := dao.GetStoreDetail(dao.GetDB(), order.JxStoreID, order.VendorID, order.VendorOrgCode)
|
||||
for _, storeCourier := range storeCourierList {
|
||||
switch storeCourier.Status {
|
||||
case model.YES:
|
||||
if (courierVendorIDs == nil || courierVendorIDMap[storeCourier.VendorID] == 1) &&
|
||||
(excludeCourierVendorIDs == nil || excludeCourierVendorIDMap[storeCourier.VendorID] == 0) {
|
||||
if handler := partner.GetDeliveryPlatformFromVendorID(storeCourier.VendorID); handler != nil && handler.Use4CreateWaybill {
|
||||
courierVendorID := storeCourier.VendorID
|
||||
// 创建运单
|
||||
bill, err2 := c.CreateWaybill(courierVendorID, order, maxDeliveryFee)
|
||||
if err = err2; err == nil {
|
||||
// 其实这个bill没啥用,运单的创建是通过回调产生的
|
||||
bill.DesiredFee += int64(model.WayBillDeliveryMarkUp + store.FreightMarkup)
|
||||
if bill.WaybillVendorID == model.VendorIDFengNiao {
|
||||
bill.DesiredFee += model.WayBillDeliveryMarkUp
|
||||
}
|
||||
bill.DesiredFee += int64(store.FreightMarkup)
|
||||
bills = append(bills, bill)
|
||||
if createOnlyOne {
|
||||
break
|
||||
}
|
||||
} else {
|
||||
errList.AddErr(fmt.Errorf("平台:%s,%s", jxutils.GetVendorName(courierVendorID), err.Error()))
|
||||
}
|
||||
}
|
||||
}
|
||||
case model.NO:
|
||||
errList.AddErr(fmt.Errorf("平台:%s,发单配送被关闭,打开后发单", jxutils.GetVendorName(storeCourier.VendorID)))
|
||||
}
|
||||
}
|
||||
if len(bills) > 0 {
|
||||
err = errList.GetErrListAsOne()
|
||||
if err != nil {
|
||||
partner.CurOrderManager.OnOrderMsg(order, "创建三方运单部分失败", err.Error())
|
||||
}
|
||||
err = nil
|
||||
} else if errList.GetErrListAsOne() == nil {
|
||||
err = fmt.Errorf("orderID:%s过订单发三方配送亏损超6元/当前订单配送方式不是门店自送/没有绑定有效的三方配送门店", order.VendorOrderID)
|
||||
} else {
|
||||
err = fmt.Errorf("orderID:%s所有运单失败:%s", order.VendorOrderID, errList.GetErrListAsOne().Error())
|
||||
}
|
||||
return bills, err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) SelfDeliveredAndUpdateStatus(ctx *jxcontext.Context, vendorOrderID string, vendorID int, userName string) (err error) {
|
||||
jxutils.CallMsgHandler(func() {
|
||||
err = func() (err error) {
|
||||
order, err := partner.CurOrderManager.LoadOrder(vendorOrderID, vendorID)
|
||||
if err == nil {
|
||||
if model.IsOrderDeliveryByStore(order) {
|
||||
err = c.SelfDeliverDelivered(order, userName)
|
||||
} else if model.IsOrderDeliveryByPlatform(order) {
|
||||
err = c.Swtich2SelfDelivered(order, userName)
|
||||
}
|
||||
if err == nil {
|
||||
order.Status = model.OrderStatusFinished // todo 是否需要强制设置完成状态?
|
||||
if err = dao.SetOrderFlag(dao.GetDB(), ctx.GetUserName(), order.VendorOrderID, order.VendorID, model.OrderFlagMaskSetDelivered); err != nil {
|
||||
return err
|
||||
}
|
||||
order.OrderFinishedAt = time.Now()
|
||||
dao.UpdateEntity(dao.GetDB(), order, "Status", "OrderFinishedAt")
|
||||
}
|
||||
}
|
||||
return err
|
||||
}()
|
||||
}, jxutils.ComposeUniversalOrderID(vendorOrderID, vendorID))
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) PickupGoodsAndUpdateStatus(ctx *jxcontext.Context, vendorOrderID string, vendorID int, userName string) (err error) {
|
||||
jxutils.CallMsgHandler(func() {
|
||||
err = func() (err error) {
|
||||
order, err := partner.CurOrderManager.LoadOrder(vendorOrderID, vendorID)
|
||||
if err == nil {
|
||||
flag := model.IsOrderDeliveryByStore(order) || model.IsOrderDeliveryBySelf(order)
|
||||
err = c.PickupGoods(order, flag, userName)
|
||||
if err == nil {
|
||||
partner.CurOrderManager.OnOrderMsg(order, fmt.Sprintf("订单手动拣货成功[%s]", ctx.GetUserName()), "")
|
||||
order.Status = model.OrderStatusFinishedPickup
|
||||
if err = partner.CurOrderManager.UpdateOrderStatusAndDeliveryFlag(order); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// 京西商城的自提订单,在拣货完成时自动设置为完成订单
|
||||
if model.IsOrderDeliveryBySelf(order) && order.VendorID == model.VendorIDJX {
|
||||
order.Status = model.OrderStatusFinished
|
||||
order.VendorStatus = utils.Int64ToStr(model.OrderStatusFinished)
|
||||
order.Flag = 128
|
||||
order.OrderFinishedAt = time.Now()
|
||||
dao.UpdateEntity(dao.GetDB(), order, "Status", "VendorStatus", "Flag", "OrderFinishedAt")
|
||||
}
|
||||
}
|
||||
return err
|
||||
}()
|
||||
}, jxutils.ComposeUniversalOrderID(vendorOrderID, vendorID))
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) AdjustOrder(ctx *jxcontext.Context, order *model.GoodsOrder, removedSkuList []*model.OrderSku, reason string) (err error) {
|
||||
if c.IsReallyCallPlatformAPI {
|
||||
err = partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID).AdjustOrder(ctx, order, removedSkuList, reason)
|
||||
if err == nil {
|
||||
var skuIDs []string
|
||||
for _, v := range removedSkuList {
|
||||
skuIDs = append(skuIDs, utils.Int2Str(v.SkuID))
|
||||
}
|
||||
noticeMsg := fmt.Sprintf("商品skuID列表:%v,订单号(点击进入详情):%v", strings.Join(skuIDs, ","), globals.BackstageHost+"/#/ordermanager/"+order.VendorOrderID)
|
||||
user, err := dao.GetUserByID(dao.GetDB(), "mobile", "18982250714")
|
||||
if user != nil && err == nil {
|
||||
ddmsg.SendUserMessage(dingdingapi.MsgTyeText, user.UserID, "调整单调整商品", noticeMsg)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) CancelOrder(ctx *jxcontext.Context, order *model.GoodsOrder, reason string) (err error) {
|
||||
if c.IsReallyCallPlatformAPI {
|
||||
if globals.IsAddEvent {
|
||||
err = cms.AddEventDetail(dao.GetDB(), ctx, model.OperateUpdate, order.StoreID, model.ThingTypeOrder, order.StoreID, order.VendorOrderID, order.StoreName)
|
||||
}
|
||||
err = partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID).CancelOrder(ctx, order, reason+","+ctx.GetUserName())
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) AcceptOrRefuseFailedGetOrder(ctx *jxcontext.Context, order *model.GoodsOrder, isAcceptIt bool, reason string) (err error) {
|
||||
if c.IsReallyCallPlatformAPI {
|
||||
err = partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID).AcceptOrRefuseFailedGetOrder(ctx, order, isAcceptIt)
|
||||
}
|
||||
if err == nil {
|
||||
flag := model.OrderFlagAgreeFailedGetGoods
|
||||
if !isAcceptIt {
|
||||
flag = model.OrderFlagRefuseFailedGetGoods
|
||||
}
|
||||
dao.SetOrderFlag(dao.GetDB(), ctx.GetUserName(), order.VendorOrderID, order.VendorID, flag)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) CallPMCourier(ctx *jxcontext.Context, order *model.GoodsOrder) (err error) {
|
||||
if c.IsReallyCallPlatformAPI {
|
||||
err = partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID).CallCourier(ctx, order)
|
||||
}
|
||||
if err == nil {
|
||||
dao.SetOrderFlag(dao.GetDB(), ctx.GetUserName(), order.VendorOrderID, order.VendorID, model.OrderFlagMaskCallPMCourier)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) ConfirmReceiveGoods(ctx *jxcontext.Context, order *model.GoodsOrder) (err error) {
|
||||
if c.IsReallyCallPlatformAPI {
|
||||
err = partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID).ConfirmReceiveGoods(ctx, order)
|
||||
}
|
||||
if err == nil {
|
||||
dao.SetOrderFlag(dao.GetDB(), ctx.GetUserName(), order.VendorOrderID, order.VendorID, model.OrderFlagMaskFailedDeliver)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) AgreeOrRefuseCancel(ctx *jxcontext.Context, order *model.GoodsOrder, isAcceptIt bool, reason string) (err error) {
|
||||
if c.IsReallyCallPlatformAPI {
|
||||
err = partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID).AgreeOrRefuseCancel(ctx, order, isAcceptIt, reason)
|
||||
}
|
||||
if err == nil {
|
||||
flag := model.OrderFlagAgreeUserApplyCancel
|
||||
if !isAcceptIt {
|
||||
flag = model.OrderFlagRefuseUserApplyCancel
|
||||
}
|
||||
dao.SetOrderFlag(dao.GetDB(), ctx.GetUserName(), order.VendorOrderID, order.VendorID, flag)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) CancelWaybillByID(ctx *jxcontext.Context, vendorWaybillID string, waybillVendorID int, cancelReasonID int, cancelReason string) (err error) {
|
||||
bill, err := partner.CurOrderManager.LoadWaybill(vendorWaybillID, waybillVendorID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
order, _ := partner.CurOrderManager.LoadOrder(bill.VendorOrderID, bill.OrderVendorID)
|
||||
|
||||
if bill.OrderVendorID != bill.WaybillVendorID { // 取消三方配送
|
||||
if err = c.CancelWaybill(bill, cancelReasonID, cancelReason); err != nil {
|
||||
return err
|
||||
}
|
||||
} else { // 取消平台配送转自送
|
||||
if err = c.Swtich2SelfDeliver(order, ctx.GetUserName()); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
partner.CurOrderManager.OnOrderMsg(order, utils.Int64ToStr(model.WaybillStatusCancel), "商户发起运单取消10")
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) AgreeOrRefuseRefund(ctx *jxcontext.Context, afsOrderID string, vendorID, approveType int, reason string) (err error) {
|
||||
skus := make([]*model.OrderFinancialSkuExt, 0, 0)
|
||||
afsOrder, err := partner.CurOrderManager.LoadAfsOrder(afsOrderID, vendorID)
|
||||
if err == nil {
|
||||
if c.IsReallyCallPlatformAPI {
|
||||
err = partner.GetPurchaseOrderHandlerFromVendorID(vendorID).AgreeOrRefuseRefund(ctx, afsOrder, approveType, reason)
|
||||
}
|
||||
if err == nil {
|
||||
flag := model.AfsOrderFlagAgreeUserRefund
|
||||
if approveType == partner.AfsApproveTypeRefused {
|
||||
flag = model.AfsOrderFlagRefuseUserRefund
|
||||
afsOrder.RefuseReason = reason
|
||||
partner.CurOrderManager.UpdateAfsOrderFields(afsOrder, []string{"RefuseReason"})
|
||||
} else {
|
||||
if order, _ := partner.CurOrderManager.LoadOrder(afsOrder.VendorOrderID, afsOrder.VendorID); order != nil {
|
||||
var (
|
||||
db = dao.GetDB()
|
||||
)
|
||||
waybills, _ := dao.GetWaybills(db, order.VendorOrderID, nil)
|
||||
//美团的订单如果是同意全部退款,要取消所有三方运单并停止调度
|
||||
if order.VendorID == model.VendorIDMTWM || order.VendorID == model.VendorIDJX || order.VendorID == model.VendorIDEBAI {
|
||||
var (
|
||||
afsCount, orderCount int
|
||||
)
|
||||
skus, _ = dao.GetAfsOrderSkuInfo(db, order.VendorOrderID, afsOrderID, order.VendorID, false)
|
||||
for _, v := range skus {
|
||||
afsCount += v.Count
|
||||
}
|
||||
for _, v := range order.Skus {
|
||||
orderCount += v.Count
|
||||
}
|
||||
//如果售后退款的商品数等于订单商品数,我就当是全部退款了
|
||||
if afsCount == orderCount && order.VendorID == model.VendorIDMTWM {
|
||||
order.DeliveryFlag |= model.OrderDeliveryFlagMaskScheduleDisabled
|
||||
partner.CurOrderManager.UpdateOrderFields(order, []string{"DeliveryFlag"})
|
||||
for _, v := range waybills {
|
||||
c.CancelWaybill(v, partner.CancelWaybillReasonOther, ctx.GetUserName()+":11"+partner.CancelWaybillReasonStrActive)
|
||||
}
|
||||
}
|
||||
if afsCount == orderCount && order.VendorID == model.VendorIDJX {
|
||||
order.DeliveryFlag |= model.OrderDeliveryFlagMaskScheduleDisabled
|
||||
order.Status = model.OrderStatusCanceled
|
||||
order.VendorStatus = utils.Int2Str(model.OrderStatusCanceled)
|
||||
partner.CurOrderManager.UpdateOrderFields(order, []string{"DeliveryFlag", "Status", "VendorStatus"})
|
||||
}
|
||||
if afsCount == orderCount && order.VendorID == model.VendorIDEBAI {
|
||||
order.DeliveryFlag |= model.OrderDeliveryFlagMaskScheduleDisabled
|
||||
order.Status = model.OrderStatusCanceled
|
||||
order.VendorStatus = "10" // 饿百取消订单
|
||||
partner.CurOrderManager.UpdateOrderFields(order, []string{"DeliveryFlag", "Status", "VendorStatus"})
|
||||
for _, v := range waybills {
|
||||
c.CancelWaybill(v, partner.CancelWaybillReasonOther, ctx.GetUserName()+":12"+partner.CancelWaybillReasonStrActive)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if order.EarningType == model.EarningTypePoints {
|
||||
var (
|
||||
skuMap = make(map[int]*model.OrderSku)
|
||||
diff int64
|
||||
)
|
||||
for _, sku := range order.Skus {
|
||||
skuMap[sku.SkuID] = sku
|
||||
}
|
||||
//京东商城和京西要重新算totalshopmoney等
|
||||
if order.VendorID == model.VendorIDJDShop || order.VendorID == model.VendorIDJX {
|
||||
skus, _ := dao.GetAfsOrderSkuInfo(db, order.VendorOrderID, afsOrderID, order.VendorID, false)
|
||||
for _, v := range skus {
|
||||
if skuMap[v.SkuID] != nil {
|
||||
diff += skuMap[v.SkuID].SalePrice * int64(v.Count)
|
||||
}
|
||||
}
|
||||
order.TotalShopMoney = utils.Float64TwoInt64(float64(float64(order.TotalShopMoney)/jdshopapi.JdsPayPercentage-float64(diff)) * jdshopapi.JdsPayPercentage)
|
||||
if len(waybills) > 0 {
|
||||
jxutils.RefreshOrderEarningPrice3(order, order.OrderPayPercentage, waybills[0])
|
||||
} else {
|
||||
jxutils.RefreshOrderEarningPrice2(order, order.OrderPayPercentage)
|
||||
}
|
||||
dao.UpdateEntity(db, order, "TotalShopMoney", "NewEarningPrice")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
dao.SetAfsOrderFlag(dao.GetDB(), ctx.GetUserName(), afsOrderID, vendorID, flag)
|
||||
}
|
||||
}
|
||||
//if approveType != partner.AfsApproveTypeRefused && err == nil {
|
||||
// storeDetail, err := partner.CurOrderManager.LoadStoreDetail(afsOrder.StoreID, afsOrder.VendorID)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// if storeDetail.IsPrintRefundOrder == model.YES { // 打印退款订单
|
||||
// order2, _ := partner.CurOrderManager.LoadOrder(afsOrder.VendorOrderID, afsOrder.VendorID)
|
||||
// order2.Status = model.AfsOrderStatusFinished
|
||||
// _, err = netprinter.PrintRefundOrCancelOrder(jxcontext.AdminCtx, model.NO, order2, afsOrder.StoreID)
|
||||
// }
|
||||
//}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) ConfirmReceivedReturnGoods(ctx *jxcontext.Context, afsOrderID string, vendorID int) (err error) {
|
||||
afsOrder, err := partner.CurOrderManager.LoadAfsOrder(afsOrderID, vendorID)
|
||||
if err == nil {
|
||||
if c.IsReallyCallPlatformAPI {
|
||||
err = partner.GetPurchaseOrderHandlerFromVendorID(vendorID).ConfirmReceivedReturnGoods(ctx, afsOrder)
|
||||
}
|
||||
if err == nil {
|
||||
dao.SetAfsOrderFlag(dao.GetDB(), ctx.GetUserName(), afsOrderID, vendorID, model.AfsOrderFlagMaskReturnGoods)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) PartRefundOrder(ctx *jxcontext.Context, order *model.GoodsOrder, refundSkuList []*model.OrderSku, reason string) (err error) {
|
||||
if c.IsReallyCallPlatformAPI {
|
||||
err = partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID).PartRefundOrder(ctx, order, refundSkuList, reason)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) RefundOrder(ctx *jxcontext.Context, order *model.GoodsOrder, reason string) (err error) {
|
||||
if c.IsReallyCallPlatformAPI {
|
||||
err = partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID).RefundOrder(ctx, order, reason)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) ConfirmSelfTake(ctx *jxcontext.Context, vendorOrderID string, vendorID int, selfTakeCode string) (err error) {
|
||||
order, err2 := partner.CurOrderManager.LoadOrder(vendorOrderID, vendorID)
|
||||
if err = err2; err == nil {
|
||||
err = c.confirmSelfTake(ctx, order, selfTakeCode)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) SetOrderWaybillTip(ctx *jxcontext.Context, vendorOrderID string, vendorID int, tipFee int64, isPay int) (errCode string, err error) {
|
||||
order, err := partner.CurOrderManager.LoadOrder(vendorOrderID, vendorID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
errCode, err = c.CheckStoreBalanceWithTip(ctx, order, tipFee, isPay)
|
||||
if err != nil {
|
||||
return errCode, err
|
||||
}
|
||||
err = c.SetOrderWaybillTipByOrder(ctx, order, tipFee)
|
||||
return errCode, err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) CheckStoreBalanceWithTip(ctx *jxcontext.Context, order *model.GoodsOrder, tipFee int64, isPay int) (errCode string, err error) {
|
||||
var (
|
||||
db = dao.GetDB()
|
||||
)
|
||||
roundTipFee := tipFee / 100 * 100
|
||||
if roundTipFee != tipFee {
|
||||
return model.ErrCodeOnePayTipFeeMore, fmt.Errorf("小费必须是1元的整数倍")
|
||||
}
|
||||
//if order.WaybillTipMoney >= tipFee {
|
||||
// return model.ErrCodeOnePayTipFeeMore, fmt.Errorf("本次小费金额不能小于已经支付的小费")
|
||||
//}
|
||||
if order.CreateDeliveryType == model.YES {
|
||||
//加小费只判断余额
|
||||
storeAcct, err := cms.GetStoreAcctBalance(ctx, jxutils.GetSaleStoreIDFromOrder(order))
|
||||
if err != nil {
|
||||
return errCode, fmt.Errorf("获取账户余额失败!")
|
||||
}
|
||||
if tipFee > int64(storeAcct.AccountBalance) {
|
||||
return model.ErrCodeAccountBalanceNotEnough, fmt.Errorf("门店账户余额不足,不能加小费!")
|
||||
}
|
||||
if tipFee > 1000 {
|
||||
return model.ErrCodeAccountBalanceNotEnough, fmt.Errorf("小费单次加价金额大于十元")
|
||||
}
|
||||
} else {
|
||||
// 品牌发单
|
||||
storeDetail, err := dao.GetStoreDetail(db, order.JxStoreID, order.VendorID, order.VendorOrgCode)
|
||||
if err != nil || storeDetail == nil {
|
||||
return model.ErrCodeAccountBalanceNotEnough, fmt.Errorf("根据订单获取门店详情错误:%v", err)
|
||||
}
|
||||
|
||||
brandAcct, err := dao.GetBrandBalance(db, storeDetail.BrandID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if tipFee > int64(brandAcct) {
|
||||
return model.ErrCodeAccountBalanceNotEnough, fmt.Errorf("品牌账户余额不足,不能加小费!")
|
||||
}
|
||||
if tipFee > 1000 {
|
||||
return model.ErrCodeOnePayTipFeeMore, fmt.Errorf("小费单次加价金额大于十元")
|
||||
}
|
||||
}
|
||||
// 是否确认支付
|
||||
if isPay != model.YES {
|
||||
return model.ErrCodeIsPaySure, fmt.Errorf("此订单已经支付小费[%d]元,本次增加小费[%d]元,总支出小费[%d]元", order.WaybillTipMoney/100, tipFee/100, (order.WaybillTipMoney+tipFee)/100)
|
||||
}
|
||||
|
||||
return errCode, err
|
||||
}
|
||||
|
||||
func isWaybillCanAddTip(waybill *model.Waybill) (isCan bool) {
|
||||
isCan = waybill.Status >= model.WaybillStatusNew && waybill.Status < model.WaybillStatusAccepted && partner.GetWaybillTipUpdater(waybill.WaybillVendorID) != nil
|
||||
return isCan
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) SetOrderWaybillTipByOrder(ctx *jxcontext.Context, order *model.GoodsOrder, tipFee int64) (err error) {
|
||||
db := dao.GetDB()
|
||||
thisTimeTipFee := tipFee - order.WaybillTipMoney
|
||||
storeDetail, _ := dao.GetStoreDetail(db, jxutils.GetSaleStoreIDFromOrder(order), order.VendorID, "")
|
||||
flag := false
|
||||
// 如果平台支持设置配送小费,必须要成功设置
|
||||
if handler := partner.GetWaybillTipUpdater(order.VendorID); handler != nil {
|
||||
if err = handler.UpdateWaybillTip(ctx, order.VendorOrgCode, order.VendorStoreID, order.VendorOrderID, "", "", utils.Int2Str(storeDetail.CityCode), thisTimeTipFee); err != nil {
|
||||
globals.SugarLogger.Debugf("订单id[%s],平台id[%d],427,err :[%v]", order.VendorOrderID, order.VendorID, err)
|
||||
} else {
|
||||
//加小费成功扣钱
|
||||
if order.CreateDeliveryType == model.YES {
|
||||
if err = partner.CurStoreAcctManager.InsertStoreAcctExpendAndUpdateStoreAcctBalance(ctx, jxutils.GetSaleStoreIDFromOrder(order), int(thisTimeTipFee), partner.StoreAcctTypeExpendCreateWaybillTip, order.VendorOrderID, "", 0); err == nil {
|
||||
flag = true
|
||||
}
|
||||
} else if order.CreateDeliveryType == model.NO {
|
||||
if err = partner.CurStoreAcctManager.InsertBrandBill(ctx, storeDetail.BrandID, int(thisTimeTipFee), model.BrandBillTypeExpend, model.BrandBillFeeTypeTipFee, order.VendorOrderID, ""); err == nil {
|
||||
flag = true
|
||||
}
|
||||
}
|
||||
}
|
||||
} //有可能进else,没加得起平台小费,就要到下面扣账户
|
||||
|
||||
order.WaybillTipMoney = tipFee
|
||||
partner.CurOrderManager.UpdateOrderFields(order, []string{"WaybillTipMoney"})
|
||||
|
||||
waybills, err := dao.GetWayBillByOrderID(db, 0, order.VendorID, 0, order.VendorOrderID)
|
||||
if err == nil {
|
||||
var waybills2 []*model.Waybill
|
||||
for _, v := range waybills {
|
||||
// 必须是三方配送
|
||||
if !model.IsWaybillPlatformOwn(v) && isWaybillCanAddTip(v) {
|
||||
waybills2 = append(waybills2, v)
|
||||
}
|
||||
}
|
||||
if len(waybills2) > 0 {
|
||||
task := tasksch.NewParallelTask("SetOrderWaybillTipByOrder", nil, ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
waybill := batchItemList[0].(*model.Waybill)
|
||||
handler := partner.GetWaybillTipUpdater(waybill.WaybillVendorID)
|
||||
if waybill.WaybillVendorID == model.VendorIDDada {
|
||||
err = handler.UpdateWaybillTip(ctx, waybill.VendorOrgCode, storeDetail.VendorStoreID, waybill.VendorOrderID, waybill.VendorWaybillID, waybill.VendorWaybillID2, utils.Int2Str(storeDetail.CityCode), tipFee)
|
||||
globals.SugarLogger.Debugf("订单id[%s],平台id[%d],462,err :[%v]", order.VendorOrderID, order.VendorID, err)
|
||||
} else {
|
||||
err = handler.UpdateWaybillTip(ctx, waybill.VendorOrgCode, storeDetail.VendorStoreID, waybill.VendorOrderID, waybill.VendorWaybillID, waybill.VendorWaybillID2, utils.Int2Str(storeDetail.CityCode), thisTimeTipFee)
|
||||
globals.SugarLogger.Debugf("订单id[%s],平台id[%d],465,err :[%v]", order.VendorOrderID, order.VendorID, err)
|
||||
}
|
||||
return nil, err
|
||||
}, waybills2)
|
||||
tasksch.HandleTask(task, nil, false).Run()
|
||||
_, err = task.GetResult(0)
|
||||
if err == nil {
|
||||
//加起了至少只扣一次钱
|
||||
if !flag {
|
||||
//加小费成功扣钱
|
||||
if order.CreateDeliveryType == model.YES {
|
||||
partner.CurStoreAcctManager.InsertStoreAcctExpendAndUpdateStoreAcctBalance(ctx, jxutils.GetSaleStoreIDFromOrder(order), int(thisTimeTipFee), partner.StoreAcctTypeExpendCreateWaybillTip, order.VendorOrderID, "", 0)
|
||||
} else if order.CreateDeliveryType == model.NO {
|
||||
partner.CurStoreAcctManager.InsertBrandBill(ctx, storeDetail.BrandID, int(thisTimeTipFee), model.BrandBillTypeExpend, model.BrandBillFeeTypeTipFee, order.VendorOrderID, "")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) confirmSelfTake(ctx *jxcontext.Context, order *model.GoodsOrder, selfTakeCode string) (err error) {
|
||||
vendorID := order.VendorID
|
||||
// if vendorID == model.VendorIDJD || vendorID == model.VendorIDJX {
|
||||
if vendorID != model.VendorIDJX {
|
||||
handler := partner.GetPurchaseOrderHandlerFromVendorID(vendorID)
|
||||
if selfTakeCode == autoSelfTakeCode {
|
||||
if selfTakeCode, err = handler.GetSelfTakeCode(ctx, order); err != nil {
|
||||
return fmt.Errorf("获取订单:%s自提货码失败,原始错误:%s", order.VendorOrderID, err.Error())
|
||||
}
|
||||
if selfTakeCode == "" {
|
||||
return fmt.Errorf("订单:%s 自动提货失败,请手动输入自提码", order.VendorOrderID)
|
||||
}
|
||||
}
|
||||
err = handler.ConfirmSelfTake(ctx, order, selfTakeCode)
|
||||
} else {
|
||||
if selfTakeCode != order.ConsigneeMobile && selfTakeCode != order.VendorOrderID[len(order.VendorOrderID)-4:] {
|
||||
return fmt.Errorf("京西平台自提单,自提码为订单后四位或完整的下单电话")
|
||||
}
|
||||
orderStatus := &model.OrderStatus{
|
||||
VendorOrderID: order.VendorOrderID,
|
||||
VendorID: model.VendorIDJX,
|
||||
OrderType: model.OrderTypeOrder,
|
||||
RefVendorOrderID: order.VendorOrderID,
|
||||
RefVendorID: model.VendorIDJX,
|
||||
VendorStatus: utils.Int2Str(model.OrderStatusFinished),
|
||||
Status: model.OrderStatusFinished,
|
||||
StatusTime: time.Now(),
|
||||
Remark: "自提完成",
|
||||
}
|
||||
jxutils.CallMsgHandlerAsync(func() {
|
||||
err = partner.CurOrderManager.OnOrderStatusChanged("", orderStatus)
|
||||
}, jxutils.ComposeUniversalOrderID(order.VendorOrderID, model.VendorIDJX))
|
||||
}
|
||||
// } else {
|
||||
// err = fmt.Errorf("自提核销不支持%s平台订单", model.VendorChineseNames[order.VendorID])
|
||||
// }
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *BaseScheduler) ConfirmSelfTakeOrders(ctx *jxcontext.Context, vendorIDs []int, orderCreatedAfter, orderCreatedBefore time.Time, isAsync, isContinueWhenError bool) (hint string, err error) {
|
||||
orderList, err := dao.GetPendingFakeOrders(dao.GetDB(), vendorIDs, orderCreatedAfter, orderCreatedBefore)
|
||||
if err == nil {
|
||||
if len(orderList) > 0 {
|
||||
task := tasksch.NewParallelTask(fmt.Sprintf("自动完成内部自提单%v,%s", vendorIDs, utils.Time2Str(orderCreatedAfter)), tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError), ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
order := batchItemList[0].(*model.GoodsOrder)
|
||||
if order.Status == model.OrderStatusAccepted {
|
||||
if handler := partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID); handler != nil {
|
||||
err = handler.AcceptOrRefuseOrder(order, true, ctx.GetUserName())
|
||||
time.Sleep(2 * time.Second)
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
if err = c.confirmSelfTake(ctx, order, autoSelfTakeCode); err == nil {
|
||||
retVal = []int{1}
|
||||
}
|
||||
}
|
||||
return retVal, err
|
||||
}, orderList)
|
||||
tasksch.HandleTask(task, nil, true).Run()
|
||||
if isAsync {
|
||||
hint = task.GetID()
|
||||
} else {
|
||||
resultList, err2 := task.GetResult(0)
|
||||
if err = err2; err == nil {
|
||||
hint = utils.Int2Str(len(resultList))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return hint, err
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,90 +0,0 @@
|
||||
package defsch
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/netprinter"
|
||||
push "git.rosy.net.cn/jx-callback/business/jxutils/unipush"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/weixinmsg"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/msghub"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
)
|
||||
|
||||
var (
|
||||
autoRejectSkuMap = map[int]int{
|
||||
33996: 1,
|
||||
33995: 1,
|
||||
33994: 1,
|
||||
33991: 1,
|
||||
}
|
||||
)
|
||||
|
||||
func (s *DefScheduler) OnAfsOrderNew(order *model.AfsOrder, isPending bool) (err error) {
|
||||
if order.Status == model.AfsOrderStatusWait4Approve {
|
||||
if !isPending {
|
||||
if isAutoRejectAfsOrder(order) {
|
||||
if handler := partner.GetPurchaseOrderHandlerFromVendorID(order.VendorID); handler != nil {
|
||||
if err := handler.AgreeOrRefuseRefund(jxcontext.AdminCtx, order, partner.AfsApproveTypeRefused, "抱歉,蟹券不接受退货或换货"); err != nil {
|
||||
globals.SugarLogger.Debugf("OnAfsOrderNew, orderID:%s, afsOrderID:%s failed with err:%v", order.VendorOrderID, order.AfsOrderID, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if order != nil && order.VendorID == model.VendorIDTaoVegetable {
|
||||
result, _ := dao.GetAfsOrders(dao.GetDB(), model.VendorIDTaoVegetable, order.VendorOrderID, "")
|
||||
if len(result) <= model.YES {
|
||||
msghub.OnNewWait4ApproveAfsOrder(order)
|
||||
weixinmsg.NotifyAfsOrderStatus(order)
|
||||
push.NotifyAfsOrder(order)
|
||||
}
|
||||
} else {
|
||||
msghub.OnNewWait4ApproveAfsOrder(order)
|
||||
weixinmsg.NotifyAfsOrderStatus(order)
|
||||
push.NotifyAfsOrder(order)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
storeDetail, err := partner.CurOrderManager.LoadStoreDetail(order.JxStoreID, order.VendorID)
|
||||
if err == nil {
|
||||
if storeDetail.IsPrintRefundOrder == model.YES { // 打印退款订单
|
||||
order2, _ := partner.CurOrderManager.LoadOrder(order.VendorOrderID, order.VendorID)
|
||||
_, err = netprinter.PrintRefundOrCancelOrder(jxcontext.AdminCtx, model.NO, order2, order2.JxStoreID)
|
||||
}
|
||||
}
|
||||
|
||||
//if order.Status == model.AfsOrderStatusWait4Approve || order.Status == model.AfsOrderStatusFinished || order.Status == model.AfsOrderStatusNew {
|
||||
// // 京西云打印机打印数据-如果门店使用京西打印机才使用如下代码块
|
||||
// store, err := dao.GetStoreDetail(dao.GetDB(), order.JxStoreID, order.VendorID, order.VendorOrgCode)
|
||||
// if err == nil && store.PrinterVendorID == model.VendorIDJxprint && store.IsPrintCancelOrder == model.YES {
|
||||
// orderObj, _ := partner.CurOrderManager.LoadOrder(order.VendorOrderID, order.VendorID)
|
||||
// if orderObj != nil {
|
||||
// netprinter.PrintOrderByOrder(jxcontext.AdminCtx, orderObj, model.PrintAfsOrder, order)
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *DefScheduler) OnAfsOrderStatusChanged(order *model.AfsOrder, status *model.OrderStatus, isPending bool) (err error) {
|
||||
if status.Status == model.AfsOrderStatusWait4ReceiveGoods {
|
||||
if !isPending {
|
||||
msghub.OnKeyAfsOrderStatusChanged(order)
|
||||
weixinmsg.NotifyAfsOrderStatus(order)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func isAutoRejectAfsOrder(order *model.AfsOrder) (isReject bool) {
|
||||
for _, v := range order.Skus {
|
||||
if autoRejectSkuMap[jxutils.GetSkuIDFromOrderSkuFinancial(v)] == 1 {
|
||||
isReject = true
|
||||
break
|
||||
}
|
||||
}
|
||||
return isReject
|
||||
}
|
||||
@@ -1,591 +0,0 @@
|
||||
package defsch
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"git.rosy.net.cn/baseapi/platformapi/mtwmapi"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxstore/cms"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
beego "github.com/astaxie/beego/server/web"
|
||||
"math"
|
||||
"math/rand"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/jxcallback/scheduler"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
)
|
||||
|
||||
func (s *DefScheduler) loadSavedOrderByID(vendorOrderID string, vendorID int, isForceLoad bool) *WatchOrderInfo {
|
||||
return s.loadSavedOrderFromMap(&model.OrderStatus{
|
||||
RefVendorOrderID: vendorOrderID,
|
||||
RefVendorID: vendorID,
|
||||
}, isForceLoad)
|
||||
}
|
||||
|
||||
func (s *DefScheduler) SelfDeliveringAndUpdateStatus(ctx *jxcontext.Context, vendorOrderID string, vendorID int, userName, courierName, courierMobile string) (err error) {
|
||||
var order *model.GoodsOrder
|
||||
jxutils.CallMsgHandler(func() {
|
||||
err = func() (err error) {
|
||||
savedOrderInfo := s.loadSavedOrderByID(vendorOrderID, vendorID, true)
|
||||
if savedOrderInfo != nil {
|
||||
order = savedOrderInfo.order
|
||||
if err = s.isPossibleSwitch2SelfDelivery(order); err == nil { // 是否能转自送
|
||||
err = s.cancelOtherWaybillsCheckOrderDeliveryFlag(savedOrderInfo, nil, partner.CancelWaybillReasonOther, ctx.GetUserName()+"17"+partner.CancelWaybillReasonStrActive)
|
||||
if err == nil {
|
||||
if model.IsOrderDeliveryByStore(order) {
|
||||
if order.Status < model.OrderStatusDelivering {
|
||||
storeDetail, err2 := dao.GetStoreDetail(dao.GetDB(), order.StoreID, order.VendorID, "")
|
||||
phone := userName
|
||||
if err = err2; err == nil {
|
||||
phone = storeDetail.Tel1
|
||||
}
|
||||
err = s.SelfDeliverDelivering(order, phone) // 取消平台自配送
|
||||
s.CancelAll3rdWaybills(ctx, vendorOrderID, vendorID, true) // 取消三方平台配送以及调度
|
||||
}
|
||||
} else {
|
||||
if order.Status < model.OrderStatusDelivering {
|
||||
err = s.Swtich2SelfDeliver(order, userName)
|
||||
} else if order.VendorID == order.WaybillVendorID { // 状态为配送中,且是购物平台运单,不能转自送了
|
||||
err = scheduler.ErrOrderStatusIsNotSuitable4CurOperation
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
order.Status = model.OrderStatusDelivering
|
||||
order.DeliveryFlag |= model.OrderDeliveryFlagMaskScheduleDisabled | model.OrderDeliveryFlagMaskPurcahseDisabled
|
||||
if err = partner.CurOrderManager.UpdateOrderStatusAndDeliveryFlag(order); err == nil {
|
||||
s.stopTimer(savedOrderInfo)
|
||||
//return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
order = &model.GoodsOrder{
|
||||
VendorOrderID: vendorOrderID,
|
||||
VendorID: vendorID,
|
||||
}
|
||||
err = scheduler.ErrCanNotFindOrder
|
||||
}
|
||||
vendorStatus := fmt.Sprintf("%s转商户自送成功", ctx.GetUserName())
|
||||
remark := ""
|
||||
if err != nil {
|
||||
vendorStatus = fmt.Sprintf("%s转商户自送失败", ctx.GetUserName())
|
||||
remark = err.Error()
|
||||
partner.CurOrderManager.OnOrderMsg(order, vendorStatus, remark)
|
||||
return err
|
||||
} else {
|
||||
partner.CurOrderManager.OnOrderMsg(order, vendorStatus, remark)
|
||||
}
|
||||
|
||||
// 上面是真的转自送,支持美团,饿百,京东,如果时抖店,抖店暂时全部是自送的!但是有骑手信息时,就是一个白嫖单子!
|
||||
if courierName != "" && courierMobile != "" && err == nil {
|
||||
timeNow := time.Now()
|
||||
rand.Seed(timeNow.UnixNano())
|
||||
randNumber := rand.Int63n(640)
|
||||
if randNumber < 60 {
|
||||
randNumber += 60
|
||||
}
|
||||
randTime := time.Duration(randNumber) * time.Second
|
||||
bill := &model.Waybill{
|
||||
VendorWaybillID: order.VendorOrderID,
|
||||
VendorWaybillID2: "",
|
||||
WaybillVendorID: model.VendorJXFakeWL,
|
||||
VendorOrderID: order.VendorOrderID,
|
||||
OrderVendorID: order.VendorID,
|
||||
CourierName: courierName,
|
||||
CourierMobile: courierMobile,
|
||||
Status: model.OrderStatusNew,
|
||||
VendorStatus: utils.Int2Str(model.OrderStatusNew),
|
||||
ActualFee: 0,
|
||||
DesiredFee: 0,
|
||||
TipFee: 0,
|
||||
DuplicatedCount: 0,
|
||||
DeliveryFlag: 0,
|
||||
WaybillCreatedAt: timeNow,
|
||||
WaybillFinishedAt: utils.DefaultTimeValue,
|
||||
StatusTime: timeNow.Add(randTime), // 下一状态时间
|
||||
OriginalData: "",
|
||||
Remark: "自定义物流单(全平台刷单)",
|
||||
VendorOrgCode: order.VendorOrgCode,
|
||||
}
|
||||
err = dao.CreateEntity(dao.GetDB(), bill)
|
||||
//if order.VendorID == model.VendorIDTaoVegetable {
|
||||
// order.VendorWaybillID = order.VendorOrderID
|
||||
// order.WaybillVendorID = model.VendorJXFakeWL
|
||||
// dao.UpdateEntity(dao.GetDB(), order, "VendorWaybillID", "WaybillVendorID")
|
||||
//}
|
||||
}
|
||||
return err
|
||||
}()
|
||||
}, jxutils.ComposeUniversalOrderID(vendorOrderID, vendorID))
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *DefScheduler) canOrderCreateWaybillNormally(order *model.GoodsOrder, savedOrderInfo *WatchOrderInfo) (err error) {
|
||||
if !(order.LockStatus != model.OrderStatusLocked && order.Status >= model.OrderStatusFinishedPickup && order.Status < model.OrderStatusEndBegin) {
|
||||
err = fmt.Errorf("当前订单%s没有处于拣货完成且没有结束没有锁定的订单才能进行召唤配送操作", order.VendorOrderID)
|
||||
} else if model.IsOrderHaveWaybill(order) {
|
||||
err = fmt.Errorf("当前订单%s已经有了有效的承运人%s了", order.VendorOrderID, jxutils.GetVendorName(order.WaybillVendorID))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *DefScheduler) isPossibleSwitch2SelfDelivery(order *model.GoodsOrder) (err error) {
|
||||
//TODO 刷单用,之后不刷单了删除
|
||||
//if order.VendorID == model.VendorIDDD {
|
||||
// return nil
|
||||
//}
|
||||
|
||||
if model.IsOrderDeliveryByPlatform(order) {
|
||||
if order.Status < model.OrderStatusFinishedPickup {
|
||||
err = fmt.Errorf("拣货完成后才能转自配送")
|
||||
} else if order.Status == model.OrderStatusFinishedPickup {
|
||||
if time.Now().Sub(order.StatusTime) < minMinute2Schedule3rdCarrier*time.Minute {
|
||||
err = fmt.Errorf("非自配送门店转3方配送至少要求拣货完成后%d分钟才能操作", minMinute2Schedule3rdCarrier)
|
||||
}
|
||||
} else if order.Status >= model.OrderStatusDelivering && order.Status < model.OrderStatusEndBegin {
|
||||
if model.IsOrderHaveOwnWaybill(order) {
|
||||
err = fmt.Errorf("%s物流已在配送中,不能转自配送", jxutils.GetVendorName(order.VendorID))
|
||||
}
|
||||
} else if order.Status >= model.OrderStatusEndBegin {
|
||||
err = fmt.Errorf("订单%s已经结束,请刷新状态", order.VendorOrderID)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// 创建订单
|
||||
func (s *DefScheduler) CreateWaybillOnProviders4SavedOrder(ctx *jxcontext.Context, savedOrderInfo *WatchOrderInfo, courierVendorIDs, excludeCourierVendorIDs []int, forceCreate bool, maxDeliveryFee int64) (bills []*model.Waybill, err error) {
|
||||
order := savedOrderInfo.order
|
||||
// 查看订单状态是否处于可配送状态
|
||||
if !forceCreate {
|
||||
err = s.canOrderCreateWaybillNormally(order, nil)
|
||||
}
|
||||
// 检查订单是否在配送状态
|
||||
waybills, err := dao.GetWaybills(dao.GetDB(), order.VendorOrderID, nil)
|
||||
for _, v := range waybills {
|
||||
if v.Status >= model.OrderStatusDelivering && v.Status != model.OrderStatusCanceled && v.Status != model.OrderStatusFinished {
|
||||
err = fmt.Errorf("订单已经在配送中,无法创建运单,有疑问请联系管理员")
|
||||
break
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
if forceCreate {
|
||||
maxDeliveryFee = math.MaxInt64
|
||||
}
|
||||
// 生成美团订单(三方订单)
|
||||
if bills, err = s.CreateWaybillOnProviders(ctx, order, courierVendorIDs, excludeCourierVendorIDs, maxDeliveryFee, forceCreate); err == nil {
|
||||
if forceCreate {
|
||||
order.DeliveryFlag |= model.OrderDeliveryFlagMaskScheduleDisabled
|
||||
err = partner.CurOrderManager.UpdateOrderStatusAndDeliveryFlag(order)
|
||||
}
|
||||
if err == nil {
|
||||
if forceCreate {
|
||||
s.stopTimer(savedOrderInfo)
|
||||
}
|
||||
|
||||
// 获取门店品牌余额
|
||||
storeAcct, err := cms.GetStoreAcctBalance(ctx, jxutils.GetSaleStoreIDFromOrder(order)) // 获取门店余额
|
||||
|
||||
// 门店详细信息
|
||||
storeList, err := dao.GetStoreDetail(dao.GetDB(), jxutils.GetSaleStoreIDFromOrder(order), savedOrderInfo.order.VendorID, order.VendorOrgCode)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
deliveryFeeMap, _ := s.QueryOrderWaybillFeeInfoEx(ctx, order.VendorOrderID, order.VendorID)
|
||||
// 不管是门店发单还是品牌发单都要扣钱,门店发单扣门店,品牌发单扣品牌
|
||||
if order.CreateDeliveryType == model.YES {
|
||||
// 获取平台配送费
|
||||
isEqual, isZero, _ := partner.CurStoreAcctManager.CheckStoreAcctExpendExist(order.VendorOrderID) // 当前订单的支出记录
|
||||
expend, lastFee, _ := partner.CurStoreAcctManager.GetStoreAcctExpendLastCreateWayBillFee(order.VendorOrderID) // 最后一个运单支出记录
|
||||
// 收最贵的一个订单配送费(配送费发送变化,收取最贵的价格)
|
||||
if !isZero && !isEqual { // 满足此条件是,门店发单已经存在此订单的发单记录,且支出记录大于退还记录
|
||||
var newPrice int64
|
||||
if len(courierVendorIDs) == 1 {
|
||||
courierVendorID := courierVendorIDs[0]
|
||||
if _, ok := deliveryFeeMap[courierVendorID]; ok {
|
||||
newPrice = deliveryFeeMap[courierVendorID].DeliveryFee
|
||||
}
|
||||
} else if len(courierVendorIDs) == 0 {
|
||||
var maxFee int64
|
||||
for _, v := range deliveryFeeMap {
|
||||
if v.DeliveryFee > maxFee {
|
||||
maxFee = v.DeliveryFee
|
||||
}
|
||||
}
|
||||
newPrice = maxFee
|
||||
}
|
||||
// 门店支出运费,门店发单
|
||||
if order.CreateDeliveryType == model.YES {
|
||||
if storeAcct.AccountBalance > int(newPrice) {
|
||||
if int(newPrice) > lastFee {
|
||||
// 门店支出费用
|
||||
partner.CurStoreAcctManager.InsertStoreAcctExpendAndUpdateStoreAcctBalance(ctx, jxutils.GetSaleStoreIDFromOrder(order), int(newPrice)-lastFee, partner.StoreAcctTypeExpendCreateWaybill2ndMore, order.VendorOrderID, "", expend.ID) //int(newPrice)-lastFee
|
||||
}
|
||||
}
|
||||
}
|
||||
} else { // 新订单的发单记录,门店发单扣门店,品牌发单扣品牌
|
||||
if len(courierVendorIDs) == 1 {
|
||||
courierVendorID := courierVendorIDs[0]
|
||||
if _, ok := deliveryFeeMap[courierVendorID]; ok {
|
||||
if order.CreateDeliveryType == model.YES {
|
||||
err = partner.CurStoreAcctManager.InsertStoreAcctExpendAndUpdateStoreAcctBalance(ctx, jxutils.GetSaleStoreIDFromOrder(order), int(deliveryFeeMap[courierVendorID].DeliveryFee), partner.StoreAcctTypeExpendCreateWaybillEx, order.VendorOrderID, "", 0) //int(newPrice)-lastFee
|
||||
}
|
||||
}
|
||||
} else if len(courierVendorIDs) == 0 {
|
||||
var maxFee int64
|
||||
for _, v := range deliveryFeeMap {
|
||||
if v.DeliveryFee > maxFee {
|
||||
maxFee = v.DeliveryFee
|
||||
}
|
||||
}
|
||||
err = partner.CurStoreAcctManager.InsertStoreAcctExpendAndUpdateStoreAcctBalance(ctx, jxutils.GetSaleStoreIDFromOrder(order), int(maxFee), partner.StoreAcctTypeExpendCreateWaybillEx, order.VendorOrderID, "", 0) //int(maxFee)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 看看此订单有无发单记录,小费记录
|
||||
// 品牌发单
|
||||
if len(courierVendorIDs) == 1 {
|
||||
courierVendorID := courierVendorIDs[0]
|
||||
if _, ok := deliveryFeeMap[courierVendorID]; ok {
|
||||
err = partner.CurStoreAcctManager.InsertBrandBill(jxcontext.AdminCtx, storeList.BrandID, int(deliveryFeeMap[courierVendorID].DeliveryFee), model.BrandBillTypeExpend, model.BrandBillFeeTypeDelivery, order.VendorOrderID, order.VendorWaybillID)
|
||||
}
|
||||
} else if len(courierVendorIDs) == 0 {
|
||||
var maxFee int64
|
||||
for _, v := range deliveryFeeMap {
|
||||
if v.DeliveryFee > maxFee {
|
||||
maxFee = v.DeliveryFee
|
||||
}
|
||||
}
|
||||
err = partner.CurStoreAcctManager.InsertBrandBill(jxcontext.AdminCtx, storeList.BrandID, int(maxFee), model.BrandBillTypeExpend, model.BrandBillFeeTypeDelivery, order.VendorOrderID, order.VendorWaybillID)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return bills, err
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
globals.SugarLogger.Debugf("CreateWaybillOnProviders4SavedOrder orderID:%s failed with error:%v", order.VendorOrderID, err)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 创建三方运单
|
||||
func (s *DefScheduler) CreateWaybillOnProvidersEx(ctx *jxcontext.Context, vendorOrderID string, vendorID int, courierVendorIDs []int, forceCreate bool, maxDeliveryFee int64) (bills []*model.Waybill, errCode string, err error) {
|
||||
savedOrderInfo := s.loadSavedOrderByID(vendorOrderID, vendorID, true)
|
||||
if savedOrderInfo != nil {
|
||||
order := savedOrderInfo.order
|
||||
//1表示为门店发单,需要验证门店账户余额情况
|
||||
if errCode, err = s.CheckStoreBalance(ctx, order, courierVendorIDs); err != nil {
|
||||
return nil, errCode, err
|
||||
}
|
||||
}
|
||||
excludeCourierVendorIDs := make([]int, 0, 0)
|
||||
allDelivery := map[int]int{model.VendorIDFengNiao: 1, model.VendorIDDada: 1, model.VendorIDMTPS: 1, model.VendorIDUUPT: 1, model.VendorIDSFPS: 1}
|
||||
for _, v := range courierVendorIDs {
|
||||
if allDelivery[v] == model.YES {
|
||||
delete(allDelivery, v)
|
||||
}
|
||||
}
|
||||
for k, _ := range allDelivery {
|
||||
excludeCourierVendorIDs = append(excludeCourierVendorIDs, k)
|
||||
}
|
||||
|
||||
billFunc := func() {
|
||||
bills, err = func() (bills []*model.Waybill, err error) {
|
||||
if vendorID == model.VendorIDELM {
|
||||
return nil, fmt.Errorf("不要直接使用饿了么订单号,请使用相应的饿百订单号")
|
||||
}
|
||||
// 创建可调度对象,并且存储
|
||||
savedOrderInfo := s.loadSavedOrderByID(vendorOrderID, vendorID, true)
|
||||
if savedOrderInfo != nil {
|
||||
savedOrderInfo.order.SendOrderType = 1 // 设置为手动创建订单
|
||||
order := savedOrderInfo.order
|
||||
if order.DeliveryType == model.OrderDeliveryTypeSelfTake {
|
||||
return nil, fmt.Errorf("订单:%s是自提单", vendorOrderID)
|
||||
}
|
||||
if !forceCreate {
|
||||
err = s.isPossibleSwitch2SelfDelivery(order)
|
||||
}
|
||||
if err == nil {
|
||||
if savedOrderInfo.order.VendorID == model.VendorIDEBAI {
|
||||
courierVendorIDs = []int{model.VendorIDMTPS, model.VendorIDDada}
|
||||
}
|
||||
order := savedOrderInfo.order
|
||||
order.DeliveryFlag = 0
|
||||
err = partner.CurOrderManager.UpdateOrderStatusAndDeliveryFlag(order)
|
||||
// 创建订单
|
||||
if bills, err = s.CreateWaybillOnProviders4SavedOrder(ctx, savedOrderInfo, courierVendorIDs, excludeCourierVendorIDs, forceCreate, maxDeliveryFee); err == nil && len(bills) > 0 {
|
||||
partner.CurOrderManager.OnOrderMsg(order, "手动创建运单成功", fmt.Sprintf("%s创建%s平台运单,强发:%t,最高限价:%d", ctx.GetUserName(), model.VendorChineseNames[bills[0].WaybillVendorID], forceCreate, maxDeliveryFee))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
err = scheduler.ErrCanNotFindOrder
|
||||
}
|
||||
return bills, err
|
||||
}()
|
||||
}
|
||||
|
||||
jxutils.CallMsgHandler(billFunc, jxutils.ComposeUniversalOrderID(vendorOrderID, vendorID))
|
||||
return bills, errCode, err
|
||||
}
|
||||
|
||||
func (s *DefScheduler) CheckStoreBalance(ctx *jxcontext.Context, order *model.GoodsOrder, courierVendorIDs []int) (errCode string, err error) {
|
||||
var (
|
||||
db = dao.GetDB()
|
||||
)
|
||||
deliveryFeeMap, _ := s.QueryOrderWaybillFeeInfoEx(ctx, order.VendorOrderID, order.VendorID)
|
||||
if err != nil {
|
||||
return errCode, fmt.Errorf("获取订单配送费错误[%v]!", err)
|
||||
}
|
||||
|
||||
switch order.CreateDeliveryType {
|
||||
case model.NO: // 品牌发单
|
||||
storeDetail, err := dao.GetStoreDetail(db, jxutils.GetSaleStoreIDFromOrder(order), order.VendorID, "")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
brandAcct, err := dao.GetBrandBalance(db, storeDetail.BrandID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if len(courierVendorIDs) == 1 {
|
||||
courierVendorID := courierVendorIDs[0]
|
||||
if _, ok := deliveryFeeMap[courierVendorID]; ok {
|
||||
if deliveryFeeMap[courierVendorID].DeliveryFee > int64(brandAcct) {
|
||||
return model.ErrCodeAccountBalanceNotEnough, fmt.Errorf("品牌账户余额小于[%v]元,不能发配送!", jxutils.IntPrice2Standard(deliveryFeeMap[courierVendorID].DeliveryFee))
|
||||
}
|
||||
}
|
||||
} else if len(courierVendorIDs) == 0 {
|
||||
var maxFee int64
|
||||
for _, v := range deliveryFeeMap {
|
||||
if v.DeliveryFee > maxFee {
|
||||
v.DeliveryFee = maxFee
|
||||
}
|
||||
}
|
||||
if maxFee > int64(brandAcct) {
|
||||
return model.ErrCodeAccountBalanceNotEnough, fmt.Errorf("品牌账户余额小于[%v]元,不能发配送!", jxutils.IntPrice2Standard(maxFee))
|
||||
}
|
||||
}
|
||||
|
||||
case model.YES: // 门店发单
|
||||
//暂时这么认为,len courierVendorIDs 为1表示是老板或者运营从小程序上点的立即发单,因为小程序上是点哪个发哪个
|
||||
//京西后台则是点一下发3个,len courierVendorIDs 是0
|
||||
//如果是小程序上点哪个扣哪个平台的钱
|
||||
//如果是后台,则选最高的那个扣
|
||||
storeAcct, err := cms.GetStoreAcctBalance(ctx, jxutils.GetSaleStoreIDFromOrder(order)) // 获取门店余额
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
//1、先判断是不是第一次发:查询库里是否有这个订单的运费支出记录,再查询是否有相同金额并且类型为回退的收入记录(取消运单退回)
|
||||
//前者有,后者无, 表示已经发过了,暂未取消,若这这次的发单金额小于上次的金额则不进行判断也不多扣钱,若大于则扣除‘这次金额-上次金额’的钱,余额不足问题也根据这个判断
|
||||
//前者有,后者有,表示发过并且取消过了,是多次发,直接扣
|
||||
//前者无,表示就是第一次发,直接扣
|
||||
//2、小程序里这次金额用发单平台的金额,后台里这次金额用所有平台最高费用
|
||||
isEqual, isZero, err := partner.CurStoreAcctManager.CheckStoreAcctExpendExist(order.VendorOrderID)
|
||||
//表示前者有,后者无
|
||||
if !isZero && !isEqual { // 当前订单支出费用大于,退还费用
|
||||
var newPrice int64
|
||||
if len(courierVendorIDs) == 1 {
|
||||
courierVendorID := courierVendorIDs[0]
|
||||
if _, ok := deliveryFeeMap[courierVendorID]; ok {
|
||||
newPrice = deliveryFeeMap[courierVendorID].DeliveryFee
|
||||
}
|
||||
} else if len(courierVendorIDs) == 0 {
|
||||
var maxFee int64
|
||||
for _, v := range deliveryFeeMap {
|
||||
if v.DeliveryFee > maxFee {
|
||||
v.DeliveryFee = maxFee
|
||||
}
|
||||
}
|
||||
newPrice = maxFee
|
||||
}
|
||||
_, lastFee, _ := partner.CurStoreAcctManager.GetStoreAcctExpendLastCreateWayBillFee(order.VendorOrderID)
|
||||
// 如果门店属于京西菜市,京西果园则只能扣门店的金额
|
||||
if int(newPrice) > lastFee {
|
||||
if storeAcct.AccountBalance < int(newPrice)-lastFee /*&& result < int(newPrice)-lastFee*/ {
|
||||
return model.ErrCodeAccountBalanceNotEnough, fmt.Errorf("门店账户余额小于[%v]元,不能发配送!", jxutils.IntPrice2Standard(newPrice-int64(lastFee)))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if len(courierVendorIDs) == 1 {
|
||||
courierVendorID := courierVendorIDs[0]
|
||||
if _, ok := deliveryFeeMap[courierVendorID]; ok {
|
||||
if deliveryFeeMap[courierVendorID].DeliveryFee > int64(storeAcct.AccountBalance) {
|
||||
return model.ErrCodeAccountBalanceNotEnough, fmt.Errorf("门店账户余额小于[%v]元,不能发配送!", jxutils.IntPrice2Standard(deliveryFeeMap[courierVendorID].DeliveryFee))
|
||||
}
|
||||
}
|
||||
} else if len(courierVendorIDs) == 0 {
|
||||
var maxFee int64
|
||||
for _, v := range deliveryFeeMap {
|
||||
if v.DeliveryFee > maxFee {
|
||||
v.DeliveryFee = maxFee
|
||||
}
|
||||
}
|
||||
if maxFee > int64(storeAcct.AccountBalance) {
|
||||
return model.ErrCodeAccountBalanceNotEnough, fmt.Errorf("门店账户余额小于[%v]元,不能发配送!", jxutils.IntPrice2Standard(maxFee))
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
return "", fmt.Errorf("不存在的订单发单类型,检查配置")
|
||||
}
|
||||
|
||||
return errCode, err
|
||||
}
|
||||
|
||||
// todo 这个函数可以和SelfDeliveringAndUpdateStatus合并
|
||||
func (s *DefScheduler) CancelAll3rdWaybills(ctx *jxcontext.Context, vendorOrderID string, vendorID int, isStopSchedule bool) (err error) {
|
||||
jxutils.CallMsgHandler(func() {
|
||||
err = func() (err error) {
|
||||
// 取消三方运单,取消各平台单号信息,间隔一段时间后定时任务重新调度
|
||||
savedOrderInfo := s.loadSavedOrderByID(vendorOrderID, vendorID, true)
|
||||
if savedOrderInfo != nil {
|
||||
if len(savedOrderInfo.waybills) == model.NO {
|
||||
wayBills, err := dao.GetWayBillByOrderID(dao.GetDB(), 0, vendorID, 0, vendorOrderID)
|
||||
if err == nil {
|
||||
for _, wb := range wayBills {
|
||||
if wb.Status < model.WaybillStatusDelivered {
|
||||
err = s.CancelWaybill(wb, partner.CancelWaybillReasonOther, ctx.GetUserName()+":18"+partner.CancelWaybillReasonStrActive)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
err = s.cancelOtherWaybills(savedOrderInfo, nil, partner.CancelWaybillReasonOther, ctx.GetUserName()+":18"+partner.CancelWaybillReasonStrActive)
|
||||
}
|
||||
} else {
|
||||
err = scheduler.ErrCanNotFindOrder
|
||||
}
|
||||
// 停止调度,同事停止订单调度,不在通知第三方
|
||||
if err == nil && isStopSchedule {
|
||||
order := savedOrderInfo.order
|
||||
order.DeliveryFlag |= model.OrderDeliveryFlagMaskScheduleDisabled
|
||||
if err = partner.CurOrderManager.UpdateOrderStatusAndDeliveryFlag(order); err == nil {
|
||||
s.stopTimer(savedOrderInfo)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}()
|
||||
}, jxutils.ComposeUniversalOrderID(vendorOrderID, vendorID))
|
||||
return err
|
||||
}
|
||||
|
||||
// 查询三方运单费用
|
||||
func (s *DefScheduler) QueryOrderWaybillFeeInfoEx(ctx *jxcontext.Context, vendorOrderID string, vendorID int) (deliveryFeeMap map[int]*partner.WaybillFeeInfo, err error) {
|
||||
jxutils.CallMsgHandler(func() {
|
||||
deliveryFeeMap, err = func() (deliveryFeeMap map[int]*partner.WaybillFeeInfo, err error) {
|
||||
db := dao.GetDB()
|
||||
order, err := partner.CurOrderManager.LoadOrder(vendorOrderID, vendorID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if order.DeliveryType == model.OrderDeliveryTypeSelfTake {
|
||||
return nil, fmt.Errorf("订单:%s是自提单", vendorOrderID)
|
||||
}
|
||||
|
||||
// 获取用户送货地址
|
||||
storeCourierList, err := dao.GetStoreCourierList(db, []int{jxutils.GetSaleStoreIDFromOrder(order)}, nil, model.StoreStatusAll, model.StoreAuditStatusOnline)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 隐私地址获取(美团)
|
||||
if vendorID == model.VendorIDMTWM && (strings.Contains(order.ConsigneeAddress, "地址已隐藏") || strings.Contains(order.ConsigneeAddress, "(***)")) {
|
||||
var apiObj *mtwmapi.API
|
||||
switch order.VendorOrgCode {
|
||||
case beego.AppConfig.DefaultString("mtwmAppID2", ""): // 5873
|
||||
store, _ := dao.GetStoreDetail(dao.GetDB(), order.JxStoreID, order.VendorID, order.VendorOrgCode)
|
||||
apiObj = api.Mtwm2API
|
||||
apiObj.SetToken(store.MtwmToken)
|
||||
default: // 589 4123
|
||||
apiObj = api.MtwmAPI
|
||||
}
|
||||
address, err := apiObj.GetOrderAddress(utils.Str2Int64(order.VendorOrderID), 3)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
addressList := strings.Split(order.ConsigneeAddress, "@#")
|
||||
order.ConsigneeAddress = address + "@#" + addressList[1]
|
||||
dao.UpdateEntity(db, order, "ConsigneeAddress")
|
||||
}
|
||||
// 美团配送订单兑现
|
||||
waybillList, err := partner.CurOrderManager.GetOrderWaybillInfo(ctx, vendorOrderID, vendorID, true, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
waybillMap := make(map[int]*model.Waybill)
|
||||
for _, bill := range waybillList {
|
||||
waybillMap[bill.WaybillVendorID] = &bill.Waybill
|
||||
}
|
||||
deliveryFeeMap = make(map[int]*partner.WaybillFeeInfo)
|
||||
var timeoutSecond int
|
||||
if savedOrderInfo := s.loadSavedOrderByID(vendorOrderID, vendorID, false); savedOrderInfo != nil {
|
||||
timeoutSecond = savedOrderInfo.GetCreateWaybillTimeout()
|
||||
}
|
||||
|
||||
store, _ := dao.GetStoreDetail(db, order.JxStoreID, order.VendorID, order.VendorOrgCode)
|
||||
for _, storeCourier := range storeCourierList {
|
||||
var feeInfo *partner.WaybillFeeInfo
|
||||
if waybillMap[storeCourier.VendorID] != nil {
|
||||
feeInfo = &partner.WaybillFeeInfo{
|
||||
Waybill: waybillMap[storeCourier.VendorID],
|
||||
}
|
||||
} else {
|
||||
if storeCourier.Status != model.StoreStatusOpened {
|
||||
feeInfo = &partner.WaybillFeeInfo{
|
||||
ErrCode: partner.WaybillFeeErrCodeCourierNotOpen,
|
||||
ErrStr: fmt.Sprintf("暂未开通,联系运营"),
|
||||
}
|
||||
} else {
|
||||
if handler := partner.GetDeliveryPlatformFromVendorID(storeCourier.VendorID); handler != nil {
|
||||
if handler.Use4CreateWaybill {
|
||||
// 获取订单配送费用
|
||||
feeInfo, err = handler.Handler.GetWaybillFee(order)
|
||||
if err != nil {
|
||||
feeInfo = &partner.WaybillFeeInfo{
|
||||
ErrCode: partner.WaybillFeeErrCodeCourierOthers,
|
||||
ErrStr: err.Error(),
|
||||
}
|
||||
} else {
|
||||
feeInfo.DeliveryFee += model.WayBillDeliveryMarkUp // 加收两毛
|
||||
if storeCourier.VendorID == model.VendorIDFengNiao {
|
||||
feeInfo.DeliveryFee += model.WayBillDeliveryMarkUp // 蜂鸟加
|
||||
}
|
||||
feeInfo.DeliveryFee += int64(store.FreightMarkup)
|
||||
feeInfo.TimeoutSecond = timeoutSecond
|
||||
}
|
||||
} else {
|
||||
feeInfo = &partner.WaybillFeeInfo{
|
||||
ErrCode: partner.WaybillFeeErrCodeCourierForbidden,
|
||||
ErrStr: fmt.Sprintf("内部错误,%d不能用于创建运单", storeCourier.VendorID),
|
||||
}
|
||||
}
|
||||
} else {
|
||||
feeInfo = &partner.WaybillFeeInfo{
|
||||
ErrCode: partner.WaybillFeeErrCodeCourierNotSupported,
|
||||
ErrStr: fmt.Sprintf("内部错误,%d不被支持", storeCourier.VendorID),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
deliveryFeeMap[storeCourier.VendorID] = feeInfo
|
||||
}
|
||||
err = nil
|
||||
return deliveryFeeMap, err
|
||||
}()
|
||||
}, jxutils.ComposeUniversalOrderID(vendorOrderID, vendorID))
|
||||
return deliveryFeeMap, err
|
||||
}
|
||||
@@ -1,280 +0,0 @@
|
||||
package jcq
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"git.rosy.net.cn/baseapi"
|
||||
"git.rosy.net.cn/baseapi/platformapi/jcqapi"
|
||||
"git.rosy.net.cn/baseapi/platformapi/jdshopapi"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/partner/purchase/jdshop"
|
||||
"sync"
|
||||
)
|
||||
|
||||
const (
|
||||
accessKey = "C0EB36912C652079DB111A922ACA406B" //京东第三方的AK
|
||||
secretKey = "86B6330051ECC88391E2630D34C2CA13" //京东第三方的SK
|
||||
consumerGroupID = "open_message_573819178445" //消费组ID
|
||||
popOrderCreatTopic = "open_message_pop_order_create_E1D746D42474D5F1F1A10CECE75D99F6" //pop订单创建主题名称
|
||||
popOrderChangeTopic = "open_message_pop_order_change_E1D746D42474D5F1F1A10CECE75D99F6" //pop订单修改主题名称
|
||||
popOrderOutTopic = "open_message_pop_order_out_E1D746D42474D5F1F1A10CECE75D99F6" //pop订单出库主题名称
|
||||
OrderOutTopic = "open_message_order_order_out_E1D746D42474D5F1F1A10CECE75D99F6" //订单出库主题名称
|
||||
OrderCancelTopic = "open_message_order_order_cancel_E1D746D42474D5F1F1A10CECE75D99F6" //订单取消主题名称
|
||||
OrderPayTopic = "open_message_order_order_pay_E1D746D42474D5F1F1A10CECE75D99F6" //订单支付主题名称
|
||||
OrderCreatTopic = "open_message_order_order_create_E1D746D42474D5F1F1A10CECE75D99F6" //订单创建主题
|
||||
DefaultSubscribeSize = 32 //默认拉取数量
|
||||
popOrderCreatType = "popCreat" //存储到数据库pop订单创建类型
|
||||
popOrderOutType = "popOut" //存储到数据库pop订单出库类型
|
||||
popOrderChangeType = "popChange" //存储到数据库pop订单修改类型
|
||||
OrderCreatType = "orderCreat" //订单创建类型
|
||||
OrderPayType = "orderPay" //订单支付类型
|
||||
OrderOutType = "orderOut" //订单出库主题
|
||||
OrderCancelType = "orderCancel" //订单取消类型
|
||||
|
||||
)
|
||||
|
||||
var (
|
||||
TopicList = []string{
|
||||
popOrderCreatTopic, popOrderChangeTopic, popOrderOutTopic, OrderCreatTopic, OrderPayTopic, OrderOutTopic, OrderCancelTopic,
|
||||
}
|
||||
)
|
||||
|
||||
type JcqMessage struct { //model
|
||||
ID int64 `orm:"column(id)" `
|
||||
MessageID string `orm:"column(message_id)" `
|
||||
MessageBody string `orm:"column(message_body)"`
|
||||
BusinessID string `orm:"column(business_id)"`
|
||||
PropertyRetryTimes string `orm:"column(property_retry_times)"`
|
||||
Status string `orm:"column(status)"` //表示业务逻辑状态 n 表示业务为处理 y 表示已处理
|
||||
MessageType string `orm:"column(message_type)" //消息类型 对应上面的枚举`
|
||||
}
|
||||
|
||||
type JqcTask struct {
|
||||
TopicId string
|
||||
Wg *sync.WaitGroup
|
||||
}
|
||||
|
||||
type PopCreatObject struct { //序列化属性首字母必须大写 否则会出现赋值问题 切记! 也可以考虑使用simplejson就需要这么多的struct
|
||||
OrderCreateTime string `json:"orderCreateTime"`
|
||||
OrderId int64 `json:"orderId"`
|
||||
OrderPaymentType int `json:"orderPaymentType"`
|
||||
OrderStatus string `json:"orderStatus"`
|
||||
OrderType int `json:"orderType"`
|
||||
VenderId int64 `json:"venderId"`
|
||||
}
|
||||
|
||||
type PopChangeObject struct { //Pop修改
|
||||
ErpOrderStatus int `json:"erpOrderStatus"`
|
||||
Modified int `json:"modified"`
|
||||
OrderCreateTime int `json:"orderCreateTime"`
|
||||
OrderId int64 `json:"orderId"`
|
||||
OrderPaymentType int `json:"orderPaymentType"`
|
||||
OrderType int `json:"orderType"`
|
||||
VenderId int `json:"venderId"`
|
||||
Yn int `json:"yn"`
|
||||
}
|
||||
type PopCreatOrderMessage struct { //pop订单创建结构体
|
||||
PopCreatObj PopCreatObject `json:"object"`
|
||||
}
|
||||
|
||||
type CreatOrderMessage struct {
|
||||
OrderCreatObj PopCreatObject `json:"object"`
|
||||
}
|
||||
|
||||
type PayOrderMessage struct {
|
||||
OrderPayObject OrderPayObject `json:"object"`
|
||||
}
|
||||
|
||||
type OrderPayObject struct {
|
||||
OrderId int64 `json:"orderId"`
|
||||
OrderPaymentTime int `json:"orderPaymentTime"`
|
||||
OrderPaymentType int `json:"orderPaymentType"`
|
||||
OrderType int `json:"orderType"`
|
||||
VenderId int `json:"venderId"`
|
||||
OrderStatus int `json:"orderStatus"`
|
||||
}
|
||||
|
||||
func (t *JqcTask) Do() {
|
||||
handleTopic(t.TopicId)
|
||||
t.Wg.Done()
|
||||
}
|
||||
|
||||
var jcqApi *jcqapi.API
|
||||
|
||||
// JCQSchedule creat by Hang
|
||||
// 用于jcq队列返回数据处理 以及业务逻辑 由于在consumeInfo2加了ack 所以不会存在重复拉取的可能性
|
||||
// 使用ants 同时启动topic数量的携程 进行handle
|
||||
func JCQSchedule() {
|
||||
jcqApi = jcqapi.New(accessKey, secretKey)
|
||||
currentTopic := OrderPayTopic
|
||||
handleTopic(currentTopic)
|
||||
|
||||
/* p, _ := ants.NewPoolWithFunc(10, func(data interface{}) {
|
||||
task := data.(*JqcTask)
|
||||
task.Do()
|
||||
})
|
||||
defer p.Release()
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(len(TopicList))
|
||||
tasks := make([]*JqcTask, 0, len(TopicList))
|
||||
for i := 0; i < len(TopicList); i++ {
|
||||
task := &JqcTask{
|
||||
TopicId: TopicList[i],
|
||||
Wg: &wg,
|
||||
}
|
||||
tasks = append(tasks, task)
|
||||
p.Invoke(task)
|
||||
}
|
||||
wg.Wait()*/
|
||||
|
||||
}
|
||||
|
||||
//处理topic 针对不同的topic进行存库操作
|
||||
func handleTopic(topicId string) {
|
||||
consumeResults, err := jcqApi.ConsumeInfo2(topicId, consumerGroupID, DefaultSubscribeSize)
|
||||
if err == nil {
|
||||
if len(consumeResults) != 0 {
|
||||
entityList := make([]JcqMessage, 0)
|
||||
//构建实体
|
||||
for _, result := range consumeResults {
|
||||
if topicId == popOrderCreatTopic {
|
||||
var r PopCreatOrderMessage
|
||||
//js, _ := simplejson.NewJson([]byte(result.MessageBody))
|
||||
json.Unmarshal([]byte(result.MessageBody), &r)
|
||||
fmt.Println(r)
|
||||
}
|
||||
jcq := JcqMessage{
|
||||
MessageID: result.MessageID,
|
||||
MessageBody: result.MessageBody,
|
||||
BusinessID: result.Properties.BUSINESSID,
|
||||
PropertyRetryTimes: result.Properties.PROPERTYRETRYTIMES,
|
||||
Status: "n", //默认给定初始值 未做处理
|
||||
MessageType: transType(topicId),
|
||||
}
|
||||
entityList = append(entityList, jcq)
|
||||
}
|
||||
db := dao.GetDB()
|
||||
if err = dao.CreateMultiEntities(db, entityList); err != nil {
|
||||
baseapi.SugarLogger.Warnf("saveMessage orderID:%s, save jqs_message failed with error:%v", entityList, err)
|
||||
} else { //存库成功进行调用API操作
|
||||
//定义菜市api
|
||||
jdmcshopapi := jdshopapi.New("37d36b62c0d14bd4b872f948b335c95czinj", "E1D746D42474D5F1F1A10CECE75D99F6", "efa7e1d1a22640fa990e6cf164b28608")
|
||||
//定义果园api
|
||||
jdgyshopapi := jdshopapi.New("f9c5ce9a5ce24218936924f7c4864cc9owe1", "E1D746D42474D5F1F1A10CECE75D99F6", "efa7e1d1a22640fa990e6cf164b28608")
|
||||
for _, result := range consumeResults {
|
||||
//处理订单支付,订单取消和pop订单出库的topic
|
||||
if topicId == OrderPayTopic || topicId == OrderCancelTopic || topicId == popOrderOutTopic {
|
||||
var r PayOrderMessage
|
||||
//js, _ := simplejson.NewJson([]byte(result.MessageBody))
|
||||
json.Unmarshal([]byte(result.MessageBody), &r)
|
||||
orderResult, err := jdmcshopapi.GetOrderById(r.OrderPayObject.OrderId, true)
|
||||
isGy := false
|
||||
if orderResult == nil && err == nil {
|
||||
isGy = true
|
||||
orderResult, err = jdgyshopapi.GetOrderById(r.OrderPayObject.OrderId, true) //查询不到之后说明不是这个账号的 使用果园再查一遍
|
||||
}
|
||||
if err == nil { //确定返回结果
|
||||
// TO DO 处理数据转换为原先回调的结果
|
||||
if orderResult == nil {
|
||||
baseapi.SugarLogger.Debug("未查询到订单ID", r.OrderPayObject.OrderId)
|
||||
} else {
|
||||
callBackResult := TransFormOrderResultToCallBackResult(orderResult, topicId, isGy)
|
||||
jdshop.OnCallbackMsg(callBackResult) //进行处理
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
baseapi.SugarLogger.Debug("handle Topic the end")
|
||||
}
|
||||
}
|
||||
|
||||
// 用于转换类型
|
||||
func transType(topic string) string {
|
||||
switch topic {
|
||||
case popOrderCreatTopic:
|
||||
return popOrderCreatType
|
||||
case popOrderChangeTopic:
|
||||
return popOrderChangeType
|
||||
case popOrderOutTopic:
|
||||
return popOrderOutType
|
||||
case OrderCreatTopic:
|
||||
return OrderCreatType
|
||||
case OrderPayTopic:
|
||||
return OrderPayType
|
||||
case OrderOutTopic:
|
||||
return OrderOutType
|
||||
case OrderCancelTopic:
|
||||
return OrderCancelType
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// TransFormOrderResultToCallBackResult 转换数据类型 使其可以进入原先回调方法
|
||||
func TransFormOrderResultToCallBackResult(getOrderResult *jdshopapi.GetEnOrderResult, topicId string, isGy bool) *jdshopapi.CallBackResult {
|
||||
return &jdshopapi.CallBackResult{
|
||||
OrderStateRemark: getOrderResult.OrderStateRemark,
|
||||
OrderRemark: getOrderResult.OrderRemark,
|
||||
OrderSellerPrice: getOrderResult.OrderSellerPrice,
|
||||
OrderState: getOrderResult.OrderState,
|
||||
OrderType: getOrderResult.OrderType,
|
||||
OrderPayment: getOrderResult.OrderPayment,
|
||||
PayType: getOrderResult.PayType,
|
||||
StoreID: getOrderResult.StoreID,
|
||||
OrderTotalPrice: getOrderResult.OrderTotalPrice,
|
||||
OrderExt: getOrderResult.OrderExt,
|
||||
StoreOrder: getOrderResult.StoreOrder,
|
||||
OrderStartTime: getOrderResult.OrderStartTime,
|
||||
OrderID: getOrderResult.OrderID,
|
||||
OrderSource: getOrderResult.OrderSource,
|
||||
FreightPrice: getOrderResult.FreightPrice,
|
||||
MsgType: TransMsgType(topicId),
|
||||
Pin:/*splitPin(getOrderResult.Pin),*/ "jd_temp",
|
||||
IDSopShipmenttype: getOrderResult.IDSopShipmenttype,
|
||||
ScDT: getOrderResult.ScDT,
|
||||
SellerDiscount: getOrderResult.SellerDiscount,
|
||||
ConsigneeInfo: getOrderResult.ConsigneeInfo,
|
||||
ItemInfoList: getOrderResult.ItemInfoList,
|
||||
VendorOrgCode: getVendorOrgCode(isGy),
|
||||
MenDianID: getOrderResult.MenDianID,
|
||||
BalanceUsed: getOrderResult.BalanceUsed}
|
||||
}
|
||||
|
||||
// TransMsgType 目前业务处理函数仅对一下三种topic做了业务处理
|
||||
func TransMsgType(topicId string) string {
|
||||
switch topicId {
|
||||
case OrderPayTopic:
|
||||
return jcqapi.TopicOrderPay
|
||||
case OrderCancelTopic:
|
||||
return jcqapi.TopicOrderCancel
|
||||
case popOrderOutTopic:
|
||||
return jcqapi.TopicOrderOut
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//由于返回的pin长度过长 进行md5操作 压缩长度
|
||||
func splitPin(pin string) string {
|
||||
h := md5.New()
|
||||
h.Write([]byte(pin))
|
||||
s := hex.EncodeToString(h.Sum(nil))
|
||||
return s
|
||||
|
||||
}
|
||||
|
||||
// 根据标识判断加密标识
|
||||
func getVendorOrgCode(isGy bool) string {
|
||||
if isGy {
|
||||
return "2"
|
||||
} else {
|
||||
return "1"
|
||||
}
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
package jdslogin
|
||||
|
||||
// RefreshQRCode Creat By 2022/04/18
|
||||
// RefreshQRCode Author By Hang xu
|
||||
// RefreshQRCode 用于爬取京东的二维码链接 并持久化进入数据库中
|
||||
//func RefreshQRCode() (retval string, err error) {
|
||||
// baseapi.SugarLogger.Debug("BEGIN JD SHOP QRCODE SPIDER---------------------------------------------------")
|
||||
// const (
|
||||
// seleniumPath = `/usr/bin/chromedriver`
|
||||
// port = 9515
|
||||
// )
|
||||
// opts := []selenium.ServiceOption{}
|
||||
//
|
||||
// selenium.SetDebug(true)
|
||||
//
|
||||
// service, err := selenium.NewChromeDriverService(seleniumPath, port, opts...)
|
||||
// if nil != err {
|
||||
// fmt.Println("start a chromedriver service falid", err.Error())
|
||||
// return
|
||||
// }
|
||||
// ////server关闭之后,chrome窗口也会关闭
|
||||
// defer service.Stop()
|
||||
// //链接本地的浏览器 chrome
|
||||
// caps := selenium.Capabilities{
|
||||
// //"browserName": "/Applications/Google Chrome Dev.app/Contents/MacOS/Google Chrome Dev",
|
||||
// "browserName": "/opt/google/chrome",
|
||||
// }
|
||||
// //禁止图片加载,加快渲染速度
|
||||
// imagCaps := map[string]interface{}{
|
||||
// "profile.managed_default_content_settings.images": 2,
|
||||
// }
|
||||
// chromeCaps := chrome.Capabilities{
|
||||
// Prefs: imagCaps,
|
||||
// Path: "/opt/google/chrome",
|
||||
// Args: []string{
|
||||
// //静默执行请求
|
||||
// "--headless", // 设置Chrome无头模式,在linux下运行,需要设置这个参数,否则会报错
|
||||
// "--no-sandbox",
|
||||
// "--user-agent=Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.51 Safari/537.36", // 模拟user-agent,防反爬
|
||||
// "--Host=porder.shop.jd.com",
|
||||
// "--Connection=keep-alive",
|
||||
// },
|
||||
// }
|
||||
// //以上是设置浏览器参数
|
||||
// caps.AddChrome(chromeCaps)
|
||||
//
|
||||
// url := "https://porder.shop.jd.com/order/orderlist/allOrders"
|
||||
// w_b1, err := selenium.NewRemote(caps, fmt.Sprintf("http://localhost:%d/wd/hub", port))
|
||||
// if err != nil {
|
||||
// fmt.Println("connect to the webDriver faild", err.Error())
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// err = w_b1.Get(url)
|
||||
// pageSource, err := w_b1.PageSource()
|
||||
// baseapi.SugarLogger.Debug("pageSource", pageSource)
|
||||
// qr, err := w_b1.FindElement("id", "js-login-qrcode")
|
||||
// qrStr, err := qr.GetAttribute("src")
|
||||
// baseapi.SugarLogger.Debug("qrStr:", qrStr) //当前qrcode sample:https://passport.shop.jd.com/login/json/qrcode_show.action?_timeStr=165026591404449b823cc58684d948d0e0ca8351adf64
|
||||
// // 进行存库操作
|
||||
// // save to database 存入 new_config表中
|
||||
// db := dao.GetDB()
|
||||
// txDB, _ := dao.Begin(db)
|
||||
// defer func() {
|
||||
// if r := recover(); r != nil {
|
||||
// dao.Rollback(db, txDB)
|
||||
// panic(r)
|
||||
// }
|
||||
// }()
|
||||
// configList, err := dao.QueryConfigs(db, "jdsQRcode", "Cookie", "")
|
||||
// if err != nil {
|
||||
// dao.Rollback(db, txDB)
|
||||
// return "", err
|
||||
// }
|
||||
// if _, err = dao.UpdateEntityLogically(db, configList[0], map[string]interface{}{
|
||||
// "Value": qrStr,
|
||||
// }, "", nil); err != nil {
|
||||
// dao.Rollback(db, txDB)
|
||||
// return "", err
|
||||
// }
|
||||
// baseapi.SugarLogger.Debug("THE JD SHOP QRCODE SPIDER THE END---------------------------------------------")
|
||||
// return "", nil
|
||||
//}
|
||||
@@ -1,50 +0,0 @@
|
||||
package scheduler
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
)
|
||||
|
||||
const (
|
||||
StoreDeliveryTypeCrowdSourcing = 0 //缺省,平台众包配送,可转自送
|
||||
StoreDeliveryTypeByPlatform = 1 //平台专送
|
||||
StoreDeliveryTypeByStore = 2 //完全门店自送,这个表示的意思是平台的门店属性(就是购物平台不负责配送),而不是真正是否是老板自己送
|
||||
)
|
||||
|
||||
const (
|
||||
TimerStatusTypeUnknown = -1
|
||||
TimerStatusTypeOrder = 0
|
||||
TimerStatusTypeWaybill = 1
|
||||
)
|
||||
|
||||
var (
|
||||
CurrentScheduler IScheduler
|
||||
)
|
||||
|
||||
var (
|
||||
ErrOrderStatusIsNotSuitable4CurOperation = errors.New("订单锁定或状态不适合当前操作")
|
||||
ErrOrderStatusAlreadySatisfyCurOperation = errors.New("订单当前状态已满足当前操作")
|
||||
ErrOrderStatusShippedCurOperation = errors.New("订单已发货,不允许再次执行发货")
|
||||
ErrOrderStatusAlreadySatisfyCurOperationELM = errors.New("无需切自配送")
|
||||
ErrOrderStatusAlreadySatisfyCurOperationMTWM = errors.New("非专送、快送、混合送订单不允许调用此接口 level:0, code:1047")
|
||||
|
||||
ErrCanNotCreateAtLeastOneWaybill = errors.New("一个运单都不能创建")
|
||||
ErrCanNotFindOrder = errors.New("不能找到订单(一般是由于事件错序)")
|
||||
ErrCanNotFindWaybill = errors.New("不能找到运单(一般是由于事件错序)")
|
||||
ErrOrderIsNotSolid = errors.New("订单是临时订单,不完整,不能用于创建运单")
|
||||
ErrDeliverProviderWrong = errors.New("快递商不存在或不能用于创建运单")
|
||||
)
|
||||
|
||||
type IScheduler interface {
|
||||
// 以下是订单
|
||||
OnOrderNew(order *model.GoodsOrder, isPending bool, isAuto bool) (err error)
|
||||
OnOrderStatusChanged(order *model.GoodsOrder, status *model.OrderStatus, isPending bool) (err error)
|
||||
|
||||
// 以下是运单
|
||||
OnWaybillStatusChanged(bill *model.Waybill, isPending bool) (err error)
|
||||
|
||||
// 以下是售后单
|
||||
OnAfsOrderNew(order *model.AfsOrder, isPending bool) (err error)
|
||||
OnAfsOrderStatusChanged(order *model.AfsOrder, status *model.OrderStatus, isPending bool) (err error)
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,206 +0,0 @@
|
||||
package act
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/globals/testinit"
|
||||
"testing"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/ebai"
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/jd"
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/mtwm"
|
||||
)
|
||||
|
||||
func init() {
|
||||
testinit.Init()
|
||||
}
|
||||
|
||||
func TestInitDb(t *testing.T) {
|
||||
dao.ExecuteSQL(dao.GetDB(), `
|
||||
DROP TABLE IF EXISTS act, act_map, act_order_rule, act_store_sku, act_store_sku_map;
|
||||
`)
|
||||
}
|
||||
|
||||
func TestCreateActOnAlpha(t *testing.T) {
|
||||
actStoreSkuList := []*ActStoreSkuParam{
|
||||
&ActStoreSkuParam{
|
||||
ActStoreSku: model.ActStoreSku{
|
||||
StoreID: 2,
|
||||
SkuID: 2142,
|
||||
},
|
||||
},
|
||||
&ActStoreSkuParam{
|
||||
ActStoreSku: model.ActStoreSku{
|
||||
StoreID: 2,
|
||||
SkuID: 1162,
|
||||
},
|
||||
},
|
||||
&ActStoreSkuParam{
|
||||
ActStoreSku: model.ActStoreSku{
|
||||
StoreID: 2,
|
||||
SkuID: 1167,
|
||||
},
|
||||
},
|
||||
&ActStoreSkuParam{
|
||||
ActStoreSku: model.ActStoreSku{
|
||||
StoreID: 2,
|
||||
SkuID: 1172,
|
||||
},
|
||||
},
|
||||
}
|
||||
t.Log(utils.Format4Output(actStoreSkuList, true))
|
||||
// actID, err := CreateAct(jxcontext.AdminCtx, &model.Act{
|
||||
// Name: "测试活动",
|
||||
// PricePercentage: 80,
|
||||
// Type: model.ActSkuDirectDown,
|
||||
// }, []int{model.VendorIDJD, model.VendorIDMTWM, model.VendorIDEBAI}, nil, actStoreSkuList, false)
|
||||
// if err != nil {
|
||||
// t.Fatal(err)
|
||||
// }
|
||||
// globals.SugarLogger.Debug(actID)
|
||||
}
|
||||
|
||||
func TestCreateActOnDev(t *testing.T) {
|
||||
//actStoreSkuList := []*ActStoreSkuParam{
|
||||
// &ActStoreSkuParam{
|
||||
// ActStoreSku: model.ActStoreSku{
|
||||
// StoreID: 100884,
|
||||
// SkuID: 22716,
|
||||
// },
|
||||
// },
|
||||
// &ActStoreSkuParam{
|
||||
// ActStoreSku: model.ActStoreSku{
|
||||
// StoreID: 100884,
|
||||
// SkuID: 22717,
|
||||
// },
|
||||
// },
|
||||
// &ActStoreSkuParam{
|
||||
// ActStoreSku: model.ActStoreSku{
|
||||
// StoreID: 100920,
|
||||
// SkuID: 22714,
|
||||
// },
|
||||
// },
|
||||
// &ActStoreSkuParam{
|
||||
// ActStoreSku: model.ActStoreSku{
|
||||
// StoreID: 100920,
|
||||
// SkuID: 22715,
|
||||
// },
|
||||
// },
|
||||
// // &ActStoreSkuParam{
|
||||
// // ActStoreSku: model.ActStoreSku{
|
||||
// // StoreID: 100119,
|
||||
// // SkuID: 26595,
|
||||
// // },
|
||||
// // },
|
||||
//}
|
||||
// t.Log(utils.Format4Output(actStoreSkuList, true))
|
||||
//actID, err := CreateAct(jxcontext.AdminCtx, &model.Act{
|
||||
// Name: "测试活动",
|
||||
// PricePercentage: 80,
|
||||
// Type: model.ActSkuDirectDown,
|
||||
// BeginAt: time.Now().Add(-24 * time.Hour),
|
||||
// EndAt: time.Now().Add(10 * 24 * time.Hour),
|
||||
//}, []int{model.VendorIDJD, model.VendorIDMTWM /*, model.VendorIDEBAI*/}, nil, actStoreSkuList, false)
|
||||
//if err != nil {
|
||||
// t.Fatal(err)
|
||||
//}
|
||||
//globals.SugarLogger.Debug(actID)
|
||||
}
|
||||
|
||||
func TestCancelAct(t *testing.T) {
|
||||
err := CancelAct(jxcontext.AdminCtx, 1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeleteActStoreBind(t *testing.T) {
|
||||
_, err := DeleteActStoreSkuBind(jxcontext.AdminCtx, dao.GetDB(), 1, []*ActStoreSkuParam{
|
||||
// &ActStoreSkuParam{
|
||||
// ActStoreSku: model.ActStoreSku{
|
||||
// StoreID: 100119,
|
||||
// SkuID: 30828,
|
||||
// },
|
||||
// },
|
||||
// &ActStoreSkuParam{
|
||||
// ActStoreSku: model.ActStoreSku{
|
||||
// StoreID: 100119,
|
||||
// SkuID: 30827,
|
||||
// },
|
||||
// },
|
||||
&ActStoreSkuParam{
|
||||
ActStoreSku: model.ActStoreSku{
|
||||
StoreID: 100884,
|
||||
SkuID: 22716,
|
||||
},
|
||||
},
|
||||
&ActStoreSkuParam{
|
||||
ActStoreSku: model.ActStoreSku{
|
||||
StoreID: 100884,
|
||||
SkuID: 22717,
|
||||
},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddActStoreBind(t *testing.T) {
|
||||
err := AddActStoreSkuBind(jxcontext.AdminCtx, dao.GetDB(), 1, []*ActStoreSkuParam{
|
||||
// &ActStoreSkuParam{
|
||||
// ActStoreSku: model.ActStoreSku{
|
||||
// StoreID: 100119,
|
||||
// SkuID: 30828,
|
||||
// },
|
||||
// },
|
||||
// &ActStoreSkuParam{
|
||||
// ActStoreSku: model.ActStoreSku{
|
||||
// StoreID: 100119,
|
||||
// SkuID: 30827,
|
||||
// },
|
||||
// },
|
||||
&ActStoreSkuParam{
|
||||
ActStoreSku: model.ActStoreSku{
|
||||
StoreID: 100884,
|
||||
SkuID: 22716,
|
||||
},
|
||||
},
|
||||
&ActStoreSkuParam{
|
||||
ActStoreSku: model.ActStoreSku{
|
||||
StoreID: 100884,
|
||||
SkuID: 22717,
|
||||
},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSyncAct(t *testing.T) {
|
||||
_, err := SyncAct(jxcontext.AdminCtx, nil, 1, nil, false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestForceUpdateVendorPrice(t *testing.T) {
|
||||
//hint, err := ForceUpdateVendorPrice(jxcontext.AdminCtx, model.VendorIDJD, model.ActSkuDirectDown, []*ActStoreSkuParam{
|
||||
// &ActStoreSkuParam{
|
||||
// ActStoreSku: model.ActStoreSku{
|
||||
// StoreID: 100118,
|
||||
// SkuID: 22509,
|
||||
// ActPrice: 9900,
|
||||
// },
|
||||
// VendorPrice: 19900,
|
||||
// },
|
||||
//}, false)
|
||||
//if err != nil {
|
||||
// t.Fatal(err)
|
||||
//}
|
||||
//t.Log(hint)
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
// todo 是否需要将Store.MarketManPhone与OperatorPhone成角色?
|
||||
|
||||
func TransferLegacyWeixins(mobile string) (err error) {
|
||||
globals.SugarLogger.Debugf("TransferLegacyWeixins mobile:%s", mobile)
|
||||
if !globals.EnableWXAuth2 || globals.DisableWXAuth1 {
|
||||
return nil
|
||||
}
|
||||
@@ -70,10 +71,11 @@ func TransferLegacyWeixins(mobile string) (err error) {
|
||||
if user.Name == "" {
|
||||
user.Name = user.GetMobile()
|
||||
}
|
||||
userList, _, err2 := dao.GetUsers(db, 0, "", nil, nil, []string{v.Tel}, 0, -1)
|
||||
userList, _, err2 := dao.GetUsers(db, 0, "", "", nil, nil, []string{v.Tel}, 0, -1)
|
||||
if err = err2; err != nil {
|
||||
return err
|
||||
}
|
||||
// globals.SugarLogger.Debug(utils.Format4Output(user, false))
|
||||
if len(userList) == 0 {
|
||||
err = CreateUser(user, v.LastOperator)
|
||||
} else {
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
package cms
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/globals/api2"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/authz/autils"
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/ebai"
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/elm"
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/jd"
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/mtwm"
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/weimob/wsc"
|
||||
)
|
||||
|
||||
func TestTransferLegacyWeixins(t *testing.T) {
|
||||
err := TransferLegacyWeixins("")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCasbin(t *testing.T) {
|
||||
userList, err := api2.RoleMan.GetRoleUserList(autils.NewStoreBossRole(100324))
|
||||
t.Log(utils.Format4Output(userList, false))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRefreshTiktokShopToken(t *testing.T) {
|
||||
RefreshTiktokShopToken(nil)
|
||||
}
|
||||
@@ -1,31 +1,24 @@
|
||||
package cms
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"git.rosy.net.cn/baseapi/platformapi/tencent_map"
|
||||
"math"
|
||||
"git.rosy.net.cn/baseapi/platformapi/mtunionapi"
|
||||
"git.rosy.net.cn/baseapi/platformapi/tbunionapi"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/autonavi"
|
||||
"git.rosy.net.cn/jx-callback/business/partner/purchase/ebai"
|
||||
"git.rosy.net.cn/baseapi/platformapi/ejyapi"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils/errlist"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/globals/api2"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/dingdingapi"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/auth2/authprovider/mobile"
|
||||
"git.rosy.net.cn/jx-callback/business/authz/autils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/ddmsg"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
@@ -46,64 +39,8 @@ type SysConfigLimit struct {
|
||||
}
|
||||
|
||||
var (
|
||||
serviceInfo map[string]interface{}
|
||||
allowUpdatePlaceFieldsMap = map[string]bool{
|
||||
"name": true,
|
||||
"enabled": true,
|
||||
"mtpsPrice": true,
|
||||
}
|
||||
|
||||
serviceInfo map[string]interface{}
|
||||
regexpMsgContentOpID = regexp.MustCompile(`"openid":"(.*?)"`)
|
||||
|
||||
receiveMsgUsersMap = map[string][]string{
|
||||
SendMsgTypeOpenStoreRequest: []string{
|
||||
"石锋",
|
||||
// "x",
|
||||
// "周扬",
|
||||
},
|
||||
SendMsgTypeSuggestRequest: []string{
|
||||
"石锋",
|
||||
// "x",
|
||||
// "周扬",
|
||||
// "苏尹岚",
|
||||
},
|
||||
}
|
||||
needConfirmRequestMap = map[string]int{
|
||||
SendMsgTypeOpenStoreRequest: 1,
|
||||
}
|
||||
|
||||
SysConfigLimitMap = map[string]*SysConfigLimit{
|
||||
model.ConfigSysEbaiBoxFee: &SysConfigLimit{
|
||||
ValueType: reflect.Int,
|
||||
MinValue: 0,
|
||||
MaxValue: 500,
|
||||
AfterChanged: func() (err error) {
|
||||
_, err = dao.SetStoreMapSyncStatus(dao.GetDB(), []int{model.VendorIDEBAI}, nil, model.SyncFlagModifiedMask)
|
||||
return err
|
||||
},
|
||||
},
|
||||
model.ConfigSysMtwmBoxFee: &SysConfigLimit{
|
||||
ValueType: reflect.Int,
|
||||
MinValue: 0,
|
||||
MaxValue: 500,
|
||||
AfterChanged: func() (err error) {
|
||||
_, err = dao.SetStoreMapSyncStatus(dao.GetDB(), []int{model.VendorIDMTWM}, nil, model.SyncFlagModifiedMask)
|
||||
return err
|
||||
},
|
||||
},
|
||||
model.ConfigSysMtwmSkuBoxFee: &SysConfigLimit{
|
||||
ValueType: reflect.Int,
|
||||
MinValue: 0,
|
||||
MaxValue: 50,
|
||||
AfterChanged: func() (err error) {
|
||||
_, err = dao.SetStoreSkuSyncStatus(dao.GetDB(), model.VendorIDMTWM, nil, nil, model.SyncFlagModifiedMask)
|
||||
return err
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
AutonaviKeyList = []string{autonavi.AMAPCyclingPlanKey1, autonavi.AMAPCyclingPlanKey2, autonavi.AMAPCyclingPlanKey3, autonavi.AMAPCyclingPlanKey4, autonavi.AMAPCyclingPlanKey5}
|
||||
AutonaviKeyIndex = 0
|
||||
)
|
||||
|
||||
func InitServiceInfo(version string, buildTime time.Time, gitCommit string) {
|
||||
@@ -117,49 +54,65 @@ func InitServiceInfo(version string, buildTime time.Time, gitCommit string) {
|
||||
"buildTime": buildTimeStr,
|
||||
"gitCommit": gitCommit,
|
||||
"metaData": map[string]interface{}{
|
||||
"skuNamePrefix": model.SkuNamePrefixNames,
|
||||
"skuNameUnit": model.UnitNames,
|
||||
"skuSpecUnit": model.SpecUnitNames,
|
||||
"skuStatus": model.SkuStatusName,
|
||||
"storeDeliveryRangeType": model.DeliveryRangeTypeName,
|
||||
"storeDeliveryType": model.DeliveryTypeName,
|
||||
"storeStatus": model.StoreStatusName,
|
||||
"categoryType": model.CategoryTypeName,
|
||||
"vendorTypeName": model.VendorTypeName,
|
||||
"vendorName": model.VendorChineseNames,
|
||||
"vendorImg": model.VendorImg,
|
||||
"vendorColors": model.VendorColors,
|
||||
"orderStatus": model.OrderStatusName,
|
||||
"waybillStatus": model.WaybillStatusName,
|
||||
"orderTypeName": model.OrderTypeName,
|
||||
"taskStatusName": tasksch.TaskStatusName,
|
||||
"opRequestTypeName": model.RequestTypeName,
|
||||
"opRequestStatusName": model.RequestStatusName,
|
||||
"storeMsgSendStatusName": model.StoreMsgSendStatusName,
|
||||
"shopChineseNames": model.ShopChineseNames,
|
||||
"printerVendorInfo": model.PrinterVendorInfo,
|
||||
"printerStatusName": partner.PrinterStatusName,
|
||||
"purchaseVendorInfo": model.PurchaseVendorInfo,
|
||||
"afsReasonTypeName": model.AfsReasonTypeName,
|
||||
"afsAppealTypeName": model.AfsAppealTypeName,
|
||||
"actTypeName": model.ActTypeName,
|
||||
"actStatusName": model.ActStatusName,
|
||||
"actCreateTypeName": model.ActCreateTypeName,
|
||||
"storeAuditStatusName": model.StoreAuditStatusName,
|
||||
"configTypeName": model.ConfigTypeName,
|
||||
"autoSaleAt": AutoSaleAtStr,
|
||||
"userTypeName": model.UserTypeName,
|
||||
"storePriceTypeName": model.StorePriceTypeName,
|
||||
"payStatusName": model.PayStatusName,
|
||||
"refundStatusName": model.RefundStatusName,
|
||||
"autoReplyTypeName": model.AutoReplyTypeName,
|
||||
"complaintReasons": model.ComplaintReasons,
|
||||
"supplementType": model.SupplementTypeName,
|
||||
"operateType": model.OperateTypeName,
|
||||
"thingType": model.ThingTypeName,
|
||||
"apiFunctionName": model.ApiFunctionName,
|
||||
"vendorStatus": model.VendorStatus,
|
||||
"couponsStatus": model.CouponStatusName,
|
||||
"ebaiSupplierID": ebai.EbaiSupplierIDMap,
|
||||
"ebaiSupplierInfo": ebai.EbaiSupplierInfo,
|
||||
"jobLimitCountType": `[{
|
||||
"id":` + utils.Int2Str(model.JobLimitCountTypePO) +
|
||||
`,"value": "每人一次"
|
||||
},{
|
||||
"id":` + utils.Int2Str(model.JobLimitCountTypePDO) +
|
||||
`,"value": "每人每天一次"
|
||||
},{
|
||||
"id":` + utils.Int2Str(model.JobLimitCountTypePWO) +
|
||||
`,"value": "每人每周一次"
|
||||
},{
|
||||
"id":` + utils.Int2Str(model.JobLimitCountTypeNoLimit) +
|
||||
`,"value": "不限次"
|
||||
}]`,
|
||||
"billTypeNames": model.BillTypeNames,
|
||||
"deliveryStatusName": model.DeliveryStatusName,
|
||||
"cashbackName": model.CashbackName,
|
||||
"consumeName": model.ConsumeName,
|
||||
"txWaybillNames": model.TxWaybillNames,
|
||||
"unionActTypeNames": map[int]map[int]interface{}{
|
||||
model.VendorIDMTWM: map[int]interface{}{
|
||||
mtunionapi.ActTypeQB: "券包推广",
|
||||
},
|
||||
model.VendorIDTB: map[int]interface{}{
|
||||
tbunionapi.TbElmActTypeBDH: "本地化",
|
||||
},
|
||||
model.VendorIDPDD: map[int]interface{}{
|
||||
1: "进行中的活动",
|
||||
},
|
||||
model.VendorIDJDShop: map[int]interface{}{
|
||||
2: "进行中",
|
||||
},
|
||||
},
|
||||
"unionOrderStatusName": model.UnionOrderStatusName,
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -169,7 +122,7 @@ func GetServiceInfo(ctx *jxcontext.Context) map[string]interface{} {
|
||||
}
|
||||
|
||||
func GetPlaces(ctx *jxcontext.Context, keyword string, includeDisabled bool, params map[string]interface{}) ([]*model.Place, error) {
|
||||
sql := `
|
||||
sql := `
|
||||
SELECT *
|
||||
FROM place t1
|
||||
WHERE 1 = 1
|
||||
@@ -196,217 +149,29 @@ func GetPlaces(ctx *jxcontext.Context, keyword string, includeDisabled bool, par
|
||||
sqlParams = append(sqlParams, params["level"])
|
||||
}
|
||||
sql += " ORDER BY t1.level, t1.name"
|
||||
// globals.SugarLogger.Debug(sql)
|
||||
places := []*model.Place{}
|
||||
return places, dao.GetRows(nil, &places, sql, sqlParams...)
|
||||
}
|
||||
|
||||
func UpdatePlaces(ctx *jxcontext.Context, places []map[string]interface{}, userName string) (num int64, err error) {
|
||||
if len(places) == 0 {
|
||||
return 0, ErrMissingInput
|
||||
}
|
||||
updateFields := []string{}
|
||||
for k := range places[0] {
|
||||
if allowUpdatePlaceFieldsMap[k] {
|
||||
updateFields = append(updateFields, k)
|
||||
}
|
||||
}
|
||||
for _, place := range places {
|
||||
if place["code"] == nil {
|
||||
return 0, ErrMissingInput
|
||||
}
|
||||
placeid := &model.Place{}
|
||||
valid := dao.NormalMakeMapByFieldList(place, updateFields, userName)
|
||||
if num, err = dao.UpdateEntityLogically(nil, placeid, valid, userName, utils.Params2Map("Code", place["code"])); err != nil {
|
||||
return num, err
|
||||
}
|
||||
}
|
||||
return num, err
|
||||
}
|
||||
|
||||
func UpdatePlace(ctx *jxcontext.Context, placeCode int, payload map[string]interface{}, userName string) (num int64, err error) {
|
||||
payload["code"] = placeCode
|
||||
return UpdatePlaces(ctx, []map[string]interface{}{payload}, userName)
|
||||
return places, dao.GetRows(nil, &places, sql, sqlParams)
|
||||
}
|
||||
|
||||
func GetCoordinateDistrictCode(ctx *jxcontext.Context, lng, lat float64) (code int, err error) {
|
||||
return api.TencentMapAPI.GetCoordinateDistrictCode(lng, lat), nil
|
||||
return api.AutonaviAPI.GetCoordinateDistrictCode(lng, lat), nil
|
||||
}
|
||||
|
||||
func GetCoordinateCityInfo(ctx *jxcontext.Context, lng, lat float64) (name string, err error) {
|
||||
name, _ = api.TencentMapAPI.GetCoordinateCityInfo(lng, lat)
|
||||
name, _ = api.AutonaviAPI.GetCoordinateCityInfo(lng, lat)
|
||||
return name, err
|
||||
}
|
||||
|
||||
func SendMsg2Somebody(ctx *jxcontext.Context, mobileNum, verifyCode, msgType, msgContent string) (err error) {
|
||||
if needConfirmRequestMap[msgType] == 1 {
|
||||
if _, err = mobile.AutherObj.VerifySecret(mobileNum, verifyCode); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
db := dao.GetDB()
|
||||
//获取门店信息
|
||||
var (
|
||||
stores []*model.Store
|
||||
authBinds []*model.AuthBind
|
||||
order *model.GoodsOrder
|
||||
storeName string
|
||||
storeID int
|
||||
vendorOrderID string
|
||||
)
|
||||
if mobileNum != "" {
|
||||
sql := `
|
||||
SELECT * FROM store WHERE (tel1 = ? OR tel2 = ?) AND deleted_at = ?
|
||||
`
|
||||
sqlParams := []interface{}{mobileNum, mobileNum, utils.DefaultTimeValue}
|
||||
err = dao.GetRows(db, &stores, sql, sqlParams)
|
||||
if len(stores) > 0 {
|
||||
storeName = stores[0].Name
|
||||
storeID = stores[0].ID
|
||||
}
|
||||
if storeID == 0 {
|
||||
results := regexpMsgContentOpID.FindStringSubmatch(msgContent)
|
||||
if len(results) > 0 {
|
||||
sql3 := `
|
||||
SELECT * FROM auth_bind WHERE auth_id = ? OR auth_id2 = ?
|
||||
`
|
||||
sqlParams3 := []interface{}{results[1], results[1]}
|
||||
err = dao.GetRows(db, &authBinds, sql3, sqlParams3)
|
||||
if len(authBinds) > 0 {
|
||||
user, _ := dao.GetUserByID(db, "user_id", authBinds[0].UserID)
|
||||
mobileNum = *user.Mobile
|
||||
sqlParams4 := []interface{}{mobileNum, mobileNum, utils.DefaultTimeValue}
|
||||
err = dao.GetRows(db, &stores, sql, sqlParams4)
|
||||
if len(stores) > 0 {
|
||||
storeName = stores[0].Name
|
||||
storeID = stores[0].ID
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
results := regexpMsgContentOpID.FindStringSubmatch(msgContent)
|
||||
if len(results) > 0 {
|
||||
sql3 := `
|
||||
SELECT * FROM auth_bind WHERE auth_id = ? OR auth_id2 = ?
|
||||
`
|
||||
sqlParams3 := []interface{}{results[1], results[1]}
|
||||
err = dao.GetRows(db, &authBinds, sql3, sqlParams3)
|
||||
if len(authBinds) > 0 {
|
||||
user, _ := dao.GetUserByID(db, "user_id", authBinds[0].UserID)
|
||||
mobileNum = *user.Mobile
|
||||
sql4 := `
|
||||
SELECT * FROM store WHERE (tel1 = ? OR tel2 = ?) AND deleted_at = ?
|
||||
`
|
||||
sqlParams4 := []interface{}{mobileNum, mobileNum, utils.DefaultTimeValue}
|
||||
err = dao.GetRows(db, &stores, sql4, sqlParams4)
|
||||
if len(stores) > 0 {
|
||||
storeName = stores[0].Name
|
||||
storeID = stores[0].ID
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
sql2 := `
|
||||
SELECT *
|
||||
FROM goods_order
|
||||
WHERE IF(store_id <> '', store_id, jx_store_id) = ?
|
||||
ORDER BY order_created_at DESC
|
||||
LIMIT 1
|
||||
`
|
||||
sqlParams2 := []interface{}{storeID}
|
||||
err = dao.GetRow(db, &order, sql2, sqlParams2)
|
||||
if order != nil {
|
||||
vendorOrderID = order.VendorOrderID
|
||||
}
|
||||
if storeID == 0 {
|
||||
vendorOrderID = ""
|
||||
}
|
||||
msgContent = msgContent + " 门店名称:" + storeName + " 门店ID:" + utils.Int2Str(storeID) + " 最新订单号:" + vendorOrderID
|
||||
for _, v := range receiveMsgUsersMap[msgType] {
|
||||
user, err2 := dao.GetUserByID(db, "name", v)
|
||||
if err2 == nil {
|
||||
ddmsg.SendUserMessage(dingdingapi.MsgTyeText, user.GetID(), msgType, msgContent)
|
||||
} else if err == nil {
|
||||
err = err2
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func checkSysConfig(key, value string) (err error) {
|
||||
if limit := SysConfigLimitMap[key]; limit != nil {
|
||||
if limit.ValueType == reflect.Int {
|
||||
int64Value, err2 := strconv.ParseInt(value, 10, 64)
|
||||
if err = err2; err == nil {
|
||||
if int64Value < limit.MinValue || int64Value > limit.MaxValue {
|
||||
err = fmt.Errorf("配置%s,值%s超范围[%d,%d]", key, value, limit.MinValue, limit.MaxValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func onSysConfigChanged(key, value string) (err error) {
|
||||
if limit := SysConfigLimitMap[key]; limit != nil && limit.AfterChanged != nil {
|
||||
err = limit.AfterChanged()
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func checkConfig(opFlag int, configType, key, value string) (err error) {
|
||||
switch configType {
|
||||
case model.ConfigTypePricePack:
|
||||
if value != "" {
|
||||
pricePack := dao.PricePercentagePack2Obj(value)
|
||||
if pricePack == nil {
|
||||
err = fmt.Errorf("配置:%s不合法", value)
|
||||
}
|
||||
}
|
||||
case model.ConfigTypeFreightPack:
|
||||
if value != "" {
|
||||
freightPack := dao.FreightDeductionPack2Obj(value)
|
||||
if freightPack == nil {
|
||||
err = fmt.Errorf("配置:%s不合法", value)
|
||||
} else {
|
||||
var lastStage *model.FreightDeductionItem
|
||||
for _, v := range freightPack.FreightDeductionList {
|
||||
if lastStage != nil && lastStage.DeductFreight > v.DeductFreight {
|
||||
err = fmt.Errorf("免运设置不合理:门槛:%s,免运金额:%s,门槛:%s,免运金额:%s",
|
||||
jxutils.IntPrice2StandardString(int64(lastStage.BeginPrice)), jxutils.IntPrice2StandardString(int64(lastStage.DeductFreight)),
|
||||
jxutils.IntPrice2StandardString(int64(v.BeginPrice)), jxutils.IntPrice2StandardString(int64(v.DeductFreight)))
|
||||
return err
|
||||
}
|
||||
lastStage = v
|
||||
}
|
||||
}
|
||||
}
|
||||
case model.ConfigTypeBank:
|
||||
if value != "" {
|
||||
if model.BankName[key] == "" {
|
||||
err = fmt.Errorf("此银行代码:%s不支持,请联系开发", value)
|
||||
}
|
||||
}
|
||||
case model.ConfigTypeRole:
|
||||
case model.ConfigTypeSys:
|
||||
if opFlag&( /*model.SyncFlagNewMask|*/ model.SyncFlagDeletedMask) != 0 {
|
||||
err = fmt.Errorf("系统参数只支持修改或添加,不支持删除")
|
||||
} else {
|
||||
err = checkSysConfig(key, value)
|
||||
}
|
||||
case model.ConfigTypeJxStore:
|
||||
case model.ConfigTypeCookie:
|
||||
case model.ConfigTypeDiscountCard:
|
||||
default:
|
||||
err = fmt.Errorf("当前只支持配置:%s, 传入的配置类型:%s", utils.Format4Output(model.ConfigTypeName, true), configType)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func AddConfig(ctx *jxcontext.Context, key, configType, value string) (err error) {
|
||||
if err = checkConfig(model.SyncFlagNewMask, configType, key, value); err != nil {
|
||||
return err
|
||||
}
|
||||
// if err = checkConfig(model.SyncFlagNewMask, configType, key, value); err != nil {
|
||||
// return err
|
||||
// }
|
||||
|
||||
db := dao.GetDB()
|
||||
conf := &model.NewConfig{
|
||||
@@ -417,41 +182,21 @@ func AddConfig(ctx *jxcontext.Context, key, configType, value string) (err error
|
||||
dao.WrapAddIDCULDEntity(conf, ctx.GetUserName())
|
||||
err = dao.CreateEntity(db, conf)
|
||||
if configType == model.ConfigTypeSys && err == nil {
|
||||
err = onSysConfigChanged(key, value)
|
||||
// err = onSysConfigChanged(key, value)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func DeleteConfig(ctx *jxcontext.Context, key, configType string) (err error) {
|
||||
if err = checkConfig(model.SyncFlagDeletedMask, configType, key, ""); err != nil {
|
||||
return err
|
||||
}
|
||||
// if err = checkConfig(model.SyncFlagDeletedMask, configType, key, ""); err != nil {
|
||||
// return err
|
||||
// }
|
||||
db := dao.GetDB()
|
||||
switch configType {
|
||||
case model.ConfigTypePricePack:
|
||||
storeMapList, err2 := dao.GetStoresMapList(db, nil, nil, nil, model.StoreStatusAll, model.StoreIsSyncYes, key, "", "")
|
||||
if err = err2; err == nil {
|
||||
var storeInfo []string
|
||||
for _, v := range storeMapList {
|
||||
storeInfo = append(storeInfo, fmt.Sprintf("门店:%d, 平台:%s", v.StoreID, model.VendorChineseNames[v.VendorID]))
|
||||
}
|
||||
if len(storeInfo) > 0 {
|
||||
err = fmt.Errorf("还有门店在使用价格包:%s,门店信息:%s", key, strings.Join(storeInfo, ","))
|
||||
}
|
||||
}
|
||||
|
||||
case model.ConfigTypeFreightPack:
|
||||
storeMapList, err2 := dao.GetStoresMapList(db, nil, nil, nil, model.StoreStatusAll, model.StoreIsSyncYes, "", "", "")
|
||||
if err = err2; err == nil {
|
||||
var storeInfo []string
|
||||
for _, v := range storeMapList {
|
||||
if v.FreightDeductionPack == key {
|
||||
storeInfo = append(storeInfo, fmt.Sprintf("门店:%d, 平台:%s", v.StoreID, model.VendorChineseNames[v.VendorID]))
|
||||
}
|
||||
}
|
||||
if len(storeInfo) > 0 {
|
||||
err = fmt.Errorf("还有门店在使用价格包:%s,门店信息:%s", key, strings.Join(storeInfo, ","))
|
||||
}
|
||||
}
|
||||
|
||||
case model.ConfigTypeBank:
|
||||
//todo
|
||||
return fmt.Errorf("暂不支持删除银行")
|
||||
@@ -459,7 +204,7 @@ func DeleteConfig(ctx *jxcontext.Context, key, configType string) (err error) {
|
||||
errList := errlist.New()
|
||||
userIDs, err2 := api2.RoleMan.GetRoleUserList(autils.NewRole(key, 0))
|
||||
if err = err2; err == nil && len(userIDs) > 0 {
|
||||
userList, totalCount, err2 := dao.GetUsers(dao.GetDB(), 0, "", userIDs, nil, nil, 0, -1)
|
||||
userList, totalCount, err2 := dao.GetUsers(dao.GetDB(), 0, "", "", userIDs, nil, nil, 0, -1)
|
||||
if err = err2; err == nil && totalCount > 0 {
|
||||
// todo
|
||||
// err = fmt.Errorf("还有人员在使用角色:%s,人员信息:%s", key, utils.MustMarshal(utils.Struct2Map(userList, "compact")))
|
||||
@@ -467,14 +212,7 @@ func DeleteConfig(ctx *jxcontext.Context, key, configType string) (err error) {
|
||||
}
|
||||
}
|
||||
errList.AddErr(err)
|
||||
storeList, err2 := dao.GetStoreList(db, nil, nil, nil, nil, nil, key)
|
||||
if err = err2; err == nil && len(storeList) > 0 {
|
||||
storeIDs := make([]int, len(storeList))
|
||||
for k, v := range storeList {
|
||||
storeIDs[k] = v.ID
|
||||
}
|
||||
err = fmt.Errorf("还有门店在使用角色:%s,门店信息:%s", key, utils.MustMarshal(storeIDs))
|
||||
}
|
||||
|
||||
errList.AddErr(err)
|
||||
err = errList.GetErrListAsOne()
|
||||
}
|
||||
@@ -485,7 +223,7 @@ func DeleteConfig(ctx *jxcontext.Context, key, configType string) (err error) {
|
||||
})
|
||||
}
|
||||
if configType == model.ConfigTypeSys && err == nil {
|
||||
err = onSysConfigChanged(key, "")
|
||||
// err = onSysConfigChanged(key, "")
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -494,9 +232,6 @@ func UpdateConfig(ctx *jxcontext.Context, key, configType, value string) (hint s
|
||||
if key == "" {
|
||||
return "", fmt.Errorf("修改配置必须给定key")
|
||||
}
|
||||
if err = checkConfig(model.SyncFlagModifiedMask, configType, key, value); err != nil {
|
||||
return "", err
|
||||
}
|
||||
hint = "1"
|
||||
|
||||
db := dao.GetDB()
|
||||
@@ -520,54 +255,12 @@ func UpdateConfig(ctx *jxcontext.Context, key, configType, value string) (hint s
|
||||
}
|
||||
switch configType {
|
||||
case model.ConfigTypePricePack:
|
||||
storeMapList, err := dao.GetStoresMapList(db, nil, nil, nil, model.StoreStatusAll, model.StoreIsSyncYes, key, "", "")
|
||||
if err != nil {
|
||||
dao.Rollback(db, txDB)
|
||||
return "", err
|
||||
}
|
||||
dao.Commit(db, txDB)
|
||||
vendorStoreMap := make(map[int][]int)
|
||||
for _, v := range storeMapList {
|
||||
vendorStoreMap[v.VendorID] = append(vendorStoreMap[v.VendorID], v.StoreID)
|
||||
}
|
||||
for vendorID, storeIDs := range vendorStoreMap {
|
||||
if vendorID != model.VendorIDJX {
|
||||
dao.SetStoreSkuSyncStatus(db, vendorID, storeIDs, nil, model.SyncFlagPriceMask)
|
||||
} else {
|
||||
hint, err = ReCalculateJxPrice(db, ctx, storeIDs)
|
||||
}
|
||||
}
|
||||
case model.ConfigTypeFreightPack:
|
||||
dao.Commit(db, txDB)
|
||||
storeMapList, err := dao.GetStoresMapList(db, nil, nil, nil, model.StoreStatusAll, model.StoreIsSyncYes, "", "", "")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
for _, v := range storeMapList {
|
||||
var storeMapList2 []*model.StoreMap
|
||||
if v.FreightDeductionPack == key {
|
||||
storeMapList2 = append(storeMapList2, v)
|
||||
}
|
||||
if len(storeMapList2) > 0 {
|
||||
task := tasksch.NewParallelTask("同步门店配送免运", tasksch.NewParallelConfig().SetIsContinueWhenError(true), ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
storeMap := batchItemList[0].(*model.StoreMap)
|
||||
_, err = CurVendorSync.SyncStore(ctx, db, storeMap.VendorID, storeMap.StoreID, false, ctx.GetUserName())
|
||||
return retVal, err
|
||||
}, storeMapList2)
|
||||
tasksch.HandleTask(task, nil, true).Run()
|
||||
if len(storeMapList2) < 5 {
|
||||
_, err = task.GetResult(0)
|
||||
} else {
|
||||
hint = task.GetID()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
dao.Commit(db, txDB)
|
||||
}
|
||||
if configType == model.ConfigTypeSys && err == nil {
|
||||
err = onSysConfigChanged(key, value)
|
||||
// err = onSysConfigChanged(key, value)
|
||||
}
|
||||
return hint, err
|
||||
}
|
||||
@@ -576,197 +269,105 @@ func QueryConfigs(key, configType, keyword string) (configList []*model.NewConfi
|
||||
return dao.QueryConfigs(dao.GetDB(), key, configType, keyword)
|
||||
}
|
||||
|
||||
func GetCityBankBranches(ctx *jxcontext.Context, cityCode int, bankCode string) (info map[int]map[string][]string, err error) {
|
||||
list, err := dao.GetCityBankBranches(dao.GetDB(), cityCode, bankCode)
|
||||
if err == nil && len(list) > 0 {
|
||||
info = make(map[int]map[string][]string)
|
||||
for _, v := range list {
|
||||
if info[v.CityCode] == nil {
|
||||
info[v.CityCode] = make(map[string][]string)
|
||||
}
|
||||
info[v.CityCode][v.PayeeBankCode] = append(info[v.CityCode][v.PayeeBankCode], v.PayeeBankBranchName)
|
||||
}
|
||||
}
|
||||
return info, err
|
||||
}
|
||||
|
||||
// GetSToURidingDistance 获取商家与用户间步行距离
|
||||
func GetSToURidingDistance(sLng, sLat, uLng, uLat float64, orderId string) (stepInfo interface{}, err error) {
|
||||
coordList, err := api.TencentMapAPI.TencentCoordinateChange(&tencent_map.TencentCoordinateChangeReq{
|
||||
Locations: fmt.Sprintf("%.6f,%.6f;%.6f,%.6f", sLat, sLng, uLat, uLng),
|
||||
Type: tencent_map.CoordinateChangeTypeBaidu,
|
||||
})
|
||||
|
||||
if err == nil && len(coordList) == 2 {
|
||||
param := &tencent_map.TencentCyclingPlanningReq{
|
||||
From: fmt.Sprintf("%s,%s", coordList[0].Lat, coordList[0].Lng),
|
||||
To: fmt.Sprintf("%s,%s", coordList[1].Lat, coordList[1].Lng),
|
||||
}
|
||||
if stepInfo, err = api.TencentMapAPI.WalkingDistance(param); err == nil {
|
||||
return stepInfo, nil
|
||||
}
|
||||
}
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// GetSToURidingDistance2 获取商家与用户间步行距离
|
||||
func GetSToURidingDistance2(sLng, sLat, uLng, uLat float64, orderId string, vendors []int64) (wayBill *model.Waybill, err error) {
|
||||
func InitStation(ctx *jxcontext.Context) (err error) {
|
||||
var (
|
||||
db = dao.GetDB()
|
||||
vendorMaps = map[int]int{model.VendorIDDada: 1, model.VendorIDFengNiao: 1, model.VendorIDMTPS: 1, model.VendorIDUUPT: 1, model.VendorIDSFPS: 1}
|
||||
db = dao.GetDB()
|
||||
stationMap = make(map[string]*model.StationInfo)
|
||||
stationEjyMap = make(map[string]*ejyapi.GetStationListResult)
|
||||
addList []*model.StationInfo
|
||||
updateList []*model.StationInfo
|
||||
deleteList []*model.StationInfo
|
||||
)
|
||||
|
||||
for {
|
||||
// 骑手坐标
|
||||
waybills, err := dao.GetWaybills(db, orderId, vendors)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
api.EjyAPI.SetTimestamp(time.Now().Unix())
|
||||
if stations, err := dao.GetStationList(db); len(stations) > 0 && err == nil {
|
||||
for _, v := range stations {
|
||||
stationMap[v.StationID] = v
|
||||
}
|
||||
if len(waybills) == model.NO {
|
||||
return nil, fmt.Errorf("请先创建运单,或者转自配送")
|
||||
}
|
||||
for _, v := range waybills {
|
||||
// 获取骑行路线图
|
||||
if v.OriginalData == "" && v.WaybillVendorID == model.VendorJXFakeWL {
|
||||
originalData, distance, durationTime, err2 := GetCyclingLine(sLng, sLat, uLng, uLat)
|
||||
if err2 == nil && len(originalData) != model.NO {
|
||||
v.OriginalData = strings.Join(originalData, ";")
|
||||
v.Distance = distance
|
||||
v.DurationTime = durationTime + 500
|
||||
}
|
||||
}
|
||||
|
||||
if vendorMaps[v.WaybillVendorID] == model.YES {
|
||||
// 如果是三方配送,更新骑手信息
|
||||
if handler := partner.GetDeliveryPlatformFromVendorID(v.WaybillVendorID); handler != nil {
|
||||
riderInfo, _ := handler.Handler.GetRiderInfo(v.VendorOrderID, v.ID+1000000, v.VendorWaybillID)
|
||||
if riderInfo != nil {
|
||||
if len(riderInfo.Longitude) < len("104.065861") || riderInfo.Longitude != "" {
|
||||
riderInfo.Longitude += "0"
|
||||
}
|
||||
if len(riderInfo.Latitude) < len("27.934441") || riderInfo.Latitude != "" {
|
||||
riderInfo.Latitude += "0"
|
||||
}
|
||||
v.CourierCoordinate = fmt.Sprintf("%s,%s", riderInfo.Longitude, riderInfo.Latitude)
|
||||
if (v.CourierName == "" || v.CourierMobile == "") && riderInfo.CourierName != "" {
|
||||
v.CourierName = riderInfo.CourierName
|
||||
v.CourierMobile = riderInfo.CourierPhone
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if getStationListResult, err := api.EjyAPI.GetStationList(); len(getStationListResult) > 0 && err == nil {
|
||||
for _, v := range getStationListResult {
|
||||
stationEjyMap[v.StationID] = v
|
||||
if stationMap[v.StationID] == nil {
|
||||
addList = append(addList, EjyStationToStationInfo(v))
|
||||
} else {
|
||||
// 如果是平台配送,获取骑手信息
|
||||
if handler := partner.GetPurchaseOrderHandlerFromVendorID(v.WaybillVendorID); handler != nil {
|
||||
riderInfo, _ := handler.OrderLogisticsStatus(v.VendorOrderID)
|
||||
if riderInfo != nil {
|
||||
if len(riderInfo.Longitude) < len("104.065861") || riderInfo.Longitude != "" {
|
||||
riderInfo.Longitude += "0"
|
||||
}
|
||||
if len(riderInfo.Latitude) < len("27.934441") || riderInfo.Latitude != "" {
|
||||
riderInfo.Latitude += "0"
|
||||
}
|
||||
v.CourierCoordinate = fmt.Sprintf("%s,%s", riderInfo.Longitude, riderInfo.Latitude)
|
||||
if (v.CourierName == "" || v.CourierMobile == "") && riderInfo.CourierName != "" {
|
||||
v.CourierName = riderInfo.CourierName
|
||||
v.CourierMobile = riderInfo.CourierPhone
|
||||
}
|
||||
}
|
||||
}
|
||||
updateList = append(updateList, stationMap[v.StationID])
|
||||
}
|
||||
|
||||
// 当这个运单为假物流/门店真实自送/获取运单骑手信息为空的时候使用假的骑手信息
|
||||
if (v.WaybillVendorID == model.VendorJXFakeWL || v.WaybillVendorID == model.VendorIDUnknown || v.CourierCoordinate == "") && v.OriginalData != "" {
|
||||
riderLine := strings.Split(v.OriginalData, ";") // 路线坐标点
|
||||
|
||||
courierDistance := float64(time.Now().Unix()-v.WaybillCreatedAt.Unix()) * (float64(v.Distance) / float64(v.DurationTime)) // 当前骑手骑行距离
|
||||
if courierDistance >= float64(v.Distance) {
|
||||
courierDistance = float64(v.Distance)
|
||||
}
|
||||
nowCourierDrop := int64(math.Ceil((courierDistance / float64(v.Distance)) * float64(len(riderLine)))) // 当前骑手骑行距离,占中的骑行距离百分比.
|
||||
if nowCourierDrop >= int64(len(riderLine)) {
|
||||
v.CourierCoordinate = riderLine[nowCourierDrop-1]
|
||||
}
|
||||
if nowCourierDrop <= 0 {
|
||||
v.CourierCoordinate = riderLine[0]
|
||||
}
|
||||
if v.Status >= model.WaybillStatusDelivered {
|
||||
v.CourierCoordinate = riderLine[len(riderLine)-1]
|
||||
}
|
||||
if v.Status == model.WaybillStatusCourierArrived {
|
||||
order, _ := partner.CurOrderManager.LoadOrder(orderId, v.OrderVendorID)
|
||||
storeDetail, err := dao.GetStoreDetail2(dao.GetDB(), order.JxStoreID, order.VendorStoreID, order.VendorID)
|
||||
if err == nil && storeDetail != nil {
|
||||
v.CourierCoordinate = fmt.Sprintf("%s,%s", utils.Float64ToStr(jxutils.IntCoordinate2Standard(storeDetail.Lng)), utils.Float64ToStr(jxutils.IntCoordinate2Standard(storeDetail.Lat)))
|
||||
}
|
||||
}
|
||||
if v.CourierCoordinate == "" {
|
||||
v.CourierCoordinate = riderLine[nowCourierDrop]
|
||||
}
|
||||
|
||||
} else if (v.WaybillVendorID == model.VendorJXFakeWL || v.WaybillVendorID == model.VendorIDUnknown || v.CourierCoordinate == "") && v.OriginalData == "" {
|
||||
lng := utils.Str2Float64(fmt.Sprintf("%0.6f", (sLng-uLng)/float64(300)))
|
||||
lat := utils.Str2Float64(fmt.Sprintf("%0.6f", (sLat-uLat)/float64(300)))
|
||||
originalData := make([]string, 0, 0)
|
||||
originalData = append(originalData, fmt.Sprintf("%.6f,%.6f", sLng, sLat))
|
||||
var nLng float64
|
||||
var nLat float64
|
||||
for i := 1; i <= 300; i++ {
|
||||
if sLng > uLng {
|
||||
nLng = sLng - (lng * float64(i))
|
||||
} else {
|
||||
nLng = sLng + (lng * float64(i))
|
||||
}
|
||||
if sLat > uLat {
|
||||
nLat = sLat - (lat * float64(i))
|
||||
} else {
|
||||
nLat = sLat + (lat * float64(i))
|
||||
}
|
||||
fakeCourier := fmt.Sprintf("%.6f,%.6f", nLng, nLat)
|
||||
originalData = append(originalData, fakeCourier)
|
||||
}
|
||||
originalData = append(originalData, fmt.Sprintf("%.6f,%.6f", uLng, uLat))
|
||||
|
||||
v.Distance = 5001 // 距离,固定
|
||||
v.DurationTime = 600 // 固定骑行时间
|
||||
v.OriginalData = strings.Join(originalData, ";")
|
||||
v.CourierCoordinate = originalData[0]
|
||||
}
|
||||
|
||||
dao.UpdateEntity(db, v, "OriginalData", "CourierCoordinate", "Distance", "DurationTime")
|
||||
if v.CourierName == "" || v.CourierMobile == "" {
|
||||
v.CourierName = "暂无骑手"
|
||||
v.CourierMobile = "暂无电话"
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
||||
}
|
||||
for _, v := range stationMap {
|
||||
if stationEjyMap[v.StationID] == nil {
|
||||
deleteList = append(deleteList, v)
|
||||
}
|
||||
}
|
||||
task := tasksch.NewParallelTask("InitStation", tasksch.NewParallelConfig().SetParallelCount(1).SetIsContinueWhenError(true), ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
step := batchItemList[0].(int)
|
||||
switch step {
|
||||
case 0:
|
||||
if len(addList) > 0 {
|
||||
err = dao.CreateMultiEntities(db, addList)
|
||||
}
|
||||
case 1:
|
||||
if len(updateList) > 0 {
|
||||
task := tasksch.NewParallelTask("updateList", tasksch.NewParallelConfig().SetParallelCount(1).SetIsContinueWhenError(true), ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
station := batchItemList[0].(*model.StationInfo)
|
||||
dao.UpdateEntity(db, station)
|
||||
return retVal, err
|
||||
}, updateList)
|
||||
tasksch.HandleTask(task, nil, true).Run()
|
||||
_, err = task.GetResult(0)
|
||||
}
|
||||
case 2:
|
||||
if len(deleteList) > 0 {
|
||||
task := tasksch.NewParallelTask("deleteList", tasksch.NewParallelConfig().SetParallelCount(1).SetIsContinueWhenError(true), ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
station := batchItemList[0].(*model.StationInfo)
|
||||
dao.DeleteEntity(db, station)
|
||||
return retVal, err
|
||||
}, deleteList)
|
||||
tasksch.HandleTask(task, nil, true).Run()
|
||||
_, err = task.GetResult(0)
|
||||
}
|
||||
}
|
||||
return retVal, err
|
||||
}, []int{0, 1, 2})
|
||||
tasksch.HandleTask(task, nil, true).Run()
|
||||
_, err = task.GetResult(0)
|
||||
return err
|
||||
}
|
||||
|
||||
// GetCyclingLine 获取骑行路线
|
||||
func GetCyclingLine(sLng, sLat, uLng, uLat float64) (polyLineList []string, distance, duration int64, err error) {
|
||||
// 百度
|
||||
/* var coords []*baidunavi.Coordinate
|
||||
coords = append(coords, &baidunavi.Coordinate{
|
||||
Lng: sLng,
|
||||
Lat: sLat,
|
||||
}, &baidunavi.Coordinate{
|
||||
Lat: uLat,
|
||||
Lng: uLng,
|
||||
})*/
|
||||
|
||||
// 高德坐标转换成百度坐标
|
||||
/*coords, err := api.TencentMapAPI.TencentCoordinateChange(&tencent_map.TencentCoordinateChangeReq{
|
||||
Locations: fmt.Sprintf("%.6f,%.6f;%.6f,%.6f", sLat, sLng, uLat, uLng),
|
||||
Type: tencent_map.CoordinateChangeTypeBaidu,
|
||||
})
|
||||
if err != nil || len(coords) <= model.NO {
|
||||
return nil, 0, 0, err
|
||||
func EjyStationToStationInfo(station *ejyapi.GetStationListResult) (stationInfo *model.StationInfo) {
|
||||
stationInfo = &model.StationInfo{
|
||||
StationID: station.StationID,
|
||||
StationName: station.StationName,
|
||||
ProvinceName: station.ProvinceName,
|
||||
ProvinceID: station.ProvinceID,
|
||||
CityName: station.CityName,
|
||||
Latitude: utils.Str2Float64(station.Latitude),
|
||||
Longitude: utils.Str2Float64(station.Longitude),
|
||||
Location: station.Location,
|
||||
StarNum: station.StarNum,
|
||||
Phone: station.Phone,
|
||||
StationPic: station.StationPic,
|
||||
StationBannerPic: station.StationBannerPic,
|
||||
District: station.District,
|
||||
CityID: station.CityID,
|
||||
StationType: station.StationType,
|
||||
}
|
||||
*/
|
||||
distance, duration, polyLineList, err = api.TencentMapAPI.TencentCyclingPlanning(&tencent_map.TencentCyclingPlanningReq{
|
||||
From: fmt.Sprintf("%.6f,%.6f", sLat, sLng),
|
||||
To: fmt.Sprintf("%.6f,%.6f", uLat, uLng),
|
||||
})
|
||||
return
|
||||
if station.Prices != nil {
|
||||
if data, err := json.Marshal(station.Prices); err == nil {
|
||||
stationInfo.Prices = string(data)
|
||||
}
|
||||
}
|
||||
if station.Adverts != nil {
|
||||
if data, err := json.Marshal(station.Adverts); err == nil {
|
||||
stationInfo.Adverts = string(data)
|
||||
}
|
||||
}
|
||||
return stationInfo
|
||||
}
|
||||
|
||||
func GetStationList(ctx *jxcontext.Context, stationName string, cityCode int, lat, lng float64, oilCode string, sortType, offset, pageSize int) (pageInfo *model.PagedInfo, err error) {
|
||||
return dao.GetStationInfoList(dao.GetDB(), stationName, cityCode, lat, lng, oilCode, sortType, offset, pageSize)
|
||||
}
|
||||
|
||||
@@ -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
@@ -68,16 +68,17 @@ func GetStoreMessages(ctx *jxcontext.Context, msgIDs, storeIDs, types []int, fro
|
||||
txDB, _ := dao.Begin(db)
|
||||
defer dao.Commit(db, txDB)
|
||||
var msgList []*model.Message
|
||||
// globals.SugarLogger.Debug(sql)
|
||||
if err = dao.GetRowsTx(txDB, &msgList, sql, sqlParams...); err == nil {
|
||||
pagedInfo = &model.PagedInfo{
|
||||
TotalCount: dao.GetLastTotalRowCount2(db, txDB),
|
||||
TotalCount: dao.GetLastTotalRowCountTx(txDB),
|
||||
Data: msgList,
|
||||
}
|
||||
}
|
||||
return pagedInfo, err
|
||||
}
|
||||
|
||||
func GetStoreMessageStatuses(ctx *jxcontext.Context, msgIDs, storeIDs, confirmStatuss []int, fromReadCount, toReadCount int, fromTime, toTime time.Time, keyword string, offset, pageSize int) (pagedInfo *model.PagedInfo, err error) {
|
||||
func GetStoreMessageStatuses(ctx *jxcontext.Context, msgIDs, storeIDs []int, fromReadCount, toReadCount int, fromTime, toTime time.Time, keyword string, offset, pageSize int) (pagedInfo *model.PagedInfo, err error) {
|
||||
sql := `
|
||||
SELECT SQL_CALC_FOUND_ROWS
|
||||
t1.*,
|
||||
@@ -91,10 +92,6 @@ func GetStoreMessageStatuses(ctx *jxcontext.Context, msgIDs, storeIDs, confirmSt
|
||||
sql += " AND t1.store_id IN (" + dao.GenQuestionMarks(len(storeIDs)) + ")"
|
||||
sqlParams = append(sqlParams, storeIDs)
|
||||
}
|
||||
if len(confirmStatuss) > 0 {
|
||||
sql += " AND t1.confirm_status IN (" + dao.GenQuestionMarks(len(confirmStatuss)) + ")"
|
||||
sqlParams = append(sqlParams, confirmStatuss)
|
||||
}
|
||||
if len(msgIDs) > 0 {
|
||||
sql += " AND t1.message_id IN (" + dao.GenQuestionMarks(len(msgIDs)) + ")"
|
||||
sqlParams = append(sqlParams, msgIDs)
|
||||
@@ -126,9 +123,11 @@ func GetStoreMessageStatuses(ctx *jxcontext.Context, msgIDs, storeIDs, confirmSt
|
||||
txDB, _ := dao.Begin(db)
|
||||
defer dao.Commit(db, txDB)
|
||||
var msgStatusList []*MessageStatusExt
|
||||
// globals.SugarLogger.Debug(sql)
|
||||
// globals.SugarLogger.Debug(utils.Format4Output(sqlParams, false))
|
||||
if err = dao.GetRowsTx(txDB, &msgStatusList, sql, sqlParams...); err == nil {
|
||||
pagedInfo = &model.PagedInfo{
|
||||
TotalCount: dao.GetLastTotalRowCount2(db, txDB),
|
||||
TotalCount: dao.GetLastTotalRowCountTx(txDB),
|
||||
Data: msgStatusList,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -1,292 +0,0 @@
|
||||
package cms
|
||||
//
|
||||
//import (
|
||||
// "encoding/json"
|
||||
// "errors"
|
||||
// "fmt"
|
||||
// "git.rosy.net.cn/baseapi/utils"
|
||||
// "git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
// "git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
|
||||
// "git.rosy.net.cn/jx-callback/business/model"
|
||||
// "git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
// "git.rosy.net.cn/jx-callback/business/partner/purchase/jx/localjx"
|
||||
// "github.com/360EntSecGroup-Skylar/excelize"
|
||||
// "io"
|
||||
// "mime/multipart"
|
||||
// "strings"
|
||||
//)
|
||||
//
|
||||
//// 根据excel新增待拣货订单
|
||||
//func CreateOrderByExcel(ctx *jxcontext.Context, files []*multipart.FileHeader) (hint string, err error) {
|
||||
// if len(files) == 0 {
|
||||
// return "", errors.New("没有文件上传!")
|
||||
// }
|
||||
// fileHeader := files[0]
|
||||
// file, err := fileHeader.Open()
|
||||
// hint, err = RefreshJxPriceByExcelBin(ctx, file, true, true)
|
||||
// file.Close()
|
||||
// return hint, err
|
||||
//}
|
||||
//
|
||||
//type CreateOrderByExcelStore struct {
|
||||
// BuyerComment int // 备注
|
||||
// StoreID int // 门店id
|
||||
// Skus int // 商品列表
|
||||
// ExpectedDeliveredTimestamp int // 预期送达时间
|
||||
// TotalPrice int // 总价格
|
||||
// FreightPrice int // 运费
|
||||
// OrderPrice int // 订单价格
|
||||
// ActualPayPrice int // 顾客实际支付
|
||||
// OrderID int // 订单id
|
||||
// StoreName int // 门店名称
|
||||
// Weight int // 重量
|
||||
// FromStoreID int // 物料ID
|
||||
// EarningType int // 结算方式(1为报价,2为扣点),0无
|
||||
// OrderType int // 订单类型
|
||||
// IsBuyNowPrice int // 守价的值只有0和1
|
||||
// IsPriceDefend int
|
||||
// OrderID2 int
|
||||
// UserID int // 用户id
|
||||
// AddressID int // 收货地址id
|
||||
// CreateType int // "创建类型, 0:预创建, 1:创建"
|
||||
// IsDeliverySelf int // 自提
|
||||
//}
|
||||
//
|
||||
//// 赋值excel表字段排序
|
||||
//func SortExcelTable() *CreateOrderByExcelStore {
|
||||
// return &CreateOrderByExcelStore{
|
||||
// StoreID: 1,
|
||||
// StoreName: 2,
|
||||
// UserID: 3,
|
||||
// AddressID: 4,
|
||||
// Skus: 5,
|
||||
// Weight: 6,
|
||||
// TotalPrice: 7,
|
||||
// FreightPrice: 8,
|
||||
// OrderPrice: 9,
|
||||
// ActualPayPrice: 10,
|
||||
// ExpectedDeliveredTimestamp: 11,
|
||||
// OrderType: 12,
|
||||
// FromStoreID: 13,
|
||||
// EarningType: 14,
|
||||
// BuyerComment: 15,
|
||||
//
|
||||
// CreateType: 16,
|
||||
// IsDeliverySelf: 17,
|
||||
// IsPriceDefend: 18,
|
||||
// IsBuyNowPrice: 19,
|
||||
// OrderID: 20,
|
||||
// OrderID2: 21,
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//// 订单结构体
|
||||
//type ExcelOrderStruct struct {
|
||||
// BuyerComment string `json:"buyerComment"` // 备注
|
||||
// StoreID int `json:"storeID"`
|
||||
// Skus []*JxSkuInfo `json:"skus"`
|
||||
// ExpectedDeliveredTimestamp int64 `json:"expectedDeliveredTimestamp"` // 预期送达时间
|
||||
// TotalPrice int64 `json:"totalPrice"` // 单位为分 订单总价
|
||||
// FreightPrice int64 `json:"freightPrice"` // 单位为分 订单配送费
|
||||
// OrderPrice int64 `json:"orderPrice"` // 单位为分 订单商品价格
|
||||
// ActualPayPrice int64 `json:"actualPayPrice"` // 单位为分 顾客实际支付
|
||||
// OrderID int64 `json:"orderID"`
|
||||
// StoreName string `json:"storeName"`
|
||||
// Weight int `json:"weight"`
|
||||
// FromStoreID int `json:"fromStoreID"` //
|
||||
// EarningType int `json:"earningType"`
|
||||
// OrderType int `json:"orderType"`
|
||||
// IsBuyNowPrice int `json:"isBuyNowPrice"`
|
||||
// IsPriceDefend int `json:"isPriceDefend"`
|
||||
// OrderID2 string `json:"-"` // 订单id2
|
||||
// UserID string `json:"userID"` // 用户id
|
||||
// AddressId int64 `json:"address_id"` // 地址id
|
||||
//}
|
||||
//
|
||||
//// 商品列表
|
||||
//type JxSkuInfo struct {
|
||||
// SkuID int `json:"skuID"`
|
||||
// Count int `json:"count"`
|
||||
// Price int64 `json:"price,omitempty"` // 原价
|
||||
// SalePrice int64 `json:"salePrice,omitempty"` // 售卖价
|
||||
// Name string `json:"name"`
|
||||
// Weight int `json:"weight"`
|
||||
// GroupSign bool `json:"groupSign"`
|
||||
// DefendPrice int64 `json:"defendPrice"` //守价
|
||||
//}
|
||||
//
|
||||
//// 解析excel到订单结构体当中
|
||||
//func GetCellIntoOrder(rowNum int, row []string, sheetParam *CreateOrderByExcelStore, order *ExcelOrderStruct, nameMap map[string]string) (errMsg string) {
|
||||
// address := make(map[string]int64, 0)
|
||||
// for k, cell := range row {
|
||||
// switch k {
|
||||
// case sheetParam.StoreID:
|
||||
// order.StoreID = utils.Str2Int(cell)
|
||||
// case sheetParam.StoreName:
|
||||
// order.StoreName = cell
|
||||
// case sheetParam.UserID:
|
||||
// order.UserID = cell
|
||||
// case sheetParam.AddressID:
|
||||
// order.AddressId = utils.Str2Int64(cell)
|
||||
// case sheetParam.Skus:
|
||||
// shop := make([]*JxSkuInfo, 0, 0)
|
||||
// if err := json.Unmarshal([]byte(cell), shop); err != nil {
|
||||
// return fmt.Sprintf("解析excel文档用户商品列表错,检查数据格式是否正确")
|
||||
// }
|
||||
// order.Skus = shop
|
||||
// case sheetParam.Weight:
|
||||
// order.Weight = utils.Str2Int(cell)
|
||||
// case sheetParam.TotalPrice:
|
||||
// order.TotalPrice = utils.Str2Int64(cell)
|
||||
// case sheetParam.FreightPrice:
|
||||
// order.FreightPrice = utils.Str2Int64(cell)
|
||||
// case sheetParam.OrderPrice:
|
||||
// order.OrderPrice = utils.Str2Int64(cell)
|
||||
// case sheetParam.ActualPayPrice:
|
||||
// order.ActualPayPrice = utils.Str2Int64(cell)
|
||||
// case :
|
||||
//
|
||||
//
|
||||
//
|
||||
// }
|
||||
//
|
||||
// if k == sheetParam.SkuNameIDCol {
|
||||
// cellReplace := strings.ReplaceAll(cell, ",", ",")
|
||||
// if cellReplace != "" {
|
||||
// if cellReplace[len(cellReplace)-1:len(cellReplace)] == "," {
|
||||
// cellReplace = cellReplace[0 : len(cellReplace)-1]
|
||||
// }
|
||||
// nameIDs := strings.Split(cellReplace, ",")
|
||||
// for _, v := range nameIDs {
|
||||
// if nameMap[v] != "" {
|
||||
// return fmt.Sprintf(" Excel中含有重复的nameID![%v]列,[%v]行,nameID [%v]\n", k+1, rowNum+1, v)
|
||||
// } else {
|
||||
// nameMap[v] = v
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// storeSkuNamePrice.NameIDGroup = cellReplace
|
||||
// }
|
||||
// if k == sheetParam.SkuPriceCol {
|
||||
// if IsChineseChar(cell) {
|
||||
// return fmt.Sprintf("Excel格式排版发生了变化!在[%v]列,[%v]行附近可能增加或减少了一列", k+1, rowNum+1)
|
||||
// }
|
||||
// storeSkuNamePrice.Price = int(utils.Float64TwoInt64(utils.Str2Float64(cell) * 100))
|
||||
// }
|
||||
// if k == sheetParam.SkuUnitCol {
|
||||
// storeSkuNamePrice.Unit = cell
|
||||
// }
|
||||
// }
|
||||
// return errMsg
|
||||
//}
|
||||
//
|
||||
//func AnalysisExcelOrder(ctx *jxcontext.Context, reader io.Reader, isAsync, isContinueWhenError bool) {
|
||||
// excelSort := SortExcelTable()
|
||||
// taskSeqFunc := func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
|
||||
// switch step {
|
||||
// case 0:
|
||||
// xlsx, err := excelize.OpenReader(reader)
|
||||
// if err != nil {
|
||||
// return "", err
|
||||
// }
|
||||
// rows, _ := xlsx.GetRows(xlsx.GetSheetName(1))
|
||||
// for rowNum, row := range rows {
|
||||
// if rowNum < model.YES { // 第一行跳过
|
||||
// continue
|
||||
// }
|
||||
// storeSkuNamePrice := &localjx.JxOrderInfo{}
|
||||
// errMsg += GetCellIntoStruct(rowNum, row, excelSort, storeSkuNamePrice, nameMap)
|
||||
// storeSkuNamePriceList = append(storeSkuNamePriceList, storeSkuNamePrice)
|
||||
// }
|
||||
// if errMsg != "" {
|
||||
// return "", errors.New(errMsg)
|
||||
// } else {
|
||||
// isErr = true
|
||||
// }
|
||||
// case 1:
|
||||
// db := dao.GetDB()
|
||||
// storeSkuNamePriceListOrg, _ := dao.GetStoreSkuNamePrice(db)
|
||||
// CreateOrUpdateStoreSkuNamePriceByExcel(db, ctx, storeSkuNamePriceList, storeSkuNamePriceListOrg)
|
||||
// storeSkuNamePriceListNew, _ := dao.GetStoreSkuNamePrice(db)
|
||||
// storeSkuNamePriceMapNew := StoreSkuNamePriceList2Map(ctx, storeSkuNamePriceListNew)
|
||||
// for _, v := range storeSkuNamePriceList {
|
||||
// if storeSkuNamePriceMapNew[v.OutSkuID] != nil {
|
||||
// storeSkuNamePriceListUpdate = append(storeSkuNamePriceListUpdate, storeSkuNamePriceMapNew[v.OutSkuID])
|
||||
// }
|
||||
// }
|
||||
// taskFunc := func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
// storeSkuNamePrice := batchItemList[0].(*model.StoreSkuNamePrice)
|
||||
// var skuBindInfos []*StoreSkuBindInfo
|
||||
// nameIDGroup := strings.Split(storeSkuNamePrice.NameIDGroup, ",")
|
||||
// for _, v := range nameIDGroup {
|
||||
// if v != "" {
|
||||
// nameID := int(utils.Str2Int64(v))
|
||||
// for _, vv := range storeIDs {
|
||||
// skuList, err2 := dao.GetStoreSkusByNameIDs(db, []int{vv}, nameID)
|
||||
// err = err2
|
||||
// if len(skuList) > 0 {
|
||||
// unitPrice := 0
|
||||
// if skuList[0].Unit == model.UnitNames[0] {
|
||||
// if storeSkuNamePrice.Unit == "KG" {
|
||||
// unitPrice = storeSkuNamePrice.Price / 2
|
||||
// } else {
|
||||
// unitPrice = storeSkuNamePrice.Price
|
||||
// }
|
||||
// } else {
|
||||
// unitPrice = storeSkuNamePrice.Price
|
||||
// }
|
||||
// storeSkuBindInfo := &StoreSkuBindInfo{
|
||||
// NameID: nameID,
|
||||
// UnitPrice: unitPrice,
|
||||
// }
|
||||
// skuBindInfos = append(skuBindInfos, storeSkuBindInfo)
|
||||
// outSuccess := DataSuccess{
|
||||
// NameID: nameID,
|
||||
// Name: skuList[0].Name,
|
||||
// Unit: storeSkuNamePrice.Unit,
|
||||
// OrgPrice: utils.Str2Float64(utils.Int64ToStr(skuList[0].UnitPrice)) / 100,
|
||||
// NowPrice: utils.Str2Float64(utils.Int64ToStr(int64(unitPrice))) / 100,
|
||||
// MixPrice: utils.Str2Float64(utils.Int64ToStr(int64(unitPrice)-skuList[0].UnitPrice)) / 100,
|
||||
// }
|
||||
// dataLock.AppendDataSuccess(outSuccess)
|
||||
// } else {
|
||||
// //京西xx门店没有关注该商品
|
||||
// outFailed := DataFailed{
|
||||
// NameID: nameID,
|
||||
// Name: storeSkuNamePrice.Name,
|
||||
// Comment: fmt.Sprintf("京西[%v]门店没有关注该商品,商品nameID[%v],Excel上商品名[%v]", vv, nameID, storeSkuNamePrice.Name),
|
||||
// }
|
||||
// dataLock.AppendDataFailed(outFailed)
|
||||
// }
|
||||
// }
|
||||
// } else {
|
||||
// //nameID为空,还未填写nameID
|
||||
// outFailed := DataFailed{
|
||||
// NameID: 0,
|
||||
// Name: storeSkuNamePrice.Name,
|
||||
// Comment: fmt.Sprintf("商品nameID为空!,还未填写商品nameID,Excel上商品名[%v]", storeSkuNamePrice.Name),
|
||||
// }
|
||||
// dataLock.AppendDataFailed(outFailed)
|
||||
// }
|
||||
// }
|
||||
// retVal = skuBindInfos
|
||||
// return retVal, err
|
||||
// }
|
||||
// taskParallel := tasksch.NewParallelTask("刷新京西价", tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError), ctx, taskFunc, storeSkuNamePriceListUpdate)
|
||||
// tasksch.HandleTask(taskParallel, task, true).Run()
|
||||
// skuBindInfosInter, err = taskParallel.GetResult(0)
|
||||
// case 2:
|
||||
// //更新京西价
|
||||
// for _, v := range skuBindInfosInter {
|
||||
// skuBindInfoList = append(skuBindInfoList, v.(*StoreSkuBindInfo))
|
||||
// }
|
||||
// if isErr {
|
||||
// UpdateStoresSkus(ctx, 0, storeIDs, skuBindInfoList, false, false, isAsync, isContinueWhenError)
|
||||
// }
|
||||
// case 3:
|
||||
// //写Excel
|
||||
// WriteToExcelJx(task, dataLock.dataSuccessList, dataLock.dataFailedList)
|
||||
// }
|
||||
// return result, err
|
||||
// }
|
||||
//}
|
||||
@@ -1,16 +1,9 @@
|
||||
package permission
|
||||
package cms
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
|
||||
"git.rosy.net.cn/jx-callback/globals/api2"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
@@ -18,17 +11,10 @@ import (
|
||||
|
||||
func GetMenu(ctx *jxcontext.Context, userID string) (menus []*model.Menu, err error) {
|
||||
if userID == "" {
|
||||
return dao.GetMenu(dao.GetDB(), "", 0, 0, userID)
|
||||
return dao.GetMenu(dao.GetDB(), "", 0, userID)
|
||||
} else {
|
||||
if user, err := dao.GetUserByID(dao.GetDB(), "user_id", userID); err == nil {
|
||||
if user.Type&model.UserTypeRole != 0 {
|
||||
return dao.GetMenuWithUser(dao.GetDB(), "", 0, 0, userID)
|
||||
} else {
|
||||
return dao.GetMenu(dao.GetDB(), "", 0, 0, "")
|
||||
}
|
||||
}
|
||||
return dao.GetMenuWithUser(dao.GetDB(), "", 0, userID)
|
||||
}
|
||||
return dao.GetMenu(dao.GetDB(), "", 0, 0, userID)
|
||||
}
|
||||
|
||||
func AddMenu(ctx *jxcontext.Context, menu *model.Menu) (err error) {
|
||||
@@ -41,7 +27,7 @@ func AddMenu(ctx *jxcontext.Context, menu *model.Menu) (err error) {
|
||||
if menu.Name == "" || menu.Level == 0 {
|
||||
return fmt.Errorf("添加失败!menu 名称和等级必须有值!")
|
||||
}
|
||||
menus, err := dao.GetMenu(db, menu.Name, menu.Level, 0, "")
|
||||
menus, err := dao.GetMenu(db, menu.Name, menu.Level, "")
|
||||
if len(menus) > 0 {
|
||||
return fmt.Errorf("添加失败!已存在相同名称的 menu name : %v", menu.Name)
|
||||
}
|
||||
@@ -91,36 +77,15 @@ func UpdateMenu(ctx *jxcontext.Context, menuID int, payload map[string]interface
|
||||
return num, err
|
||||
}
|
||||
|
||||
func GetRole(ctx *jxcontext.Context, name string) (roles []*model.Role, err error) {
|
||||
var (
|
||||
db = dao.GetDB()
|
||||
)
|
||||
roles, err = dao.GetRole(db, name, "")
|
||||
task := tasksch.NewParallelTask("GetRole", tasksch.NewParallelConfig().SetIsContinueWhenError(true), ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
v := batchItemList[0].(*model.Role)
|
||||
if v.CityCodes != "" {
|
||||
if cityInfos, err := dao.GetPlaces(db, jxutils.StrListToIntList(strings.Split(v.CityCodes, ","))); err == nil {
|
||||
v.CityInfo = cityInfos
|
||||
}
|
||||
}
|
||||
if v.StoreIDs != "" {
|
||||
if stores, err := dao.GetStoreList(db, jxutils.StrListToIntList(strings.Split(v.StoreIDs, ",")), nil, nil, nil, nil, ""); err == nil {
|
||||
v.Stores = stores
|
||||
}
|
||||
}
|
||||
return retVal, err
|
||||
}, roles)
|
||||
tasksch.HandleTask(task, nil, false).Run()
|
||||
task.GetResult(0)
|
||||
return roles, err
|
||||
func GetRole(ctx *jxcontext.Context) (roles []*model.Role, err error) {
|
||||
return dao.GetRole(dao.GetDB(), "")
|
||||
}
|
||||
|
||||
func AddRole(ctx *jxcontext.Context, name string) (err error) {
|
||||
var (
|
||||
db = dao.GetDB()
|
||||
)
|
||||
roles, err := dao.GetRole(db, "", name)
|
||||
roles, err := dao.GetRole(db, name)
|
||||
if len(roles) > 0 {
|
||||
return fmt.Errorf("添加失败!已存在相同名称的 role name : %v", name)
|
||||
}
|
||||
@@ -140,18 +105,10 @@ func AddRole(ctx *jxcontext.Context, name string) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
func UpdateRole(ctx *jxcontext.Context, roleID int, name string, isDelete bool, brandID int, cityCodes, storeIDs []int) (num int64, err error) {
|
||||
func UpdateRole(ctx *jxcontext.Context, roleID int, name string, isDelete bool) (num int64, err error) {
|
||||
var (
|
||||
db = dao.GetDB()
|
||||
cityCodesStr []string
|
||||
storeIDsStr []string
|
||||
db = dao.GetDB()
|
||||
)
|
||||
for _, v := range cityCodes {
|
||||
cityCodesStr = append(cityCodesStr, utils.Int2Str(v))
|
||||
}
|
||||
for _, v := range storeIDs {
|
||||
storeIDsStr = append(storeIDsStr, utils.Int2Str(v))
|
||||
}
|
||||
if roleID == 1 {
|
||||
return 0, fmt.Errorf("管理员不允许修改!")
|
||||
}
|
||||
@@ -172,10 +129,7 @@ func UpdateRole(ctx *jxcontext.Context, roleID int, name string, isDelete bool,
|
||||
role.Name = name
|
||||
role.UpdatedAt = time.Now()
|
||||
role.LastOperator = ctx.GetUserName()
|
||||
role.BrandID = brandID
|
||||
role.CityCodes = strings.Join(cityCodesStr, ",")
|
||||
role.StoreIDs = strings.Join(storeIDsStr, ",")
|
||||
num, err = dao.UpdateEntity(db, role, "Name", "UpdatedAt", "LastOperator", "BrandID", "CityCodes", "StoreIDs")
|
||||
num, err = dao.UpdateEntity(db, role, "Name", "UpdatedAt", "LastOperator")
|
||||
} else {
|
||||
role.DeletedAt = time.Now()
|
||||
num, err = dao.UpdateEntity(db, role, "DeletedAt")
|
||||
@@ -217,7 +171,7 @@ func UpdateUserRole(ctx *jxcontext.Context, userIDs []string, roleIDs []int) (er
|
||||
}
|
||||
nowRoleIDMap[nowRoleID] = 1
|
||||
}
|
||||
for roleID, _ := range roleIDMap {
|
||||
for _, roleID := range roleIDMap {
|
||||
if nowRoleIDMap[roleID] == 0 {
|
||||
addUserRoleMap[userID] = append(addUserRoleMap[userID], roleID)
|
||||
}
|
||||
@@ -254,12 +208,6 @@ func UpdateUserRole(ctx *jxcontext.Context, userIDs []string, roleIDs []int) (er
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, v := range userIDs {
|
||||
if user, err := dao.GetUserByID(db, "user_id", v); err == nil {
|
||||
user.Type = user.Type | model.UserTypeRole
|
||||
dao.UpdateEntity(db, user, "Type")
|
||||
}
|
||||
}
|
||||
dao.Commit(db, txDB)
|
||||
return err
|
||||
}
|
||||
@@ -297,9 +245,9 @@ func UpdateRoleMenu(ctx *jxcontext.Context, roleIDs, menuIDs []int) (err error)
|
||||
}
|
||||
nowMenuIDMap[nowMenuID] = 1
|
||||
}
|
||||
for menuID, _ := range menuIDMap {
|
||||
for _, menuID := range menuIDMap {
|
||||
if nowMenuIDMap[menuID] == 0 {
|
||||
addRoleMenuMap[roleID] = append(addRoleMenuMap[roleID], menuID)
|
||||
addRoleMenuMap[menuID] = append(addRoleMenuMap[menuID], menuID)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -337,74 +285,3 @@ func UpdateRoleMenu(ctx *jxcontext.Context, roleIDs, menuIDs []int) (err error)
|
||||
dao.Commit(db, txDB)
|
||||
return err
|
||||
}
|
||||
|
||||
func GetUserStoresResultMap(userID string) (resultMap map[int]int, err error) {
|
||||
var (
|
||||
db = dao.GetDB()
|
||||
)
|
||||
resultMap = make(map[int]int)
|
||||
user, _ := dao.GetUserByID(db, "user_id", userID)
|
||||
if user != nil && user.BindStoreID != "" {
|
||||
for _, v := range strings.Split(user.BindStoreID, ",") {
|
||||
resultMap[utils.Str2Int(v)] = utils.Str2Int(v)
|
||||
}
|
||||
return resultMap, err
|
||||
}
|
||||
userRoles, err2 := dao.GetUserRole2(db, []string{userID}, nil)
|
||||
err = err2
|
||||
for _, v := range userRoles {
|
||||
var (
|
||||
brandIDs, cityCodes, storeIDs []int
|
||||
)
|
||||
if v.CityCodes == "" && v.StoreIDs == "" {
|
||||
continue
|
||||
}
|
||||
if v.BrandID != 0 {
|
||||
brandIDs = append(brandIDs, v.BrandID)
|
||||
}
|
||||
if v.CityCodes != "0" && v.CityCodes != "" {
|
||||
cityCodes = append(cityCodes, jxutils.StrListToIntList(strings.Split(v.CityCodes, ","))...)
|
||||
}
|
||||
if v.StoreIDs != "" {
|
||||
storeIDs = append(storeIDs, jxutils.StrListToIntList(strings.Split(v.StoreIDs, ","))...)
|
||||
}
|
||||
if stores, err := dao.GetStoreList(db, storeIDs, cityCodes, nil, brandIDs, nil, ""); len(stores) > 0 && err == nil {
|
||||
for _, v := range stores {
|
||||
resultMap[v.ID] = v.ID
|
||||
}
|
||||
}
|
||||
}
|
||||
roleList, _ := api2.RoleMan.GetUserRoleList(userID)
|
||||
for _, v := range roleList {
|
||||
resultMap[v.StoreID] = v.StoreID
|
||||
}
|
||||
|
||||
return resultMap, err
|
||||
}
|
||||
|
||||
func IsRoled(ctx *jxcontext.Context) bool {
|
||||
if ctx.GetUserName() != "jxadmin" {
|
||||
userRole, _ := dao.GetUserRole(dao.GetDB(), []string{ctx.GetUserID()}, nil)
|
||||
for _, v := range userRole {
|
||||
if v.RoleID == model.YES {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
/*if user, err := dao.GetUserByID(dao.GetDB(), "user_id", ctx.GetUserID()); err == nil {
|
||||
if user.Type&model.UserTypeRole != 0 {
|
||||
return true
|
||||
}
|
||||
}*/
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func IsRoledByUserID(userID string) bool {
|
||||
if user, err := dao.GetUserByID(dao.GetDB(), "user_id", userID); err == nil {
|
||||
if user.Type&model.UserTypeRole != 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
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
@@ -1,216 +0,0 @@
|
||||
package cms
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/smsmsg"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
)
|
||||
|
||||
type StoreAcctManager struct {
|
||||
}
|
||||
|
||||
var (
|
||||
FixedStoreAcctManager *StoreAcctManager
|
||||
)
|
||||
|
||||
func init() {
|
||||
FixedStoreAcctManager = &StoreAcctManager{}
|
||||
partner.InitStoreAcctManager(FixedStoreAcctManager)
|
||||
}
|
||||
|
||||
func InsertStoreAcctIncome(ctx *jxcontext.Context, storeID, price, acctType int, vendorOrderID, vendorWaybillId string, expendID int) (err error) {
|
||||
var (
|
||||
userID, userName string
|
||||
goodsVendorOrderID string
|
||||
db = dao.GetDB()
|
||||
)
|
||||
if ctx != nil {
|
||||
userID = ctx.GetUserID()
|
||||
userName = ctx.GetUserName()
|
||||
goodsVendorOrderID = vendorOrderID
|
||||
} else {
|
||||
storeOrder := &model.StoreAcctOrder{
|
||||
VendorOrderID: vendorOrderID,
|
||||
}
|
||||
if err = dao.GetEntity(db, storeOrder, "VendorOrderID"); err == nil && storeOrder.ID != 0 {
|
||||
userID = storeOrder.UserID
|
||||
userName = storeOrder.LastOperator
|
||||
goodsVendorOrderID = storeOrder.GoodsVendorOrderID
|
||||
}
|
||||
}
|
||||
storeAcctIncome := &model.StoreAcctIncome{
|
||||
StoreID: storeID,
|
||||
IncomePrice: price,
|
||||
Type: acctType,
|
||||
UserID: userID,
|
||||
VendorOrderID: goodsVendorOrderID,
|
||||
VendorWaybillID: vendorWaybillId,
|
||||
}
|
||||
dao.WrapAddIDCULEntity(storeAcctIncome, userName)
|
||||
if expendID != 0 {
|
||||
storeAcctIncome.ExpID = expendID
|
||||
}
|
||||
err = dao.CreateEntity(db, storeAcctIncome)
|
||||
return err
|
||||
}
|
||||
|
||||
func InsertStoreAcctExpend(ctx *jxcontext.Context, storeID, price, acctType int, vendorOrderID, vendorWaybillId string, expendID int) (err error) {
|
||||
var (
|
||||
userID, userName string
|
||||
db = dao.GetDB()
|
||||
)
|
||||
if ctx != nil {
|
||||
userID = ctx.GetUserID()
|
||||
userName = ctx.GetUserName()
|
||||
} else {
|
||||
storeOrder := &model.StoreAcctOrder{
|
||||
VendorOrderID: vendorOrderID,
|
||||
}
|
||||
if err = dao.GetEntity(db, storeOrder, "VendorOrderID"); err == nil && storeOrder.ID != 0 {
|
||||
userID = storeOrder.UserID
|
||||
userName = storeOrder.LastOperator
|
||||
}
|
||||
}
|
||||
storeAcctExpend := &model.StoreAcctExpend{
|
||||
StoreID: storeID,
|
||||
ExpendPrice: price,
|
||||
Type: acctType,
|
||||
UserID: userID,
|
||||
VendorOrderID: vendorOrderID,
|
||||
VendorWaybillID: vendorWaybillId,
|
||||
}
|
||||
dao.WrapAddIDCULEntity(storeAcctExpend, userName)
|
||||
if expendID != 0 {
|
||||
storeAcctExpend.ExpID = expendID
|
||||
}
|
||||
err = dao.CreateEntity(db, storeAcctExpend)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *StoreAcctManager) UpdateStoreAcctBalance(ctx *jxcontext.Context, storeID, price int, isIncome bool) (err error) {
|
||||
var (
|
||||
db = dao.GetDB()
|
||||
)
|
||||
if ctx == nil {
|
||||
ctx = jxcontext.AdminCtx
|
||||
}
|
||||
storeAcct := &model.StoreAcct{
|
||||
StoreID: storeID,
|
||||
}
|
||||
txDB, _ := dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil || err != nil {
|
||||
dao.Rollback(db, txDB)
|
||||
if r != nil {
|
||||
panic(r)
|
||||
}
|
||||
}
|
||||
}()
|
||||
if err = dao.GetEntity(db, storeAcct, "StoreID"); err != nil && dao.IsNoRowsError(err) {
|
||||
//新增门店账单
|
||||
dao.WrapAddIDCULEntity(storeAcct, ctx.GetUserName())
|
||||
if err = dao.CreateEntityTx(txDB, storeAcct); err != nil {
|
||||
dao.Rollback(db, txDB)
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if isIncome {
|
||||
storeAcct.AccountBalance += price
|
||||
} else {
|
||||
storeAcct.AccountBalance -= price
|
||||
}
|
||||
if _, err = dao.UpdateEntityTx(txDB, storeAcct, "AccountBalance"); err != nil {
|
||||
dao.Rollback(db, txDB)
|
||||
return err
|
||||
}
|
||||
}
|
||||
dao.Commit(db, txDB)
|
||||
return err
|
||||
}
|
||||
|
||||
// 门店到账(老版本,修改门店的交易记录)
|
||||
func (s *StoreAcctManager) InsertStoreAcctExpendAndUpdateStoreAcctBalance(ctx *jxcontext.Context, storeID, price, acctType int, vendorOrderID, vendorWaybillID string, expendID int) (err error) {
|
||||
utils.CallFuncAsync(func() {
|
||||
if err = InsertStoreAcctExpend(ctx, storeID, price, acctType, vendorOrderID, vendorWaybillID, expendID); err == nil {
|
||||
s.UpdateStoreAcctBalance(ctx, storeID, price, false)
|
||||
}
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *StoreAcctManager) InsertStoreAcctIncomeAndUpdateStoreAcctBalance(ctx *jxcontext.Context, storeID, price, acctType int, vendorOrderID, vendorWaybillID string, expendID int) (err error) {
|
||||
utils.CallFuncAsync(func() {
|
||||
if err = InsertStoreAcctIncome(ctx, storeID, price, acctType, vendorOrderID, vendorWaybillID, expendID); err == nil {
|
||||
s.UpdateStoreAcctBalance(ctx, storeID, price, true)
|
||||
}
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
// 检查当前订单的状态以及支出收入比
|
||||
func (s *StoreAcctManager) CheckStoreAcctExpendExist(vendorOrderID string) (isEqual, isZero bool, err error) {
|
||||
var (
|
||||
expends, incomes int
|
||||
db = dao.GetDB()
|
||||
)
|
||||
// 当前订单的支出金额(临时运费+真实运费)[小费] partner.StoreAcctTypeExpendCreateWaybillDeductFee 违约金不参与计算,本来就要扣除
|
||||
expends, err = dao.GetStoreAcctExpendTotal(db, 0, []int{partner.StoreAcctTypeExpendCreateWaybillEx, partner.StoreAcctTypeExpendCreateWaybillTip, partner.StoreAcctTypeExpendCreateWaybill2ndMore, partner.StoreAcctTypeRealFeeExpend}, vendorOrderID, utils.ZeroTimeValue, utils.ZeroTimeValue)
|
||||
// 当前订单的退费金额()
|
||||
incomes, err = dao.GetStoreAcctIncomeTotal(db, 0, []int{partner.StoreAcctTypeRealFeeIncome, partner.StoreAcctTypeIncomeCancelTemp, partner.StoreAcctTypeIncomeCancelReal}, vendorOrderID, utils.ZeroTimeValue, utils.ZeroTimeValue)
|
||||
if expends != incomes {
|
||||
if expends > incomes {
|
||||
return false, false, err
|
||||
} else {
|
||||
globals.SugarLogger.Debugf("CheckStoreAcctExpendExist 收入大于支出! orderID:[%v]", vendorOrderID)
|
||||
}
|
||||
} else {
|
||||
if expends == 0 && incomes == 0 {
|
||||
return true, true, err
|
||||
} else {
|
||||
return true, false, err
|
||||
}
|
||||
}
|
||||
return false, false, err
|
||||
}
|
||||
|
||||
func (s *StoreAcctManager) GetStoreAcctExpendLastCreateWayBillFee(vendorOrderID string) (expend *dao.GetStoreAcctExpendLastCreateWayBillFeeResult, lastFee int, err error) {
|
||||
return dao.GetStoreAcctExpendLastCreateWayBillFee(dao.GetDB(), vendorOrderID)
|
||||
}
|
||||
|
||||
func (s *StoreAcctManager) GetBrandBalance(brandID int) (balance int, err error) {
|
||||
return dao.GetBrandBalance(dao.GetDB(), brandID)
|
||||
}
|
||||
|
||||
func (s *StoreAcctManager) InsertBrandBill(ctx *jxcontext.Context, brandID, price, billType, feeType int, vendorOrderID string, wayVendorOrderId string) (err error) {
|
||||
utils.CallFuncAsync(func() {
|
||||
var (
|
||||
db = dao.GetDB()
|
||||
)
|
||||
if price == 0 {
|
||||
return
|
||||
}
|
||||
brandBill := &model.BrandBill{
|
||||
BrandID: brandID,
|
||||
Price: price,
|
||||
BillType: billType,
|
||||
FeeType: feeType,
|
||||
VendorOrderID: vendorOrderID,
|
||||
OrderID: wayVendorOrderId,
|
||||
}
|
||||
dao.WrapAddIDCULEntity(brandBill, ctx.GetUserName())
|
||||
//扣除后,如果余额小于10元要发消息通知 ,每天通知一次
|
||||
if err = dao.CreateEntity(db, brandBill); err == nil {
|
||||
if mark := api.Cacher.Get("brandID" + utils.Int2Str(brandID)); mark == nil {
|
||||
if balance, _ := s.GetBrandBalance(brandID); balance < model.BrandBalanceLimit {
|
||||
smsmsg.NotifyBrandBalance(brandID)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
return err
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
package cms
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// 更新门店负责人信息
|
||||
func UpdateStoreOperatorConfig() {
|
||||
db := dao.GetDB()
|
||||
store, err := dao.GetStoreList(db, nil, nil, []int{-1, 0, 1}, nil, nil, "")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
userData := make(map[string][][]interface{}, 0)
|
||||
jx := make(map[string]string, 0)
|
||||
jd := make(map[string]string, 0)
|
||||
mt := make(map[string]string, 0)
|
||||
eb := make(map[string]string, 0)
|
||||
for _, v := range store {
|
||||
storeDetail, err := dao.GetStoreDetail(dao.GetDB(), v.ID, 0, "")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if storeDetail.MarketManPhone != "" { // 平台负责人jx
|
||||
jx[storeDetail.MarketManName] = storeDetail.MarketManPhone
|
||||
}
|
||||
if storeDetail.OperatorPhone != "" { // 京东负责人电话
|
||||
jd[storeDetail.OperatorName] = storeDetail.OperatorPhone
|
||||
}
|
||||
if storeDetail.OperatorPhone2 != "" { // 美团负责人电话
|
||||
mt[storeDetail.OperatorName2] = storeDetail.OperatorPhone2
|
||||
}
|
||||
if storeDetail.OperatorPhone3 != "" { // 饿了么负责人电话
|
||||
eb[storeDetail.OperatorName3] = storeDetail.OperatorPhone3
|
||||
}
|
||||
}
|
||||
userData["jx"] = Map2Slice(jx)
|
||||
userData["jd"] = Map2Slice(jd)
|
||||
userData["mt"] = Map2Slice(mt)
|
||||
userData["eb"] = Map2Slice(eb)
|
||||
// 写入配置
|
||||
byteData, err := json.Marshal(userData)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if err := dao.UpdateOperatorConfig(string(byteData), "Sys", "FZR"); err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func Map2Slice(param map[string]string) [][]interface{} {
|
||||
if len(param) <= 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
result := make([][]interface{}, 0, 0)
|
||||
for k, v := range param {
|
||||
phone, _ := strconv.Atoi(v)
|
||||
result = append(result, []interface{}{k, phone})
|
||||
}
|
||||
return result
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,163 +0,0 @@
|
||||
package cms
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
/*
|
||||
func TestGetStoresVendorSnapshot(t *testing.T) {
|
||||
result, err := GetStoresVendorSnapshot(jxcontext.AdminCtx, nil, []int{model.VendorIDEBAI}, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(utils.Format4Output(result, false))
|
||||
t.Log(len(result))
|
||||
}
|
||||
|
||||
func TestSendAlarmVendorSnapshot(t *testing.T) {
|
||||
db := dao.GetDB()
|
||||
prevSnapshotList, _ := dao.GetVendorStoreSnapshot(db, utils.Str2Time("2019-09-19 11:00:00"))
|
||||
curSnapshotList, _ := dao.GetVendorStoreSnapshot(db, utils.Str2Time("2019-09-19 15:00:00"))
|
||||
err := SendAlarmVendorSnapshot(jxcontext.AdminCtx, nil, prevSnapshotList, curSnapshotList)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateVendorStoreStatusBySnapshot(t *testing.T) {
|
||||
db := dao.GetDB()
|
||||
curSnapshotList, _ := dao.GetVendorStoreSnapshot(db, utils.Str2Time("2019-07-30 08:00:00"))
|
||||
updateVendorStoreStatusBySnapshot(db, curSnapshotList)
|
||||
}
|
||||
*/
|
||||
func TestGetBrands(t *testing.T) {
|
||||
var test bool = false
|
||||
if test {
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
func TestAbs(t *testing.T) {
|
||||
got := 1
|
||||
if got != 1 {
|
||||
t.Errorf("Abs(-1) = %d; want 1", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetBrands1(t *testing.T) {
|
||||
type args struct {
|
||||
ctx *jxcontext.Context
|
||||
name string
|
||||
brandID int
|
||||
isManage bool
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantGetBrandsResult []*GetBrandsResult
|
||||
wantErr bool
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
|
||||
}
|
||||
var test bool = false
|
||||
if test {
|
||||
return
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
gotGetBrandsResult, err := GetBrands(tt.args.ctx, tt.args.name, tt.args.brandID, tt.args.isManage)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("GetBrands() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if !reflect.DeepEqual(gotGetBrandsResult, tt.wantGetBrandsResult) {
|
||||
t.Errorf("GetBrands() gotGetBrandsResult = %v, want %v", gotGetBrandsResult, tt.wantGetBrandsResult)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestQueryPageStores2(t *testing.T) {
|
||||
type args struct {
|
||||
db *dao.DaoDB
|
||||
pageSize int
|
||||
offset int
|
||||
keyword string
|
||||
vendorStoreID string
|
||||
brandName string
|
||||
vendorID int
|
||||
cityCode int
|
||||
districtCode int
|
||||
tel string
|
||||
minShopScore float32
|
||||
minRecentOrderNum int
|
||||
minSkuCount int
|
||||
lng1 float64
|
||||
lat1 float64
|
||||
lng2 float64
|
||||
lat2 float64
|
||||
cat string
|
||||
}
|
||||
dbt := dao.GetDB()
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantPagedInfo *model.PagedInfo
|
||||
wantErr bool
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
{
|
||||
"测试1",
|
||||
args{
|
||||
dbt,
|
||||
15,
|
||||
0,
|
||||
"",
|
||||
"",
|
||||
"", //缺
|
||||
-1,
|
||||
510000,
|
||||
0, //缺
|
||||
"",
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
104.066301,
|
||||
30.572961,
|
||||
104.066301,
|
||||
30.572961,
|
||||
"",
|
||||
},
|
||||
nil,
|
||||
true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
gotPagedInfo, err := QueryPageStores2(tt.args.db, tt.args.pageSize, tt.args.offset, tt.args.keyword, tt.args.vendorStoreID, tt.args.brandName, tt.args.vendorID, tt.args.cityCode, tt.args.districtCode, tt.args.tel, tt.args.minShopScore, tt.args.minRecentOrderNum, tt.args.minSkuCount, tt.args.lng1, tt.args.lat1, tt.args.lng2, tt.args.lat2, tt.args.cat)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("QueryPageStores2() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if !reflect.DeepEqual(gotPagedInfo, tt.wantPagedInfo) {
|
||||
t.Errorf("QueryPageStores2() gotPagedInfo = %v, want %v", gotPagedInfo, tt.wantPagedInfo)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdate(t *testing.T) {
|
||||
UpdateStoreOperatorConfig()
|
||||
}
|
||||
func TestUpdateStorePoiStatus(t *testing.T) {
|
||||
var ctx *jxcontext.Context
|
||||
err := UpdateStorePoiStatus(ctx)
|
||||
fmt.Println(err)
|
||||
}
|
||||
@@ -1,135 +0,0 @@
|
||||
package cms
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/netprinter"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
)
|
||||
|
||||
type StoreManager struct {
|
||||
}
|
||||
|
||||
var (
|
||||
FixedStoreManager *StoreManager
|
||||
)
|
||||
|
||||
func init() {
|
||||
FixedStoreManager = &StoreManager{}
|
||||
partner.InitStoreManager(FixedStoreManager)
|
||||
}
|
||||
|
||||
func (s *StoreManager) OnStoreStatusChanged(vendorStoreID string, vendorID int, storeStatus int) (err error) {
|
||||
db := dao.GetDB()
|
||||
storeDetail, err := dao.GetStoreDetailByVendorStoreID(db, vendorStoreID, vendorID, "")
|
||||
if err == nil {
|
||||
if storeDetail.IsSync == model.NO || storeDetail.Status == model.StoreStatusDisabled || storeDetail.Status == model.StoreStatusHaveRest {
|
||||
return err
|
||||
}
|
||||
var storeKV, storeMapKV map[string]interface{}
|
||||
if storeStatus == model.StoreStatusOpened {
|
||||
if storeDetail.Status != model.StoreStatusOpened {
|
||||
storeKV = map[string]interface{}{
|
||||
"Status": model.StoreStatusOpened,
|
||||
}
|
||||
}
|
||||
if storeDetail.VendorStatus != model.StoreStatusOpened {
|
||||
storeMapKV = map[string]interface{}{
|
||||
"Status": model.StoreStatusOpened,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if storeDetail.Status == model.StoreStatusOpened {
|
||||
if storeDetail.VendorStatus != storeStatus {
|
||||
storeMapKV = map[string]interface{}{
|
||||
"Status": storeStatus,
|
||||
}
|
||||
}
|
||||
} else if storeDetail.Status <= storeStatus {
|
||||
if storeDetail.VendorStatus != storeStatus {
|
||||
storeMapKV = map[string]interface{}{
|
||||
"Status": storeStatus,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if err == nil && (storeKV != nil || storeMapKV != nil) {
|
||||
txDB, _ := dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil || err != nil {
|
||||
dao.Rollback(db, txDB)
|
||||
if r != nil {
|
||||
panic(r)
|
||||
}
|
||||
}
|
||||
}()
|
||||
if storeKV != nil {
|
||||
store := &model.Store{}
|
||||
store.ID = storeDetail.Store.ID
|
||||
if err = utils.CallFuncLogError(func() error {
|
||||
_, err = dao.UpdateEntityLogically(db, store, storeKV, model.AdminName, nil)
|
||||
return err
|
||||
}, "OnStoreStatusChanged Update Store venvendorStoreID:%s", vendorStoreID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if storeMapKV != nil {
|
||||
if err = utils.CallFuncLogError(func() error {
|
||||
_, err = dao.UpdateEntityLogically(db, &model.StoreMap{}, storeMapKV, model.AdminName, map[string]interface{}{
|
||||
model.FieldStoreID: storeDetail.Store.ID,
|
||||
model.FieldVendorID: vendorID,
|
||||
model.FieldDeletedAt: utils.DefaultTimeValue,
|
||||
})
|
||||
return err
|
||||
}, "OnStoreStatusChanged Update StoreMap venvendorStoreID:%s", vendorStoreID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if storeStatus != model.StoreStatusOpened {
|
||||
// 因为storeStatus != model.StoreStatusOpened不会修改京西门店的状态,所以直接用storeDetail.Status是合适的
|
||||
if err = utils.CallFuncLogError(func() error {
|
||||
return dao.FormalizeStoreStatus(db, storeDetail.Store.ID, storeDetail.Status)
|
||||
}, "OnStoreStatusChanged FormalizeStoreStatus venvendorStoreID:%s", vendorStoreID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
dao.Commit(db, txDB)
|
||||
}
|
||||
|
||||
// 打印门第离线消息
|
||||
if storeStatus < model.StoreStatusOpened && storeDetail.PrinterVendorID == model.VendorIDJxprint {
|
||||
netprinter.PrintStoreStatus(jxcontext.AdminCtx, storeDetail, vendorID, 0)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *StoreManager) OnCourierStoreStatusChanged(ctx *jxcontext.Context, vendorStoreID string, vendorID int, auditStatus int, message string) (err error) {
|
||||
if vendorStoreID != "" {
|
||||
db := dao.GetDB()
|
||||
_, err2 := dao.GetStoreDetail2(db, 0, vendorStoreID, vendorID)
|
||||
if err = err2; err == nil {
|
||||
status := model.StoreStatusOpened
|
||||
if auditStatus != model.StoreAuditStatusOnline && auditStatus != model.StoreAuditStatusUpdated {
|
||||
status = model.StoreStatusDisabled
|
||||
}
|
||||
comment := ""
|
||||
if auditStatus == model.StoreAuditStatusRejected {
|
||||
comment = message
|
||||
}
|
||||
_, err = dao.UpdateEntityLogically(db, &model.StoreCourierMap{}, map[string]interface{}{
|
||||
model.FieldStatus: status,
|
||||
"AuditStatus": auditStatus,
|
||||
"Comment": comment,
|
||||
}, ctx.GetUserName(), map[string]interface{}{
|
||||
model.FieldVendorStoreID: vendorStoreID,
|
||||
model.FieldVendorID: vendorID,
|
||||
})
|
||||
} else if dao.IsNoRowsError(err) {
|
||||
err = nil
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,742 +0,0 @@
|
||||
package cms
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"git.rosy.net.cn/jx-callback/business/partner/purchase/tiktok_store"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/baseapi/utils/errlist"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/business/partner/putils"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
)
|
||||
|
||||
type MultiStoreVendorInfo struct {
|
||||
VendorID int
|
||||
OrgCode string
|
||||
}
|
||||
|
||||
func CombineVendorIDAndOrgCode(vendorID int, orgCode string) string {
|
||||
return fmt.Sprintf("%d-%s", vendorID, orgCode)
|
||||
}
|
||||
|
||||
func getMultiStoreVendorInfoList() (list []*MultiStoreVendorInfo) {
|
||||
vendorIDs := partner.GetMultiStoreVendorIDs()
|
||||
for _, vendorID := range vendorIDs {
|
||||
orgCodeList := partner.CurAPIManager.GetAppOrgCodeList(vendorID)
|
||||
for _, v := range orgCodeList {
|
||||
list = append(list, &MultiStoreVendorInfo{
|
||||
VendorID: vendorID,
|
||||
OrgCode: v,
|
||||
})
|
||||
}
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
func syncCategories(ctx *jxcontext.Context, db *dao.DaoDB, parentTask tasksch.ITask, catList []*dao.SkuStoreCatInfo, isAsync bool) (hint string, err error) {
|
||||
if len(catList) > 0 {
|
||||
// todo 按vendorID orgCode合并操作
|
||||
task := tasksch.NewParallelTask(fmt.Sprintf("同步分类2:%d", len(catList)), tasksch.NewParallelConfig().SetIsContinueWhenError(true), ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
catVendorInfo := batchItemList[0].(*dao.SkuStoreCatInfo)
|
||||
if catVendorInfo.Level != 1 && catVendorInfo.ParentVendorCatID == "" {
|
||||
return nil, fmt.Errorf("%d的父目录%d没有同步", catVendorInfo.ID, catVendorInfo.ParentID)
|
||||
}
|
||||
if catVendorInfo.MapID == 0 {
|
||||
return nil, fmt.Errorf("分类:%d的数据异常", catVendorInfo.ID)
|
||||
}
|
||||
//表示是不用京西分类,要用平台分类
|
||||
if catVendorInfo.IsJxCat == model.YES {
|
||||
if catVendorInfo.VendorCategoryID != 0 {
|
||||
catVendorInfo.Seq = catVendorInfo.VendorCategorySeq
|
||||
catVendorInfo.Name = catVendorInfo.VendorCategoryName
|
||||
}
|
||||
}
|
||||
if multiStoresHandler, ok := partner.GetPurchasePlatformFromVendorID(catVendorInfo.VendorID).(partner.IMultipleStoresHandler); ok {
|
||||
if model.IsSyncStatusDelete(catVendorInfo.CatSyncStatus) { //删除
|
||||
if !dao.IsVendorThingIDEmpty(catVendorInfo.VendorCatID) &&
|
||||
model.IsSyncStatusNeedDelete(catVendorInfo.CatSyncStatus) {
|
||||
err = multiStoresHandler.DeleteCategory2(ctx, catVendorInfo.VendorOrgCode, catVendorInfo.VendorCatID)
|
||||
}
|
||||
} else if model.IsSyncStatusNew(catVendorInfo.CatSyncStatus) { // 新增
|
||||
err = multiStoresHandler.CreateCategory2(ctx, catVendorInfo)
|
||||
} else if model.IsSyncStatusUpdate(catVendorInfo.CatSyncStatus) { // 修改
|
||||
err = multiStoresHandler.UpdateCategory2(ctx, catVendorInfo)
|
||||
}
|
||||
} else {
|
||||
if catVendorInfo.VendorID != model.VendorIDDD {
|
||||
err = fmt.Errorf("平台:%d不合法", catVendorInfo.VendorID)
|
||||
}
|
||||
}
|
||||
if err = OnThingSync(ctx, dao.GetDB(), SkuCategoryVendor2ThingMap(catVendorInfo), err); err == nil {
|
||||
retVal = []int{1}
|
||||
}
|
||||
return retVal, err
|
||||
}, catList)
|
||||
tasksch.HandleTask(task, parentTask, len(catList) == 0 || len(catList) > 10).Run()
|
||||
if isAsync {
|
||||
hint = task.GetID()
|
||||
} else {
|
||||
resultList, err2 := task.GetResult(0)
|
||||
if err = err2; err == nil {
|
||||
hint = utils.Int2Str(len(resultList))
|
||||
}
|
||||
}
|
||||
}
|
||||
return hint, err
|
||||
}
|
||||
|
||||
func SyncCategories(ctx *jxcontext.Context, parentTask tasksch.ITask, vendorIDs []int, appOrgCodes []string, catIDs []int, isAsync bool) (hint string, err error) {
|
||||
db := dao.GetDB()
|
||||
catList, err := dao.GetSkuCategoryWithVendor(db, vendorIDs, appOrgCodes, -1, catIDs, true)
|
||||
if err == nil && len(catList) > 0 {
|
||||
//TODO 同一平台不同账号会有影响needSyncParentIDs,暂不处理
|
||||
var needSyncParentIDs []int
|
||||
for _, cat := range catList {
|
||||
if cat.Level == 2 && cat.ParentVendorCatID == "" && cat.IsExdSpec == model.NO {
|
||||
needSyncParentIDs = append(needSyncParentIDs, cat.ParentID)
|
||||
}
|
||||
}
|
||||
if len(needSyncParentIDs) > 0 {
|
||||
task := tasksch.NewSeqTask(fmt.Sprintf("同步分类1:%v", catIDs), ctx,
|
||||
func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
|
||||
switch step {
|
||||
case 0:
|
||||
catList2, err := dao.GetSkuCategoryWithVendor(db, vendorIDs, appOrgCodes, -1, needSyncParentIDs, true)
|
||||
if err == nil {
|
||||
_, err = syncCategories(ctx, db, task, catList2, false)
|
||||
}
|
||||
case 1:
|
||||
catList2, err := dao.GetSkuCategoryWithVendor(db, vendorIDs, appOrgCodes, -1, catIDs, true)
|
||||
if err == nil {
|
||||
_, err = syncCategories(ctx, db, task, catList2, false)
|
||||
}
|
||||
}
|
||||
return result, err
|
||||
}, 2)
|
||||
tasksch.HandleTask(task, parentTask, len(catIDs) == 0 || len(catIDs) > 10).Run()
|
||||
if isAsync {
|
||||
hint = task.GetID()
|
||||
} else {
|
||||
resultList, err2 := task.GetResult(0)
|
||||
if err = err2; err == nil {
|
||||
hint = utils.Int2Str(len(resultList))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
hint, err = syncCategories(ctx, db, parentTask, catList, false)
|
||||
}
|
||||
}
|
||||
return hint, err
|
||||
}
|
||||
|
||||
func SyncSkus(ctx *jxcontext.Context, parentTask tasksch.ITask, vendorIDs []int, appOrgCodes []string, nameIDs, skuIDs []int, isAsync bool) (hint string, err error) {
|
||||
db := dao.GetDB()
|
||||
skuList, err := dao.GetSkusWithVendor(db, vendorIDs, appOrgCodes, nameIDs, skuIDs, true)
|
||||
|
||||
cc := func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
skuVendorInfo := batchItemList[0].(*dao.StoreSkuSyncInfo)
|
||||
var failedList []*partner.StoreSkuInfoWithErr
|
||||
// if skuVendorInfo.VendorCatID == "" {
|
||||
// return nil, fmt.Errorf("商品:%d的商家分类没有同步", skuVendorInfo.SkuID)
|
||||
// }
|
||||
if skuVendorInfo.BindID == 0 {
|
||||
return nil, fmt.Errorf("商品:%d的数据异常", skuVendorInfo.SkuID)
|
||||
}
|
||||
if skuVendorInfo.ExdSkuID != "" {
|
||||
return nil, err
|
||||
}
|
||||
//todo 暂时注释
|
||||
if !model.IsSyncStatusNew(skuVendorInfo.SkuSyncStatus) && skuVendorInfo.VendorSkuID == "" {
|
||||
return nil, err
|
||||
}
|
||||
if skuVendorInfo.SkuVendorMapCatID != "" {
|
||||
skuVendorInfo.VendorVendorCatID = utils.Str2Int64(skuVendorInfo.SkuVendorMapCatID)
|
||||
}
|
||||
skuVendorInfo.SkuName = jxutils.ComposeSkuNameSync(skuVendorInfo.Prefix, skuVendorInfo.Name, skuVendorInfo.Comment, skuVendorInfo.Unit, skuVendorInfo.SpecQuality, skuVendorInfo.SpecUnit, 0, skuVendorInfo.ExPrefix, skuVendorInfo.ExPrefixBegin, skuVendorInfo.ExPrefixEnd, true)
|
||||
skuVendorInfo.SkuNameOrigin = jxutils.ComposeSkuNameOriginal(skuVendorInfo.Prefix, skuVendorInfo.Name, skuVendorInfo.Comment, skuVendorInfo.Unit, skuVendorInfo.SpecQuality, skuVendorInfo.SpecUnit, 0)
|
||||
if skuVendorInfo.ImgWatermark != "" {
|
||||
downLoad, _ := uploadImgStandard(skuVendorInfo.ImgWatermark)
|
||||
skuVendorInfo.ImgMix = jxutils.MixWatermarkImg(downLoad, skuVendorInfo.Img, skuVendorInfo.ExPrefixBegin, skuVendorInfo.ExPrefixEnd)
|
||||
}
|
||||
skuVendorInfo.MergedStatus = jxutils.MergeSkuStatus(skuVendorInfo.Status, skuVendorInfo.NameStatus)
|
||||
if multiStoresHandler, ok := partner.GetPurchasePlatformFromVendorID(skuVendorInfo.VendorID).(partner.IMultipleStoresHandler); ok {
|
||||
if model.IsSyncStatusDelete(skuVendorInfo.SkuSyncStatus) { //删除
|
||||
if !dao.IsVendorThingIDEmpty(skuVendorInfo.VendorSkuID) &&
|
||||
model.IsSyncStatusNeedDelete(skuVendorInfo.SkuSyncStatus) {
|
||||
err = multiStoresHandler.DeleteSku2(ctx, skuVendorInfo.VendorOrgCode, storeSkuSyncInfo2Bare(skuVendorInfo))
|
||||
if err != nil {
|
||||
failedList = putils.GetErrMsg2FailedSingleList(skuVendorInfo, err, 0, model.VendorChineseNames[skuVendorInfo.VendorID], "删除商品")
|
||||
}
|
||||
}
|
||||
} else if model.IsSyncStatusNew(skuVendorInfo.SkuSyncStatus) { // 新增
|
||||
err = multiStoresHandler.CreateSku2(ctx, skuVendorInfo)
|
||||
if err != nil {
|
||||
failedList = putils.GetErrMsg2FailedSingleList(skuVendorInfo, err, 0, model.VendorChineseNames[skuVendorInfo.VendorID], "新增商品")
|
||||
}
|
||||
} else if model.IsSyncStatusUpdate(skuVendorInfo.SkuSyncStatus) { // 修改
|
||||
err = multiStoresHandler.UpdateSku2(ctx, skuVendorInfo)
|
||||
if err != nil {
|
||||
failedList = putils.GetErrMsg2FailedSingleList(skuVendorInfo, err, 0, model.VendorChineseNames[skuVendorInfo.VendorID], "修改商品")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if skuVendorInfo.VendorID != model.VendorIDDD {
|
||||
err = fmt.Errorf("平台:%d不合法", skuVendorInfo.VendorID)
|
||||
}
|
||||
}
|
||||
if len(failedList) > 0 {
|
||||
task.AddFailedList(failedList)
|
||||
} else {
|
||||
dao.SetStoreSkuSyncStatus(dao.GetDB(), model.VendorIDJD, []int{skuVendorInfo.StoreID}, []int{skuVendorInfo.SkuID}, model.ThingTypeSyncSuccess)
|
||||
}
|
||||
if err = OnThingSync(ctx, dao.GetDB(), SkuVendor2ThingMap(skuVendorInfo), err); err == nil {
|
||||
retVal = []int{1}
|
||||
}
|
||||
return retVal, err
|
||||
}
|
||||
|
||||
if err == nil && len(skuList) > 0 {
|
||||
task := tasksch.NewParallelTask(
|
||||
fmt.Sprintf("同步商品:%v,%v", nameIDs, skuIDs),
|
||||
tasksch.NewParallelConfig().SetIsContinueWhenError(true), ctx, cc, skuList)
|
||||
if isAsync {
|
||||
buildSetFinishHook(task, ctx)
|
||||
}
|
||||
tasksch.HandleTask(task, parentTask, len(skuList) == 0 || len(skuList) > 10).Run()
|
||||
if isAsync {
|
||||
hint = task.GetID()
|
||||
} else {
|
||||
resultList, err2 := task.GetResult(0)
|
||||
if len(task.GetFailedList()) > 0 {
|
||||
err2 = buildErrMsg(task)
|
||||
err2 = makeSyncError(err2)
|
||||
}
|
||||
if err = err2; err == nil {
|
||||
hint = utils.Int2Str(len(resultList))
|
||||
}
|
||||
}
|
||||
}
|
||||
return hint, err
|
||||
}
|
||||
|
||||
func SyncReorderCategories(ctx *jxcontext.Context, parentCatID int, isAsync bool) (hint string, err error) {
|
||||
db := dao.GetDB()
|
||||
hint, err = CurVendorSync.LoopMultiStoresVendors(ctx, db, fmt.Sprintf("分类重排序:%d", parentCatID), isAsync, false,
|
||||
func(t *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
vendorInfo := batchItemList[0].(*MultiStoreVendorInfo)
|
||||
multiStoresHandler := CurVendorSync.GetMultiStoreHandler(vendorInfo.VendorID)
|
||||
vendorOrgCode, err := dao.GetVendorOrgCode(db, vendorInfo.VendorID, vendorInfo.OrgCode, "")
|
||||
if multiStoresHandler != nil {
|
||||
var vendorCatIDList []string
|
||||
var parentVendorCatID string
|
||||
//如果用平台分类就走else,用京西分类就还是原来的if
|
||||
if vendorOrgCode[0].IsJxCat == model.NO {
|
||||
catList, err2 := dao.GetSkuCategoryWithVendor(db, []int{vendorInfo.VendorID}, []string{vendorInfo.OrgCode}, parentCatID, nil, false)
|
||||
if err = err2; err == nil {
|
||||
for _, v := range catList {
|
||||
if v.VendorCatID != "" {
|
||||
vendorCatIDList = append(vendorCatIDList, v.VendorCatID)
|
||||
}
|
||||
}
|
||||
}
|
||||
parentVendorCatID = catList[0].ParentVendorCatID
|
||||
} else {
|
||||
vendorCatList, _ := dao.GetVendorCategoryMapExt(db, parentCatID, 0, vendorInfo.VendorID, vendorInfo.OrgCode, 0)
|
||||
for _, v := range vendorCatList {
|
||||
if v.VendorThingID != "" {
|
||||
vendorCatIDList = append(vendorCatIDList, v.VendorThingID)
|
||||
}
|
||||
}
|
||||
thingMaps, _ := dao.GetThingMapList(db, model.ThingTypeCategory, []int{vendorInfo.VendorID}, []int{parentCatID}, []string{vendorInfo.OrgCode})
|
||||
parentVendorCatID = thingMaps[0].VendorThingID
|
||||
}
|
||||
if len(vendorCatIDList) > 0 {
|
||||
if err = multiStoresHandler.ReorderCategories2(ctx, vendorInfo.OrgCode, parentVendorCatID, vendorCatIDList); err == nil {
|
||||
retVal = []int{len(vendorCatIDList)}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
err = fmt.Errorf("非法平台:%d", vendorInfo.VendorID)
|
||||
}
|
||||
return retVal, err
|
||||
})
|
||||
return hint, err
|
||||
}
|
||||
|
||||
func SyncReorderCategories2(ctx *jxcontext.Context, parentCatID, vendorID int, vendorOrgCode string) (err error) {
|
||||
db := dao.GetDB()
|
||||
multiStoresHandler := CurVendorSync.GetMultiStoreHandler(vendorID)
|
||||
if multiStoresHandler != nil {
|
||||
var vendorCatIDList []string
|
||||
var parentVendorCatID string
|
||||
vendorCatList, _ := dao.GetVendorCategoryMapExt(db, parentCatID, 0, vendorID, vendorOrgCode, 0)
|
||||
for _, v := range vendorCatList {
|
||||
if v.VendorThingID != "" {
|
||||
vendorCatIDList = append(vendorCatIDList, v.VendorThingID)
|
||||
}
|
||||
}
|
||||
thingMaps, _ := dao.GetThingMapList(db, model.ThingTypeCategory, []int{vendorID}, []int{parentCatID}, []string{vendorOrgCode})
|
||||
if len(thingMaps) > 0 {
|
||||
parentVendorCatID = thingMaps[0].VendorThingID
|
||||
}
|
||||
|
||||
if len(vendorCatIDList) > 0 {
|
||||
err = multiStoresHandler.ReorderCategories2(ctx, vendorOrgCode, parentVendorCatID, vendorCatIDList)
|
||||
}
|
||||
} else {
|
||||
err = fmt.Errorf("非法平台:%d", vendorID)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func getThingMap(db *dao.DaoDB, thingMap *model.ThingMap) (err error) {
|
||||
return dao.GetEntity(db, thingMap, "ThingID", "ThingType", "VendorID", "VendorOrgCode", model.FieldDeletedAt)
|
||||
}
|
||||
|
||||
func OnCreateThing(ctx *jxcontext.Context, db *dao.DaoDB, vendorInfoList []*model.VendorOrgCode, thingID int64, thingType, syncFlag int8, vendorFlag bool) (err error) {
|
||||
if thingType == model.ThingTypeSkuName {
|
||||
return nil
|
||||
}
|
||||
if len(vendorInfoList) == 0 {
|
||||
vendorInfoList, err = dao.GetVendorOrgCode(db, model.VendorIDJD, "", model.VendorOrgTypePlatform)
|
||||
}
|
||||
errList := errlist.New()
|
||||
for _, v := range vendorInfoList {
|
||||
thingMap := &model.ThingMap{
|
||||
ThingID: thingID,
|
||||
ThingType: thingType,
|
||||
VendorID: v.VendorID,
|
||||
VendorOrgCode: v.VendorOrgCode,
|
||||
}
|
||||
if thingType == model.ThingTypeCategory && !vendorFlag {
|
||||
if v.IsJxCat == model.YES {
|
||||
syncFlag = 0
|
||||
}
|
||||
}
|
||||
thingMap.SyncStatus = syncFlag
|
||||
dao.WrapAddIDCULDEntity(thingMap, ctx.GetUserName())
|
||||
if err2 := dao.CreateEntity(db, thingMap); err2 != nil {
|
||||
if dao.IsDuplicateError(err2) {
|
||||
errList.AddErr(onUpdateThing(ctx, db, vendorInfoList, thingID, thingType, syncFlag))
|
||||
} else {
|
||||
errList.AddErr(err2)
|
||||
}
|
||||
}
|
||||
updateThingMapEntity(db, thingMap)
|
||||
}
|
||||
err = errList.GetErrListAsOne()
|
||||
return err
|
||||
}
|
||||
|
||||
func OnCreateThing2Tiktok(ctx *jxcontext.Context, db *dao.DaoDB, appOrgCode string, vendorThingList []*tiktok_store.TiktokIdAndLocalSkuId, thingType, syncFlag int8, vendorFlag bool) (err error) {
|
||||
if thingType == model.ThingTypeSkuName {
|
||||
return nil
|
||||
}
|
||||
errList := errlist.New()
|
||||
for _, v := range vendorThingList {
|
||||
thingMap := &model.ThingMap{
|
||||
ThingID: v.LocalSkuId,
|
||||
ThingType: thingType,
|
||||
VendorID: model.VendorIDDD,
|
||||
VendorOrgCode: appOrgCode,
|
||||
VendorThingID: v.MainId,
|
||||
Remark: v.SkuAttrId,
|
||||
}
|
||||
if thingType == model.ThingTypeCategory && !vendorFlag {
|
||||
syncFlag = 0
|
||||
}
|
||||
thingMap.SyncStatus = syncFlag
|
||||
dao.WrapAddIDCULDEntity(thingMap, ctx.GetUserName())
|
||||
if err2 := dao.CreateEntity(db, thingMap); err2 != nil {
|
||||
if err2 := getThingMap(db, thingMap); err2 == nil {
|
||||
thingMap.SyncStatus = 2
|
||||
thingMap.LastOperator = ctx.GetUserName()
|
||||
_, err2 = dao.UpdateEntity(db, thingMap)
|
||||
errList.AddErr(err2)
|
||||
}
|
||||
}
|
||||
}
|
||||
err = errList.GetErrListAsOne()
|
||||
return err
|
||||
}
|
||||
|
||||
func onUpdateThing(ctx *jxcontext.Context, db *dao.DaoDB, vendorInfoList []*model.VendorOrgCode, thingID int64, thingType int8, syncStatus int8) (err error) {
|
||||
if thingType == model.ThingTypeSkuName {
|
||||
return nil
|
||||
}
|
||||
if len(vendorInfoList) == 0 {
|
||||
vendorInfoList, err = dao.GetVendorOrgCode(db, model.VendorIDJD, "", model.VendorOrgTypePlatform)
|
||||
}
|
||||
errList := errlist.New()
|
||||
for _, v := range vendorInfoList {
|
||||
thingMap := &model.ThingMap{
|
||||
ThingID: thingID,
|
||||
ThingType: thingType,
|
||||
VendorID: v.VendorID,
|
||||
VendorOrgCode: v.VendorOrgCode,
|
||||
}
|
||||
thingMap.DeletedAt = utils.DefaultTimeValue
|
||||
if err2 := getThingMap(db, thingMap); err2 == nil {
|
||||
thingMap.SyncStatus |= syncStatus
|
||||
thingMap.LastOperator = ctx.GetUserName()
|
||||
_, err2 = dao.UpdateEntity(db, thingMap)
|
||||
errList.AddErr(err2)
|
||||
|
||||
updateThingMapEntity(db, thingMap)
|
||||
} else {
|
||||
if dao.IsNoRowsError(err2) {
|
||||
err2 = nil
|
||||
} else {
|
||||
errList.AddErr(err2)
|
||||
}
|
||||
}
|
||||
}
|
||||
err = errList.GetErrListAsOne()
|
||||
return err
|
||||
}
|
||||
|
||||
func DeleteThingByData(ctx *jxcontext.Context, db *dao.DaoDB, appOrgCode string, startTime time.Time, endTime time.Time) error {
|
||||
sql := ` DELETE FROM thing_map WHERE vendor_org_code = ? AND created_at >= ? AND created_at < ? `
|
||||
_, err := dao.ExecuteSQL(db, sql, []interface{}{appOrgCode, startTime, endTime})
|
||||
return err
|
||||
}
|
||||
|
||||
func OnUpdateThing(ctx *jxcontext.Context, db *dao.DaoDB, vendorInfoList []*model.VendorOrgCode, thingID int64, thingType int8) (err error) {
|
||||
return onUpdateThing(ctx, db, vendorInfoList, thingID, thingType, model.SyncFlagModifiedMask)
|
||||
}
|
||||
|
||||
func OnDeleteThing(ctx *jxcontext.Context, db *dao.DaoDB, vendorInfoList []*MultiStoreVendorInfo, thingID int64, thingType int8) (err error) {
|
||||
if thingType == model.ThingTypeSkuName {
|
||||
return nil
|
||||
}
|
||||
if len(vendorInfoList) == 0 {
|
||||
vendorInfoList = getMultiStoreVendorInfoList()
|
||||
}
|
||||
errList := errlist.New()
|
||||
for _, v := range vendorInfoList {
|
||||
thingMap := &model.ThingMap{
|
||||
ThingID: thingID,
|
||||
ThingType: thingType,
|
||||
VendorID: v.VendorID,
|
||||
VendorOrgCode: v.OrgCode,
|
||||
}
|
||||
thingMap.DeletedAt = utils.DefaultTimeValue
|
||||
if err2 := getThingMap(db, thingMap); err2 == nil {
|
||||
if model.IsSyncStatusNew(thingMap.SyncStatus) {
|
||||
thingMap.SyncStatus = 0
|
||||
thingMap.DeletedAt = time.Now()
|
||||
} else {
|
||||
thingMap.SyncStatus |= model.SyncFlagDeletedMask
|
||||
}
|
||||
thingMap.LastOperator = ctx.GetUserName()
|
||||
_, err2 = dao.UpdateEntity(db, thingMap)
|
||||
errList.AddErr(err2)
|
||||
|
||||
updateThingMapEntity(db, thingMap)
|
||||
} else if !dao.IsNoRowsError(err2) {
|
||||
errList.AddErr(err2)
|
||||
}
|
||||
}
|
||||
err = errList.GetErrListAsOne()
|
||||
return err
|
||||
}
|
||||
|
||||
func SkuCategoryVendor2ThingMap(cat *dao.SkuStoreCatInfo) (thingMap *model.ThingMap) {
|
||||
thingMap = &model.ThingMap{
|
||||
ThingID: int64(cat.ID),
|
||||
ThingType: model.ThingTypeCategory,
|
||||
VendorID: cat.VendorID,
|
||||
VendorOrgCode: cat.VendorOrgCode,
|
||||
|
||||
SyncStatus: cat.CatSyncStatus,
|
||||
VendorThingID: cat.VendorCatID,
|
||||
}
|
||||
thingMap.ID = cat.MapID // 一定要赋值
|
||||
return thingMap
|
||||
}
|
||||
|
||||
func SkuVendor2ThingMap(sku *dao.StoreSkuSyncInfo) (thingMap *model.ThingMap) {
|
||||
thingMap = &model.ThingMap{
|
||||
ThingID: int64(sku.SkuID),
|
||||
ThingType: model.ThingTypeSku,
|
||||
VendorID: sku.VendorID,
|
||||
VendorOrgCode: sku.VendorOrgCode,
|
||||
|
||||
SyncStatus: sku.SkuSyncStatus,
|
||||
VendorThingID: sku.VendorSkuID,
|
||||
}
|
||||
thingMap.DeletedAt = utils.DefaultTimeValue
|
||||
thingMap.ID = sku.BindID // 一定要赋值
|
||||
return thingMap
|
||||
}
|
||||
|
||||
func OnThingSync(ctx *jxcontext.Context, db *dao.DaoDB, thingMap *model.ThingMap, syncErr error) (err error) {
|
||||
if syncErr != nil {
|
||||
err = syncErr
|
||||
thingMap.Remark = utils.LimitUTF8StringLen(err.Error(), 255)
|
||||
dao.UpdateEntity(db, thingMap, "Remark")
|
||||
|
||||
if thingMap.VendorOrgCode == globals.JdcsOrgCode {
|
||||
if strings.Contains(err.Error(), "店内分类信息不存在") {
|
||||
err = nil
|
||||
}
|
||||
}
|
||||
} else {
|
||||
updateFields := []string{
|
||||
model.FieldSyncStatus,
|
||||
model.FieldUpdatedAt,
|
||||
model.FieldLastOperator,
|
||||
"Remark",
|
||||
}
|
||||
if model.IsSyncStatusDelete(thingMap.SyncStatus) { //删除
|
||||
thingMap.DeletedAt = time.Now()
|
||||
thingMap.VendorThingID = ""
|
||||
updateFields = append(updateFields, "VendorThingID", model.FieldDeletedAt)
|
||||
} else if model.IsSyncStatusNew(thingMap.SyncStatus) { // 新增
|
||||
updateFields = append(updateFields, "VendorThingID")
|
||||
}
|
||||
thingMap.SyncStatus = 0
|
||||
thingMap.LastOperator = ctx.GetUserName()
|
||||
thingMap.UpdatedAt = time.Now()
|
||||
thingMap.Remark = ""
|
||||
_, err = dao.UpdateEntity(db, thingMap, updateFields...)
|
||||
|
||||
updateThingMapEntity(db, thingMap)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func updateThingMapEntity(db *dao.DaoDB, thingMap *model.ThingMap) {
|
||||
// if thingMap.VendorOrgCode == globals.JdOrgCode {
|
||||
// if thingMap.ThingType == model.ThingTypeCategory {
|
||||
// cat := &model.SkuCategory{
|
||||
// JdID: utils.Str2Int64WithDefault(thingMap.VendorThingID, 0),
|
||||
// JdSyncStatus: thingMap.SyncStatus,
|
||||
// }
|
||||
// cat.ID = int(thingMap.ThingID)
|
||||
// dao.UpdateEntity(db, cat, "JdID", "JdSyncStatus")
|
||||
// } else if thingMap.ThingType == model.ThingTypeSku {
|
||||
// sku := &model.Sku{
|
||||
// JdID: utils.Str2Int64WithDefault(thingMap.VendorThingID, 0),
|
||||
// JdSyncStatus: thingMap.SyncStatus,
|
||||
// }
|
||||
// sku.ID = int(thingMap.ThingID)
|
||||
// dao.UpdateEntity(db, sku, "JdID", "JdSyncStatus")
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
func amendAndPruneVendorStuff(ctx *jxcontext.Context, parentTask tasksch.ITask, storeID, vendorID int, vendorOrgCode string, isAsync, isContinueWhenError bool, opType int, isForceUpdate bool) (hint string, err error) {
|
||||
handler, _ := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.IMultipleStoresHandler)
|
||||
if handler == nil {
|
||||
return "", fmt.Errorf("平台:%s不支持此操作", model.VendorChineseNames[vendorID])
|
||||
}
|
||||
db := dao.GetDB()
|
||||
vendorOrgCodes, _ := dao.GetVendorOrgCode(db, vendorID, vendorOrgCode, model.VendorOrgTypePlatform)
|
||||
var sku2Delete []*partner.StoreSkuInfo
|
||||
var cat2Delete []*partner.BareCategoryInfo
|
||||
task := tasksch.NewParallelTask(fmt.Sprintf("平台:%s,账号:%s上的商品与商家分类", model.VendorChineseNames[vendorID], vendorOrgCode),
|
||||
tasksch.NewParallelConfig().SetParallelCount(1).SetIsContinueWhenError(isContinueWhenError), ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
step := batchItemList[0].(int)
|
||||
switch step {
|
||||
case 0:
|
||||
localSkuList, err := dao.GetSkusWithVendor(db, []int{vendorID}, []string{vendorOrgCode}, nil, nil, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
localSkuMap := make(map[string]*dao.StoreSkuSyncInfo)
|
||||
for _, v := range localSkuList {
|
||||
if v.VendorSkuID != "" {
|
||||
localSkuMap[v.VendorSkuID] = v
|
||||
}
|
||||
}
|
||||
|
||||
remoteSkuList, err2 := handler.GetSkus(ctx, vendorOrgCode, 0, "")
|
||||
if err = err2; err == nil {
|
||||
remoteSkuMap := make(map[string]int)
|
||||
for _, v := range remoteSkuList {
|
||||
if vendorSkuID := v.SkuList[0].VendorSkuID; vendorSkuID != "" {
|
||||
if localSkuMap[vendorSkuID] == nil {
|
||||
sku2Delete = append(sku2Delete, &partner.StoreSkuInfo{
|
||||
SkuID: v.SkuList[0].SkuID,
|
||||
VendorSkuID: vendorSkuID,
|
||||
})
|
||||
} else {
|
||||
remoteSkuMap[vendorSkuID] = 1
|
||||
}
|
||||
} else if v.VendorNameID != "" {
|
||||
sku2Delete = append(sku2Delete, &partner.StoreSkuInfo{
|
||||
SkuID: v.NameID,
|
||||
VendorSkuID: v.VendorNameID,
|
||||
})
|
||||
}
|
||||
}
|
||||
StoreSkuMap := make(map[int]*dao.StoreSkuSyncInfo)
|
||||
if storeID != 0 {
|
||||
skuList2, _ := dao.GetStoreSkuListWithVendor(db, storeID, vendorID, vendorOrgCode)
|
||||
for _, v := range skuList2 {
|
||||
if _, ok := StoreSkuMap[v.ID]; !ok {
|
||||
StoreSkuMap[v.ID] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
getSyncFlag := func(skuID int) int8 {
|
||||
if StoreSkuMap[skuID] != nil {
|
||||
return model.SyncFlagNewMask
|
||||
}
|
||||
return 0
|
||||
}
|
||||
if opType == AmendPruneOnlyAmend || opType == AmendPruneAll {
|
||||
for _, v := range localSkuList {
|
||||
if v.ExdSkuID == "" {
|
||||
if v.BindID != 0 {
|
||||
if !model.IsSyncStatusDelete(v.SkuSyncStatus) {
|
||||
if remoteSkuMap[v.VendorSkuID] == 0 {
|
||||
if !model.IsSyncStatusNew(v.SkuSyncStatus) {
|
||||
err = OnCreateThing(ctx, db, vendorOrgCodes, int64(v.SkuID), model.ThingTypeSku, getSyncFlag(v.SkuID), false)
|
||||
}
|
||||
} else if isForceUpdate {
|
||||
err = OnUpdateThing(ctx, db, vendorOrgCodes, int64(v.SkuID), model.ThingTypeSku)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//表示根据某门店的门店商品同步京东商品库中,这个门店关注并可售了这个商品,插到thingmap里同步标志是待创建(SyncFlagNewMask)才会创建
|
||||
//若该门店没关注可售,那插到thingmap里的话就该同步标志为0,就不会创建
|
||||
//getSyncFlag
|
||||
err = OnCreateThing(ctx, db, vendorOrgCodes, int64(v.SkuID), model.ThingTypeSku, getSyncFlag(v.SkuID), false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
case 1:
|
||||
// if (opType == AmendPruneOnlyPrune || opType == AmendPruneAll) && len(sku2Delete) > 0 {
|
||||
// _, err = putils.FreeBatchStoreSkuInfo("删除商品", func(task tasksch.ITask, batchedStoreSkuList []*partner.StoreSkuInfo) (result interface{}, successCount int, err error) {
|
||||
// if err = handler.DeleteSku2(ctx, vendorOrgCode, batchedStoreSkuList[0]); err == nil {
|
||||
// successCount = 1
|
||||
// }
|
||||
// return nil, successCount, err
|
||||
// }, ctx, task, sku2Delete, 1, isContinueWhenError)
|
||||
// }
|
||||
sku2Delete = nil
|
||||
case 2:
|
||||
localCatList, err := dao.GetSkuCategoryWithVendor(db, []int{vendorID}, []string{vendorOrgCode}, -1, nil, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
localCatMap := make(map[string]*dao.SkuStoreCatInfo)
|
||||
for _, v := range localCatList {
|
||||
localCatMap[v.VendorCatID] = v
|
||||
localCatMap[v.Name] = v
|
||||
localCatMap[utils.Int2Str(v.ID)] = v
|
||||
}
|
||||
|
||||
vendorCatMap := make(map[int]*model.VendorCategoryMap)
|
||||
if vendorOrgCodes[0].IsJxCat == model.YES {
|
||||
vendorCats, _ := dao.GetVendorCategoryMap(db, -1, 0, vendorID, vendorOrgCode, 0)
|
||||
for _, v := range vendorCats {
|
||||
if _, ok := vendorCatMap[v.CategoryID]; !ok {
|
||||
vendorCatMap[v.CategoryID] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
getSyncFlagCat := func(categoryID int) int8 {
|
||||
if vendorCatMap[categoryID] != nil || vendorOrgCodes[0].IsJxCat == model.NO {
|
||||
return model.SyncFlagNewMask
|
||||
}
|
||||
return 0
|
||||
}
|
||||
remoteCatList, err2 := handler.GetAllCategories(ctx, vendorOrgCode)
|
||||
if err = err2; err == nil {
|
||||
remoteCatMap := make(map[string]int)
|
||||
cat2Delete = checkRemoteCatExist(remoteCatMap, localCatMap, remoteCatList)
|
||||
for _, v := range localCatList {
|
||||
if v.IsExdSpec == model.NO {
|
||||
if v.MapID != 0 {
|
||||
if !model.IsSyncStatusDelete(v.CatSyncStatus) {
|
||||
if remoteCatMap[v.VendorCatID] == 0 {
|
||||
if !model.IsSyncStatusNew(v.CatSyncStatus) {
|
||||
err = OnCreateThing(ctx, db, vendorOrgCodes, int64(v.ID), model.ThingTypeCategory, getSyncFlagCat(v.ID), true)
|
||||
}
|
||||
} else if isForceUpdate && !model.IsSyncStatusUpdate(v.CatSyncStatus) {
|
||||
OnUpdateThing(ctx, db, vendorOrgCodes, int64(v.ID), model.ThingTypeCategory)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
OnCreateThing(ctx, db, vendorOrgCodes, int64(v.ID), model.ThingTypeCategory, getSyncFlagCat(v.ID), true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
case 3:
|
||||
if (opType == AmendPruneOnlyPrune || opType == AmendPruneAll) && len(cat2Delete) > 0 {
|
||||
for i := 0; i < 2; i++ {
|
||||
level := 2 - i
|
||||
var levelCat2Delete []*partner.BareCategoryInfo
|
||||
for _, v := range cat2Delete {
|
||||
if v.Level == level {
|
||||
levelCat2Delete = append(levelCat2Delete, v)
|
||||
}
|
||||
}
|
||||
if len(levelCat2Delete) > 0 {
|
||||
// task4Delete := tasksch.NewParallelTask(fmt.Sprintf("删除商家分类,level:%d", level), tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError), ctx,
|
||||
// func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
// cat := batchItemList[0].(*partner.BareCategoryInfo)
|
||||
// err = handler.DeleteCategory2(ctx, vendorOrgCode, cat.VendorCatID)
|
||||
// return nil, err
|
||||
// }, levelCat2Delete)
|
||||
// tasksch.HandleTask(task4Delete, task, true).Run()
|
||||
// _, err = task4Delete.GetResult(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
cat2Delete = nil
|
||||
}
|
||||
return nil, err
|
||||
}, []int{0, 1, 2, 3})
|
||||
tasksch.HandleTask(task, parentTask, true).Run()
|
||||
if !isAsync {
|
||||
_, err = task.GetResult(0)
|
||||
hint = "1"
|
||||
} else {
|
||||
hint = task.ID
|
||||
}
|
||||
return hint, err
|
||||
}
|
||||
|
||||
func FullSyncVendorStuff(ctx *jxcontext.Context, parentTask tasksch.ITask, storeID, vendorID int, vendorOrgCode string, isAsync, isContinueWhenError bool) (hint string, err error) {
|
||||
multiStoreHandler, _ := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.IMultipleStoresHandler)
|
||||
if multiStoreHandler == nil {
|
||||
return "", fmt.Errorf("vendorID:%d不是多门店平台", vendorID)
|
||||
}
|
||||
worker := func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
step := batchItemList[0].(int)
|
||||
switch step {
|
||||
case 0:
|
||||
_, err = amendAndPruneVendorStuff(ctx, task, storeID, vendorID, vendorOrgCode, false, isContinueWhenError, AmendPruneAll, false)
|
||||
case 1:
|
||||
//_, err = SyncCategories(ctx, task, []int{vendorID}, []string{vendorOrgCode}, nil, false)
|
||||
case 2:
|
||||
_, err = SyncSkus(ctx, task, []int{vendorID}, []string{vendorOrgCode}, nil, nil, false)
|
||||
}
|
||||
return retVal, err
|
||||
}
|
||||
task := tasksch.NewParallelTask("FullSyncStoreSkuNew", tasksch.NewParallelConfig().SetParallelCount(1).SetIsContinueWhenError(false), ctx, worker, []int{0, 1, 2})
|
||||
tasksch.HandleTask(task, parentTask, true).Run()
|
||||
if !isAsync {
|
||||
_, err = task.GetResult(0)
|
||||
} else {
|
||||
hint = task.GetID()
|
||||
}
|
||||
return hint, err
|
||||
}
|
||||
@@ -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,328 +0,0 @@
|
||||
package cms
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/business/partner/putils"
|
||||
"git.rosy.net.cn/jx-callback/globals/api/apimanager"
|
||||
"github.com/360EntSecGroup-Skylar/excelize"
|
||||
)
|
||||
|
||||
func storeOrSkuMap2List(intStrMap map[int]string) (ids []int) {
|
||||
for k, v := range intStrMap {
|
||||
if v != "" {
|
||||
ids = append(ids, k)
|
||||
}
|
||||
}
|
||||
return ids
|
||||
}
|
||||
|
||||
func getStoreSkus(db *dao.DaoDB, storeID int, skuIDs []int) (skus []*dao.StoreSkuSyncInfo, err error) {
|
||||
sql := `
|
||||
SELECT
|
||||
t1.id bind_id, t1.sku_id, t1.price, t1.unit_price, t1.status store_sku_status,
|
||||
t1.jd_sync_status sku_sync_status, t1.jd_price vendor_price, t1.jd_lock_time lock_time,
|
||||
t1.store_id, t1.deleted_at bind_deleted_at,t1.status_sale_begin,t1.status_sale_end,
|
||||
t2.*,
|
||||
t3.id name_id, t3.prefix, t3.name, t3.unit, t3.upc, t3.status name_status, t3.ex_prefix, t3.ex_prefix_begin, t3.ex_prefix_end
|
||||
FROM store_sku_bind t1
|
||||
LEFT JOIN sku t2 ON t1.sku_id = t2.id AND t2.deleted_at = ?/* AND t2.status = ?*/
|
||||
LEFT JOIN sku_name t3 ON t2.name_id = t3.id AND t3.deleted_at = ?/* AND t3.status = ?*/
|
||||
WHERE 1 = 1
|
||||
AND t1.store_id = ?
|
||||
AND t1.deleted_at = ?
|
||||
AND t1.sku_id IN ( ` + dao.GenQuestionMarks(len(skuIDs)) + `)
|
||||
ORDER BY t1.price`
|
||||
sqlParams := []interface{}{
|
||||
utils.DefaultTimeValue,
|
||||
utils.DefaultTimeValue,
|
||||
storeID,
|
||||
utils.DefaultTimeValue,
|
||||
skuIDs,
|
||||
}
|
||||
if err = dao.GetRows(db, &skus, sql, sqlParams...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return skus, err
|
||||
}
|
||||
|
||||
func SyncStoreSku4FakeJD(ctx *jxcontext.Context, parentTask tasksch.ITask, storeID int, vendorStoreID string, inSkuMap map[int]string, isContinueWhenError bool) (err error) {
|
||||
vendorID := model.VendorIDJD
|
||||
db := dao.GetDB()
|
||||
storeDetail, err := dao.GetStoreDetail(db, storeID, vendorID, "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
storeDetail.VendorOrgCode = apimanager.FakeJdOrgCode
|
||||
skuIDs := storeOrSkuMap2List(inSkuMap)
|
||||
skus, err := getStoreSkus(db, storeID, skuIDs)
|
||||
if err != nil || len(skus) == 0 {
|
||||
return err
|
||||
}
|
||||
formalizeStoreSkuList(skus)
|
||||
storeSkuHandler := partner.GetPurchasePlatformFromVendorID(vendorID).(partner.IPurchasePlatformStoreSkuHandler)
|
||||
|
||||
var (
|
||||
stockList, onlineList, offlineList, priceList []*partner.StoreSkuInfo
|
||||
)
|
||||
skuMap := make(map[*partner.StoreSkuInfo]*dao.StoreSkuSyncInfo)
|
||||
now := jxutils.OperationTime2HourMinuteFormat(time.Now())
|
||||
var failedList []*partner.StoreSkuInfoWithErr
|
||||
for _, sku := range skus {
|
||||
sku.SkuSyncStatus = model.SyncFlagSaleMask | model.SyncFlagPriceMask | model.SyncFlagStockMask
|
||||
sku.VendorSkuID = inSkuMap[sku.SkuID]
|
||||
sku.SkuID = int(utils.Str2Int64(sku.VendorSkuID)) // skuID与vendorID一样
|
||||
sku.VendorOrgCode = apimanager.FakeJdOrgCode
|
||||
|
||||
sku.VendorPrice = 0
|
||||
sku.MergedStatus = MergeSkuSaleStatusWithStoreOpTime(sku, storeDetail, now)
|
||||
var bareSku *partner.StoreSkuInfo
|
||||
if isStoreSkuSyncNeedDelete(sku) {
|
||||
if !dao.IsVendorThingIDEmpty(sku.VendorSkuID) {
|
||||
bareSku = storeSkuSyncInfo2Bare(sku)
|
||||
stockList = append(stockList, bareSku)
|
||||
} else {
|
||||
// updateItems = append(updateItems, sku2Update(vendorID, sku, model.SyncFlagDeletedMask))
|
||||
}
|
||||
} else if model.IsSyncStatusNew(sku.SkuSyncStatus) {
|
||||
calVendorPrice4StoreSku(sku, storeDetail.PricePercentagePackObj, int(storeDetail.PricePercentage))
|
||||
if dao.IsVendorThingIDEmpty(sku.VendorSkuID) {
|
||||
// todo 多平台商品库没有正常创建,直接跳过
|
||||
} else {
|
||||
sku.SkuSyncStatus |= model.SyncFlagSaleMask | model.SyncFlagPriceMask
|
||||
bareSku = storeSkuSyncInfo2Bare(sku)
|
||||
stockList = append(stockList, bareSku)
|
||||
priceList = append(priceList, bareSku)
|
||||
if sku.MergedStatus == model.SkuStatusNormal {
|
||||
onlineList = append(onlineList, bareSku)
|
||||
} else {
|
||||
offlineList = append(offlineList, bareSku)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if dao.IsVendorThingIDEmpty(sku.VendorSkuID) {
|
||||
// err = fmt.Errorf("门店:%d,修改没有创建的商品:%d", storeID, sku.SkuID)
|
||||
err = utils.NewErrorCode(fmt.Sprintf("门店:%d,修改没有创建的商品:%d", storeID, sku.SkuID), "-1", 0)
|
||||
failedList = putils.GetErrMsg2FailedSingleList(nil, err, storeID, model.VendorChineseNames[vendorID], "异常同步错误")
|
||||
if parentTask == nil {
|
||||
return err
|
||||
}
|
||||
parentTask.AddBatchErr(err)
|
||||
parentTask.AddFailedList(failedList)
|
||||
} else {
|
||||
isAdded2Update := false
|
||||
if model.IsSyncStatusPrice(sku.SkuSyncStatus) {
|
||||
bareSku = storeSkuSyncInfo2Bare(calVendorPrice4StoreSku(sku, storeDetail.PricePercentagePackObj, int(storeDetail.PricePercentage)))
|
||||
priceList = append(priceList, bareSku)
|
||||
}
|
||||
if !isAdded2Update {
|
||||
if model.IsSyncStatusSale(sku.SkuSyncStatus) {
|
||||
if bareSku == nil {
|
||||
bareSku = storeSkuSyncInfo2Bare(sku)
|
||||
}
|
||||
if sku.MergedStatus == model.SkuStatusNormal {
|
||||
onlineList = append(onlineList, bareSku)
|
||||
stockList = append(stockList, bareSku)
|
||||
} else {
|
||||
offlineList = append(offlineList, bareSku)
|
||||
// 因为京东平台以是否有库存表示是否关注,所以不论是否可售,都要设置库存
|
||||
stockList = append(stockList, bareSku)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if bareSku != nil {
|
||||
skuMap[bareSku] = sku
|
||||
}
|
||||
}
|
||||
bareSku2Sync := func(bareSkuList []*partner.StoreSkuInfo) (skuList []*dao.StoreSkuSyncInfo) {
|
||||
if len(bareSkuList) > 0 {
|
||||
skuList = make([]*dao.StoreSkuSyncInfo, len(bareSkuList))
|
||||
for k, v := range bareSkuList {
|
||||
skuList[k] = skuMap[v]
|
||||
}
|
||||
}
|
||||
return skuList
|
||||
}
|
||||
isContinueWhenError2 := true
|
||||
realStoreID := int(utils.Str2Int64(vendorStoreID))
|
||||
task := tasksch.NewParallelTask("SyncStoreSku4FakeJD", tasksch.NewParallelConfig().SetParallelCount(1).SetIsContinueWhenError(isContinueWhenError2), ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
step := batchItemList[0].(int)
|
||||
switch step {
|
||||
case 0:
|
||||
for k, list := range [][]*partner.StoreSkuInfo{stockList /*, onlineList*/} {
|
||||
if len(list) > 0 {
|
||||
_, err = putils.FreeBatchStoreSkuInfo("更新门店商品库存", func(task tasksch.ITask, batchedStoreSkuList []*partner.StoreSkuInfo) (result interface{}, successCount int, err error) {
|
||||
var failedList []*partner.StoreSkuInfoWithErr
|
||||
failedList, err = storeSkuHandler.UpdateStoreSkusStock(ctx, storeDetail.VendorOrgCode, realStoreID, vendorStoreID, batchedStoreSkuList)
|
||||
if len(failedList) > 0 {
|
||||
task.AddFailedList(failedList)
|
||||
}
|
||||
successList := putils.UnselectStoreSkuListByVendorSkuIDs(batchedStoreSkuList, GetVendorSkuIDList(failedList))
|
||||
if k == 0 && len(successList) > 0 {
|
||||
updateStoreSku(dao.GetDB(), vendorID, bareSku2Sync(successList), model.SyncFlagStockMask)
|
||||
}
|
||||
return nil, len(successList), err
|
||||
}, ctx, task, list, storeSkuHandler.GetStoreSkusBatchSize(partner.FuncUpdateStoreSkusStock), isContinueWhenError2)
|
||||
}
|
||||
}
|
||||
case 1, 2:
|
||||
statusList := onlineList
|
||||
status := model.SkuStatusNormal
|
||||
name := "可售门店商品"
|
||||
if step == 2 {
|
||||
statusList = offlineList
|
||||
status = model.SkuStatusDontSale
|
||||
name = "不可售门店商品"
|
||||
}
|
||||
if len(statusList) > 0 {
|
||||
_, err = putils.FreeBatchStoreSkuInfo(name, func(task tasksch.ITask, batchedStoreSkuList []*partner.StoreSkuInfo) (result interface{}, successCount int, err error) {
|
||||
var failedList []*partner.StoreSkuInfoWithErr
|
||||
failedList, err = storeSkuHandler.UpdateStoreSkusStatus(ctx, storeDetail.VendorOrgCode, realStoreID, vendorStoreID, batchedStoreSkuList, status)
|
||||
if len(failedList) > 0 {
|
||||
task.AddFailedList(failedList)
|
||||
}
|
||||
successList := putils.UnselectStoreSkuListByVendorSkuIDs(batchedStoreSkuList, GetVendorSkuIDList(failedList))
|
||||
if len(successList) > 0 {
|
||||
updateStoreSku(dao.GetDB(), vendorID, bareSku2Sync(successList), model.SyncFlagSaleMask)
|
||||
}
|
||||
return nil, len(successList), err
|
||||
}, ctx, task, statusList, storeSkuHandler.GetStoreSkusBatchSize(partner.FuncUpdateStoreSkusStatus), isContinueWhenError2)
|
||||
}
|
||||
case 3:
|
||||
if len(priceList) > 0 {
|
||||
_, err = putils.FreeBatchStoreSkuInfo("更新门店商品价格2", func(task tasksch.ITask, batchedStoreSkuList []*partner.StoreSkuInfo) (result interface{}, successCount int, err error) {
|
||||
var failedList []*partner.StoreSkuInfoWithErr
|
||||
failedList, err = storeSkuHandler.UpdateStoreSkusPrice(ctx, storeDetail.VendorOrgCode, realStoreID, vendorStoreID, batchedStoreSkuList)
|
||||
if len(failedList) > 0 {
|
||||
task.AddFailedList(failedList)
|
||||
}
|
||||
successList := putils.UnselectStoreSkuListByVendorSkuIDs(batchedStoreSkuList, GetVendorSkuIDList(failedList))
|
||||
if len(successList) > 0 {
|
||||
updateStoreSku(dao.GetDB(), vendorID, bareSku2Sync(successList), model.SyncFlagPriceMask)
|
||||
}
|
||||
return nil, len(successList), err
|
||||
}, ctx, task, priceList, storeSkuHandler.GetStoreSkusBatchSize(partner.FuncUpdateStoreSkusPrice), isContinueWhenError2)
|
||||
}
|
||||
}
|
||||
return retVal, err
|
||||
}, []int{0, 1, 2, 3})
|
||||
tasksch.HandleTask(task, parentTask, true).Run()
|
||||
_, err = task.GetResult(0)
|
||||
return err
|
||||
}
|
||||
|
||||
func SyncFakeJdStoreSku(ctx *jxcontext.Context, parentTask tasksch.ITask, storeMap, skuMap map[int]string, isAsync, isContinueWhenError bool) (hint string, err error) {
|
||||
storeIDs := storeOrSkuMap2List(storeMap)
|
||||
task := tasksch.NewParallelTask("同步假京东", nil, ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
storeID := batchItemList[0].(int)
|
||||
err = SyncStoreSku4FakeJD(ctx, task, storeID, storeMap[storeID], skuMap, isContinueWhenError)
|
||||
return retVal, err
|
||||
}, storeIDs)
|
||||
tasksch.HandleTask(task, parentTask, true).Run()
|
||||
if isAsync {
|
||||
hint = task.GetID()
|
||||
} else {
|
||||
_, err = task.GetResult(0)
|
||||
hint = utils.Int2Str(len(storeIDs))
|
||||
}
|
||||
return hint, err
|
||||
}
|
||||
|
||||
func excel2FakeJdThingMap(ctx *jxcontext.Context, reader io.Reader) (thingMapList []*model.FakeJdThingMap, err error) {
|
||||
xlsx, err := excelize.OpenReader(reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for sheetIndex := 0; sheetIndex < xlsx.SheetCount; sheetIndex++ {
|
||||
rows, err2 := xlsx.GetRows(xlsx.GetSheetName(sheetIndex + 1))
|
||||
if err2 != nil {
|
||||
return nil, err2
|
||||
}
|
||||
for rowNum, row := range rows {
|
||||
thingMap := &model.FakeJdThingMap{
|
||||
JxID: int(utils.Str2Int64WithDefault(row[0], 0)),
|
||||
JdID: utils.Str2Int64WithDefault(row[1], 0),
|
||||
}
|
||||
if thingMap.JxID == 0 || thingMap.JdID == 0 {
|
||||
if rowNum == 0 {
|
||||
continue
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
if sheetIndex == 0 {
|
||||
thingMap.ThingType = model.ThingTypeStore
|
||||
} else {
|
||||
thingMap.ThingType = model.ThingTypeSku
|
||||
}
|
||||
dao.WrapAddIDCULEntity(thingMap, ctx.GetUserName())
|
||||
thingMapList = append(thingMapList, thingMap)
|
||||
}
|
||||
}
|
||||
return thingMapList, err
|
||||
}
|
||||
|
||||
func getFakeThingMap(ctx *jxcontext.Context, db *dao.DaoDB) (storeMap, skuMap map[int]string, err error) {
|
||||
var thingMapList []*model.FakeJdThingMap
|
||||
err = dao.GetRows(db, &thingMapList, "SELECT t1.* FROM fake_jd_thing_map t1")
|
||||
if err == nil {
|
||||
storeMap, skuMap = make(map[int]string), make(map[int]string)
|
||||
for _, v := range thingMapList {
|
||||
if v.ThingType == model.ThingTypeStore {
|
||||
storeMap[v.JxID] = utils.Int64ToStr(v.JdID)
|
||||
} else {
|
||||
skuMap[v.JxID] = utils.Int64ToStr(v.JdID)
|
||||
}
|
||||
}
|
||||
}
|
||||
return storeMap, skuMap, err
|
||||
}
|
||||
|
||||
func UploadFakeJdThingMap(ctx *jxcontext.Context, reader io.Reader, isSyncNow, isAsync, isContinueWhenError bool) (hint string, err error) {
|
||||
thingMapList, err := excel2FakeJdThingMap(ctx, reader)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
db := dao.GetDB()
|
||||
txDB, _ := dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
dao.Rollback(db, txDB)
|
||||
panic(r)
|
||||
}
|
||||
}()
|
||||
_, err = dao.ExecuteSQL(db, "DELETE t1 FROM fake_jd_thing_map t1")
|
||||
if err != nil {
|
||||
dao.Rollback(db, txDB)
|
||||
return "", err
|
||||
}
|
||||
err = dao.CreateMultiEntities(db, thingMapList)
|
||||
if err != nil {
|
||||
dao.Rollback(db, txDB)
|
||||
return "", err
|
||||
}
|
||||
dao.Commit(db, txDB)
|
||||
|
||||
if isSyncNow {
|
||||
if storeMap, skuMap, err2 := getFakeThingMap(ctx, db); err2 == nil {
|
||||
hint, err = SyncFakeJdStoreSku(ctx, nil, storeMap, skuMap, isAsync, isContinueWhenError)
|
||||
}
|
||||
} else {
|
||||
hint = utils.Int2Str(len(thingMapList))
|
||||
}
|
||||
return hint, err
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
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,207 +0,0 @@
|
||||
package cms
|
||||
|
||||
// var (
|
||||
// LoginTypeFieldMap = map[string]string{
|
||||
// mobile.LoginType: "tel",
|
||||
// weixin.LoginType: "openid",
|
||||
// weixin.LoginTypeMiniProgram: "openid_mini",
|
||||
// }
|
||||
// )
|
||||
|
||||
// func GetStoreUsers(ctx *jxcontext.Context, storeID int) (storeUserInfos []*dao.StoreUserInfo, err error) {
|
||||
// sql := `
|
||||
// SELECT t1.id, t1.jxstoreid, t1.openid, t1.tel, t1.nickname, t1.parentid, t3.tel parent_mobile,
|
||||
// CONCAT("[", GROUP_CONCAT(CONCAT('{"id":', t2.id, ',"parentID":', t2.parentid, ',"tel":"', t2.tel, '","nickname":"', IF(t2.nickname IS NULL, "", t2.nickname), '"}')), "]") members_str
|
||||
// FROM weixins t1
|
||||
// LEFT JOIN weixins t2 ON t2.parentid = t1.id
|
||||
// LEFT JOIN weixins t3 ON t1.parentid = t3.id
|
||||
// WHERE t1.parentid = -1 AND t1.jxstoreid = ?
|
||||
// GROUP BY 1,2,3,4,5,6,7;
|
||||
// `
|
||||
// if err = dao.GetRows(nil, &storeUserInfos, sql, storeID); err == nil {
|
||||
// for _, storeUserInfo := range storeUserInfos {
|
||||
// if storeUserInfo.MembersStr != "" {
|
||||
// err = utils.UnmarshalUseNumber([]byte(storeUserInfo.MembersStr), &storeUserInfo.Members)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return storeUserInfos, err
|
||||
// }
|
||||
|
||||
// func GetUserInfo(ctx *jxcontext.Context, mobile string) (storeUserInfo *dao.StoreUserInfo, err error) {
|
||||
// storeUserInfo, err = dao.GetUserStoreInfo(dao.GetDB(), "tel", mobile)
|
||||
// globals.SugarLogger.Debugf("GetUserInfo:%s, token:%s, mobile:%s, storeUserInfo:%s, err:%v", ctx.GetTrackInfo(), ctx.GetToken(), mobile, utils.Format4Output(storeUserInfo, true), err)
|
||||
// return storeUserInfo, err
|
||||
// }
|
||||
|
||||
// func GetSelfInfo(ctx *jxcontext.Context) (storeUserInfo *dao.StoreUserInfo, err error) {
|
||||
// loginInfo := ctx.GetLoginInfo()
|
||||
// if loginInfo == nil {
|
||||
// return nil, auth.ErrAPINeedRealLogin
|
||||
// }
|
||||
// fieldName := LoginTypeFieldMap[loginInfo.GetAuthType()]
|
||||
// if fieldName == "" {
|
||||
// return nil, auth.ErrIllegalLoginType
|
||||
// }
|
||||
// storeUserInfo, err = dao.GetUserStoreInfo(dao.GetDB(), fieldName, loginInfo.GetAuthID())
|
||||
// return storeUserInfo, err
|
||||
// }
|
||||
|
||||
// func GetMyStoreList(ctx *jxcontext.Context) (storeList []*dao.StoreWithCityName, err error) {
|
||||
// mobileNum, _ := ctx.GetMobileAndUserID()
|
||||
// if mobileNum == "" {
|
||||
// return nil, fmt.Errorf("不能得到用户手机号")
|
||||
// }
|
||||
// storeList, err = dao.GetStoreListByMobile(dao.GetDB(), mobileNum)
|
||||
// return storeList, err
|
||||
// }
|
||||
|
||||
// func UnbindMobile(ctx *jxcontext.Context, mobile string) (num int64, err error) {
|
||||
// db := dao.GetDB()
|
||||
// num, err = dao.UpdateEntityByKV(db, &legacymodel.WeiXins{}, map[string]interface{}{
|
||||
// "JxStoreID": 0,
|
||||
// "ParentID": -1,
|
||||
// }, map[string]interface{}{
|
||||
// "Tel": mobile,
|
||||
// })
|
||||
// if err == nil {
|
||||
// jxutils.HandleUserWXRemark(db, mobile, false)
|
||||
// TransferLegacyWeixins(mobile)
|
||||
// }
|
||||
// return num, err
|
||||
// }
|
||||
|
||||
// func BindMobile2Store(ctx *jxcontext.Context, mobile string, storeID int) (num int64, err error) {
|
||||
// db := dao.GetDB()
|
||||
// user, err2 := verifyMobileIsBlank(db, mobile)
|
||||
// if err = err2; err == nil || err == orm.ErrNoRows {
|
||||
// user.JxStoreID = storeID
|
||||
// if err == nil {
|
||||
// txDB , _ := dao.Begin(db)
|
||||
// defer func() {
|
||||
// if r := recover(); r != nil {
|
||||
// dao.Rollback(db, txDB)
|
||||
// panic(r)
|
||||
// }
|
||||
// }()
|
||||
// if num, err = dao.UpdateEntity(db, user, "JxStoreID"); err == nil {
|
||||
// err = dao.SetWeiXinsEmpty2Null(db, user)
|
||||
// }
|
||||
// if err != nil {
|
||||
// dao.Rollback(db, txDB)
|
||||
// } else {
|
||||
// dao.Commit(db, txDB)
|
||||
// }
|
||||
// } else {
|
||||
// // globals.SugarLogger.Debug(utils.Format4Output(user, false))
|
||||
// dao.WrapAddIDCULEntity(user, ctx.GetUserName())
|
||||
// user.ParentID = -1
|
||||
// if err = dao.CreateWeiXins(db, user); err == nil {
|
||||
// num = 1
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// if err == nil {
|
||||
// jxutils.HandleUserWXRemark(db, mobile, false)
|
||||
// TransferLegacyWeixins(mobile)
|
||||
// }
|
||||
// return num, err
|
||||
// }
|
||||
|
||||
// func AddMobile2Mobile(ctx *jxcontext.Context, parentMobile, mobile string) (num int64, err error) {
|
||||
// db := dao.GetDB()
|
||||
// parentUser := &legacymodel.WeiXins{}
|
||||
// parentUser.Tel = parentMobile
|
||||
// if err = dao.GetEntity(db, parentUser, "Tel"); err == nil {
|
||||
// if parentUser.ParentID == -1 {
|
||||
// if err = verifyMobileHasNoMembers(db, mobile); err == nil {
|
||||
// user, err2 := verifyMobileIsBlank(db, mobile)
|
||||
// if err = err2; err == nil || err == orm.ErrNoRows {
|
||||
// user.ParentID = parentUser.ID
|
||||
// if err == nil {
|
||||
// // todo transaction
|
||||
// if num, err = dao.UpdateEntity(db, user, "ParentID"); err == nil {
|
||||
// err = dao.SetWeiXinsEmpty2Null(db, user)
|
||||
// }
|
||||
// } else {
|
||||
// dao.WrapAddIDCULEntity(user, ctx.GetUserName())
|
||||
// if err = dao.CreateWeiXins(db, user); err == nil {
|
||||
// num = 1
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// } else {
|
||||
// err = fmt.Errorf("%s本身是成员", parentMobile)
|
||||
// }
|
||||
// }
|
||||
// if err == nil {
|
||||
// jxutils.HandleUserWXRemark(db, mobile, false)
|
||||
// TransferLegacyWeixins(mobile)
|
||||
// }
|
||||
// return num, err
|
||||
// }
|
||||
|
||||
// func ChangeMobile(ctx *jxcontext.Context, curMobile, expectedMobile string) (num int64, err error) {
|
||||
// num, err = dao.UpdateEntityByKV(nil, &legacymodel.WeiXins{}, map[string]interface{}{
|
||||
// "Tel": expectedMobile,
|
||||
// }, map[string]interface{}{
|
||||
// "Tel": curMobile,
|
||||
// })
|
||||
// if err == nil {
|
||||
// TransferLegacyWeixins(curMobile)
|
||||
// TransferLegacyWeixins(expectedMobile)
|
||||
// }
|
||||
// return num, err
|
||||
// }
|
||||
|
||||
// func verifyMobileIsBlank(db *dao.DaoDB, mobile string) (user *legacymodel.WeiXins, err error) {
|
||||
// if !jxutils.IsStringLikeMobile(mobile) {
|
||||
// return nil, fmt.Errorf("%s看起来不像是一个手机号", mobile)
|
||||
// }
|
||||
// user = &legacymodel.WeiXins{
|
||||
// Tel: mobile,
|
||||
// }
|
||||
// if err = dao.GetEntity(db, user, "Tel"); err == nil {
|
||||
// if user.ParentID != -1 && user.ParentID != 0 {
|
||||
// userParent := &legacymodel.WeiXins{
|
||||
// ID: user.ParentID,
|
||||
// }
|
||||
// if err = dao.GetEntity(db, userParent); err != nil && err != orm.ErrNoRows {
|
||||
// return nil, err
|
||||
// }
|
||||
// if err != orm.ErrNoRows {
|
||||
// err = fmt.Errorf("%s已经是组长:%s,门店:%d的小组成员", mobile, userParent.Tel, userParent.JxStoreID)
|
||||
// } else {
|
||||
// err = nil
|
||||
// }
|
||||
// } else if user.JxStoreID != 0 {
|
||||
// store := &model.Store{}
|
||||
// store.ID = user.JxStoreID
|
||||
// if err = dao.GetEntity(db, store); err == nil {
|
||||
// err = fmt.Errorf("%s本身已经是门店:%d的组长", mobile, user.JxStoreID)
|
||||
// } else if dao.IsNoRowsError(err) {
|
||||
// err = nil
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return user, err
|
||||
// }
|
||||
|
||||
// func verifyMobileHasNoMembers(db *dao.DaoDB, mobile string) (err error) {
|
||||
// countInfo := &struct{ Ct int }{}
|
||||
// if err = dao.GetRow(db, countInfo, `
|
||||
// SELECT COUNT(*) ct
|
||||
// FROM weixins t1
|
||||
// JOIN weixins t2 ON t1.parentid = t2.id AND t2.tel = ?
|
||||
// `, mobile); err == nil {
|
||||
// if countInfo.Ct > 0 {
|
||||
// user := &legacymodel.WeiXins{
|
||||
// Tel: mobile,
|
||||
// }
|
||||
// dao.GetEntity(db, user, "Tel")
|
||||
// err = fmt.Errorf("%s本身已经是门店:%d组长", mobile, user.JxStoreID)
|
||||
// }
|
||||
// }
|
||||
// return err
|
||||
// }
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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,121 +0,0 @@
|
||||
package cms
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/business/partner/purchase/mtwm"
|
||||
)
|
||||
|
||||
// GetMtSkuDetailInfo 获取美团商品信息,暂时只支持美团
|
||||
func GetMtSkuDetailInfo(ctx *jxcontext.Context, vendorOrderID string, vendorSkuName string) (outSkuNameExt *model.SkuNameExt, err error) {
|
||||
orderDetail, err := partner.CurOrderManager.LoadOrder(vendorOrderID, model.VendorIDMTWM)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 获取订单详情
|
||||
mtApi := mtwm.GetAPI(orderDetail.VendorOrgCode, orderDetail.JxStoreID, orderDetail.VendorStoreID)
|
||||
mtOrderDetail, err := mtApi.OrderGetOrderDetail(utils.Str2Int64(vendorOrderID), false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var detail []map[string]interface{}
|
||||
if err = utils.UnmarshalUseNumber([]byte(mtOrderDetail["detail"].(string)), &detail); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mtCode := ""
|
||||
for _, product := range detail {
|
||||
if product["food_name"].(string) == vendorSkuName {
|
||||
if product["app_food_code"].(string) == "" {
|
||||
return nil, fmt.Errorf("[%s] 未获取到商品的美团code,无法创建商品", vendorSkuName)
|
||||
}
|
||||
mtCode = product["app_food_code"].(string)
|
||||
break
|
||||
}
|
||||
}
|
||||
if mtCode == "" {
|
||||
return nil, fmt.Errorf("[%s] 未获取到商品的美团code,无法创建商品", vendorSkuName)
|
||||
}
|
||||
|
||||
// 获取美团商品详情
|
||||
mtSkuDetail, err := mtApi.RetailGet(orderDetail.VendorStoreID, mtCode)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
skuName := &model.SkuNameExt{
|
||||
SkuName: model.SkuName{
|
||||
Prefix: "",
|
||||
Name: mtSkuDetail.Name,
|
||||
Upc: utils.String2Pointer(mtSkuDetail.UpcCode),
|
||||
Status: 1,
|
||||
CategoryID: 291, // ?
|
||||
IsGlobal: 1,
|
||||
Unit: mtSkuDetail.Unit,
|
||||
Price: utils.Float64TwoInt(mtSkuDetail.Price * float64(100)),
|
||||
DescImg: mtSkuDetail.PictureContents,
|
||||
JdsStockSwitch: 1,
|
||||
PreparationTime: 0,
|
||||
MtAttribute: "",
|
||||
// 京西创建是传入的属性
|
||||
// [{"attr_id":"1200000088","attr_name":"品牌","valueList":[{"value":"其他"}]},{"attr_id":"1200000135","attr_name":"包装方式","valueList":[{"value_id":"1300000231","value":"袋装"}]}]
|
||||
// 美团获取的属性,不太好转换,暂时不弄
|
||||
// [{"attrId":1200000202,"attrName":"品种","setAttrId":true,"setAttrName":true,"setValueList":true,"valueList":[{"setValue":true,"setValueId":true,"value":"二荆条","valueId":1300015565}],"valueListIterator":[{"$ref":"$[0].valueList[0]"}],"valueListSize":1},{"attrId":1200000135,"attrName":"包装方式","setAttrId":true,"setAttrName":true,"setValueList":true,"valueList":[{"setValue":true,"setValueId":true,"value":"散装","valueId":1300000232}],"valueListIterator":[{"$ref":"$[1].valueList[0]"}],"valueListSize":1}]
|
||||
},
|
||||
Skus: nil,
|
||||
MtwmCategoryID: utils.Int2Str(mtSkuDetail.TagID),
|
||||
}
|
||||
|
||||
skus := make([]*model.SkuWithVendor, 0, 0)
|
||||
for _, mtSks := range mtSkuDetail.SkuList {
|
||||
sku := &model.SkuWithVendor{
|
||||
Sku: &model.Sku{
|
||||
MinOrderCount: utils.Str2Int(mtSks.MinOrderCount),
|
||||
LadderBoxNum: utils.Str2Int(mtSks.LadderBoxNum),
|
||||
LadderBoxPrice: utils.Float64TwoInt(utils.Str2Float64(mtSks.Price) * float64(100)),
|
||||
SpecQuality: float32(utils.Str2Float64(mtSks.Weight)),
|
||||
Weight: utils.Str2Int(mtSks.Weight),
|
||||
SpecUnit: mtSks.Unit,
|
||||
Status: 1,
|
||||
Comment: "",
|
||||
EclpID: "",
|
||||
},
|
||||
}
|
||||
skus = append(skus, sku)
|
||||
}
|
||||
skuName.Skus = skus
|
||||
|
||||
mTImg2Jx(skuName, mtSkuDetail.PictureList)
|
||||
return AddSkuName(ctx, skuName, ctx.GetUserName())
|
||||
}
|
||||
|
||||
func mTImg2Jx(sku *model.SkuNameExt, pictureList []string) {
|
||||
switch len(pictureList) {
|
||||
case 0:
|
||||
return
|
||||
case 1:
|
||||
sku.Img = pictureList[0]
|
||||
case 2:
|
||||
sku.Img = pictureList[0]
|
||||
sku.Img2 = pictureList[1]
|
||||
case 3:
|
||||
sku.Img = pictureList[0]
|
||||
sku.Img2 = pictureList[1]
|
||||
sku.Img3 = pictureList[2]
|
||||
case 4:
|
||||
sku.Img = pictureList[0]
|
||||
sku.Img2 = pictureList[1]
|
||||
sku.Img3 = pictureList[2]
|
||||
sku.Img4 = pictureList[3]
|
||||
case 5:
|
||||
sku.Img = pictureList[0]
|
||||
sku.Img2 = pictureList[1]
|
||||
sku.Img3 = pictureList[2]
|
||||
sku.Img4 = pictureList[3]
|
||||
sku.Img5 = pictureList[4]
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,7 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"git.rosy.net.cn/baseapi/platformapi/tencent_map"
|
||||
"sort"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
)
|
||||
|
||||
type Store4User struct {
|
||||
@@ -40,7 +31,6 @@ type Store4User struct {
|
||||
|
||||
Distance int `json:"distance"`
|
||||
WalkDistance int `json:"walkDistance"`
|
||||
DeliverySelf int `json:"deliverySelf"`
|
||||
}
|
||||
|
||||
type Store4UserList []*Store4User
|
||||
@@ -63,236 +53,166 @@ func (x Store4UserList) Swap(i, j int) {
|
||||
x[i], x[j] = x[j], x[i]
|
||||
}
|
||||
|
||||
func GetNearSupplyGoodsStoreByStoreID(ctx *jxcontext.Context, storeID int) (store *model.Store, err error) {
|
||||
var (
|
||||
stores []*model.Store
|
||||
db = dao.GetDB()
|
||||
)
|
||||
store2, _ := dao.GetStoreDetail(db, storeID, model.VendorIDJX, "")
|
||||
if store2 == nil {
|
||||
return nil, fmt.Errorf("该门店未绑定京西平台!storeID: %v", storeID)
|
||||
}
|
||||
if store2.IsSupplyGoods == model.YES {
|
||||
return nil, fmt.Errorf("该门店已经是货源门店,无法从其他货源门店进货!storeID: %v", storeID)
|
||||
}
|
||||
sql := `
|
||||
SELECT a.*
|
||||
FROM store a
|
||||
JOIN store_map b ON b.store_id = a.id
|
||||
JOIN store c ON c.city_code = a.city_code AND c.id = ?
|
||||
WHERE a.deleted_at = ?
|
||||
AND b.deleted_at = ?
|
||||
AND b.vendor_id = ?
|
||||
AND b.is_supply_goods = ?
|
||||
AND a.status = ?
|
||||
`
|
||||
sqlParams := []interface{}{
|
||||
storeID,
|
||||
utils.DefaultTimeValue, utils.DefaultTimeValue,
|
||||
model.VendorIDJX, model.YES, model.StoreStatusOpened,
|
||||
}
|
||||
err = dao.GetRows(db, &stores, sql, sqlParams...)
|
||||
if len(stores) > 0 {
|
||||
realDistance := float64(0)
|
||||
for _, v := range stores {
|
||||
distance := jxutils.EarthDistance(jxutils.IntCoordinate2Standard(v.Lng), jxutils.IntCoordinate2Standard(v.Lat), jxutils.IntCoordinate2Standard(store2.Lng), jxutils.IntCoordinate2Standard(store2.Lat))
|
||||
if realDistance == 0 {
|
||||
realDistance = distance
|
||||
store = v
|
||||
} else {
|
||||
if realDistance > distance {
|
||||
realDistance = distance
|
||||
store = v
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return store, err
|
||||
}
|
||||
|
||||
func GetStoreListByLocation(ctx *jxcontext.Context, lng, lat float64, maxRadius int, needWalkDistance, isJds bool, brandID []int) (storeList []*Store4User, err error) {
|
||||
const (
|
||||
maxStoreCount4User = 5
|
||||
)
|
||||
|
||||
var (
|
||||
sql string
|
||||
sqlParams []interface{}
|
||||
)
|
||||
|
||||
lng2, _ := jxutils.ConvertDistanceToLogLat(lng, lat, float64(maxRadius), 90)
|
||||
_, lat2 := jxutils.ConvertDistanceToLogLat(lng, lat, float64(maxRadius), 0)
|
||||
lng1 := lng - (lng2 - lng)
|
||||
lat1 := lat - (lat2 - lat)
|
||||
if !isJds {
|
||||
sql = `
|
||||
SELECT t1.*,
|
||||
city.name city_name,sm.delivery_self
|
||||
FROM store t1
|
||||
JOIN place city ON city.code = t1.city_code
|
||||
JOIN store_map sm ON sm.store_id = t1.id AND sm.vendor_id = ? AND sm.deleted_at = ? AND sm.status <> ?
|
||||
WHERE t1.deleted_at = ? AND t1.status <> ? AND t1.lng > ? AND t1.lng < ? AND t1.lat > ? AND t1.lat < ?
|
||||
AND sm.is_order <> ?
|
||||
AND t1.id <> ?
|
||||
`
|
||||
sqlParams = append(sqlParams,
|
||||
model.VendorIDJX, utils.DefaultTimeValue, model.StoreStatusDisabled,
|
||||
utils.DefaultTimeValue, model.StoreStatusDisabled, jxutils.StandardCoordinate2Int(lng1), jxutils.StandardCoordinate2Int(lng2), jxutils.StandardCoordinate2Int(lat1), jxutils.StandardCoordinate2Int(lat2),
|
||||
model.YES,
|
||||
model.MatterStoreID,
|
||||
)
|
||||
if len(brandID) != 0 {
|
||||
sql += " AND t1.brand_id IN (" + dao.GenQuestionMarks(len(brandID)) + ")"
|
||||
sqlParams = append(sqlParams, brandID)
|
||||
}
|
||||
sql += `
|
||||
ORDER BY t1.id
|
||||
`
|
||||
} else {
|
||||
sql = `
|
||||
SELECT t1.*,
|
||||
city.name city_name,sm.delivery_self
|
||||
FROM store t1
|
||||
JOIN place city ON city.code = t1.city_code
|
||||
JOIN store_map sm ON sm.store_id = t1.id AND sm.vendor_id = ? AND sm.deleted_at = ? AND sm.status = ?
|
||||
WHERE t1.deleted_at = ? AND t1.status = ? AND t1.lng > ? AND t1.lng < ? AND t1.lat > ? AND t1.lat < ?
|
||||
AND sm.is_order <> ?
|
||||
AND t1.id <> ?
|
||||
ORDER BY t1.id
|
||||
`
|
||||
sqlParams = []interface{}{
|
||||
model.VendorIDJDShop, utils.DefaultTimeValue, model.StoreStatusOpened,
|
||||
utils.DefaultTimeValue, model.StoreStatusOpened, jxutils.StandardCoordinate2Int(lng1), jxutils.StandardCoordinate2Int(lng2), jxutils.StandardCoordinate2Int(lat1), jxutils.StandardCoordinate2Int(lat2),
|
||||
model.YES,
|
||||
model.MatterStoreID,
|
||||
}
|
||||
}
|
||||
var storeList1 []*Store4User
|
||||
if err = dao.GetRows(dao.GetDB(), &storeList1, sql, sqlParams...); err == nil {
|
||||
var storeList2 []*Store4User
|
||||
for _, v := range storeList1 {
|
||||
distance := jxutils.Point2StoreDistance(lng, lat, v.Lng, v.Lat, v.DeliveryRangeType, v.DeliveryRange)
|
||||
if distance > 0 || (lng == jxutils.IntCoordinate2Standard(v.Lng) && lat == jxutils.IntCoordinate2Standard(v.Lat)) {
|
||||
v.Distance = distance
|
||||
storeList2 = append(storeList2, v)
|
||||
}
|
||||
}
|
||||
|
||||
// 为了审核用
|
||||
if len(storeList2) == 0 {
|
||||
sql2 := `
|
||||
SELECT t1.*,
|
||||
city.name city_name
|
||||
FROM store t1
|
||||
JOIN place city ON city.code = t1.city_code
|
||||
WHERE t1.deleted_at = ? AND t1.id = ?
|
||||
`
|
||||
sqlParams2 := []interface{}{
|
||||
// model.VendorIDJX, utils.DefaultTimeValue, model.StoreStatusDisabled,
|
||||
utils.DefaultTimeValue,
|
||||
// model.StoreStatusDisabled,
|
||||
// jxutils.StandardCoordinate2Int(0),
|
||||
// jxutils.StandardCoordinate2Int(10000),
|
||||
// jxutils.StandardCoordinate2Int(0),
|
||||
// jxutils.StandardCoordinate2Int(10000),
|
||||
// model.YES,
|
||||
102919, //商城模板店
|
||||
}
|
||||
dao.GetRows(dao.GetDB(), &storeList2, sql2, sqlParams2...)
|
||||
// if len(storeList2) > 1 {
|
||||
// storeList2 = storeList2[:1]
|
||||
// }
|
||||
}
|
||||
|
||||
// 如果要求以步行距离来算
|
||||
if needWalkDistance {
|
||||
var coordList []*tencent_map.Coordinate
|
||||
for _, v := range storeList2 {
|
||||
coordList = append(coordList, &tencent_map.Coordinate{
|
||||
Lng: v.FloatLng,
|
||||
Lat: v.FloatLat,
|
||||
})
|
||||
}
|
||||
if distanceList, err2 := api.TencentMapAPI.BatchWalkingDistance(lng, lat, coordList); err2 == nil {
|
||||
for k, v := range storeList2 {
|
||||
v.WalkDistance = int(distanceList[k])
|
||||
}
|
||||
} else {
|
||||
return nil, err2
|
||||
}
|
||||
}
|
||||
|
||||
sort.Sort(Store4UserList(storeList2))
|
||||
storeList = storeList2
|
||||
if len(storeList) > maxStoreCount4User {
|
||||
storeList = storeList[:maxStoreCount4User]
|
||||
}
|
||||
}
|
||||
return storeList, err
|
||||
}
|
||||
|
||||
func GetVendorOrgCode(ctx *jxcontext.Context, vendorID int, vendorOrgCode, vendorType string) (vendorOrgs []*model.VendorOrgCode, err error) {
|
||||
return dao.GetVendorOrgCode(dao.GetDB(), vendorID, vendorOrgCode, vendorType)
|
||||
}
|
||||
|
||||
func UpdateVendorOrgCode(ctx *jxcontext.Context, ID int, payload map[string]interface{}) (err error) {
|
||||
var (
|
||||
db = dao.GetDB()
|
||||
vendorOrgCode = &model.VendorOrgCode{}
|
||||
)
|
||||
vendorOrgCode.ID = ID
|
||||
err = dao.GetEntity(db, vendorOrgCode)
|
||||
valid := dao.StrictMakeMapByStructObject(payload, vendorOrgCode, ctx.GetUserName())
|
||||
if len(valid) > 0 {
|
||||
if valid["key"] != nil {
|
||||
valid["vendorOrgCode"] = valid["key"]
|
||||
delete(valid, "key")
|
||||
}
|
||||
if valid["code"] != nil {
|
||||
valid["vendorID"] = valid["code"]
|
||||
delete(valid, "code")
|
||||
}
|
||||
if valid["name"] != nil {
|
||||
valid["comment"] = valid["name"]
|
||||
delete(valid, "name")
|
||||
}
|
||||
txDB, _ := dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
dao.Rollback(db, txDB)
|
||||
panic(r)
|
||||
}
|
||||
}()
|
||||
if _, err = dao.UpdateEntityLogically(db, vendorOrgCode, valid, ctx.GetUserName(), nil); err != nil {
|
||||
dao.Rollback(db, txDB)
|
||||
return err
|
||||
}
|
||||
dao.Commit(db, txDB)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func AddVendorOrgCode(ctx *jxcontext.Context, vendorOrgCode *model.VendorOrgCode) (err error) {
|
||||
var (
|
||||
db = dao.GetDB()
|
||||
)
|
||||
list, err := dao.GetVendorOrgCode(db, vendorOrgCode.VendorID, vendorOrgCode.VendorOrgCode, model.VendorOrgTypePlatform)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(list) > 0 {
|
||||
vendorOrgCode.ID = list[0].ID
|
||||
_, err = dao.UpdateEntity(db, vendorOrgCode, "token", "updated_at", "app_key", "app_secret", "comment", "vendor_org_code")
|
||||
return err
|
||||
}
|
||||
|
||||
var userName string
|
||||
if ctx != nil {
|
||||
userName = ctx.GetUserName()
|
||||
} else {
|
||||
userName = "system"
|
||||
}
|
||||
dao.WrapAddIDCULDEntity(vendorOrgCode, userName)
|
||||
dao.CreateEntity(db, vendorOrgCode)
|
||||
return err
|
||||
}
|
||||
//
|
||||
//func GetNearSupplyGoodsStoreByStoreID(ctx *jxcontext.Context, storeID int) (store *model.Store, err error) {
|
||||
// var (
|
||||
// stores []*model.Store
|
||||
// db = dao.GetDB()
|
||||
// )
|
||||
// store2, _ := dao.GetStoreDetail(db, storeID, model.VendorIDJX)
|
||||
// if store2 == nil {
|
||||
// return nil, fmt.Errorf("该门店未绑定京西平台!storeID: %v", storeID)
|
||||
// }
|
||||
// if store2.IsSupplyGoods == model.YES {
|
||||
// return nil, fmt.Errorf("该门店已经是货源门店,无法从其他货源门店进货!storeID: %v", storeID)
|
||||
// }
|
||||
// sql := `
|
||||
// SELECT a.*
|
||||
// FROM store a
|
||||
// JOIN store_map b ON b.store_id = a.id
|
||||
// JOIN store c ON c.city_code = a.city_code AND c.id = ?
|
||||
// WHERE a.deleted_at = ?
|
||||
// AND b.deleted_at = ?
|
||||
// AND b.vendor_id = ?
|
||||
// AND b.is_supply_goods = ?
|
||||
// AND a.status = ?
|
||||
// `
|
||||
// sqlParams := []interface{}{
|
||||
// storeID,
|
||||
// utils.DefaultTimeValue, utils.DefaultTimeValue,
|
||||
// model.VendorIDJX, model.YES, model.StoreStatusOpened,
|
||||
// }
|
||||
// err = dao.GetRows(db, &stores, sql, sqlParams)
|
||||
// if len(stores) > 0 {
|
||||
// realDistance := float64(0)
|
||||
// for _, v := range stores {
|
||||
// distance := jxutils.EarthDistance(jxutils.IntCoordinate2Standard(v.Lng), jxutils.IntCoordinate2Standard(v.Lat), jxutils.IntCoordinate2Standard(store2.Lng), jxutils.IntCoordinate2Standard(store2.Lat))
|
||||
// if realDistance == 0 {
|
||||
// realDistance = distance
|
||||
// store = v
|
||||
// } else {
|
||||
// if realDistance > distance {
|
||||
// realDistance = distance
|
||||
// store = v
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return store, err
|
||||
//}
|
||||
//
|
||||
//func GetStoreListByLocation(ctx *jxcontext.Context, lng, lat float64, maxRadius int, needWalkDistance, isJds bool) (storeList []*Store4User, err error) {
|
||||
// const (
|
||||
// maxStoreCount4User = 5
|
||||
// )
|
||||
//
|
||||
// var (
|
||||
// sql string
|
||||
// sqlParams []interface{}
|
||||
// )
|
||||
//
|
||||
// lng2, _ := jxutils.ConvertDistanceToLogLat(lng, lat, float64(maxRadius), 90)
|
||||
// _, lat2 := jxutils.ConvertDistanceToLogLat(lng, lat, float64(maxRadius), 0)
|
||||
// lng1 := lng - (lng2 - lng)
|
||||
// lat1 := lat - (lat2 - lat)
|
||||
// // globals.SugarLogger.Debugf("%f,%f,%f,%f\n", lng1, lng2, lat1, lat2)
|
||||
// if !isJds {
|
||||
// sql = `
|
||||
// SELECT t1.*,
|
||||
// city.name city_name
|
||||
// FROM store t1
|
||||
// JOIN place city ON city.code = t1.city_code
|
||||
// JOIN store_map sm ON sm.store_id = t1.id AND sm.vendor_id = ? AND sm.deleted_at = ? AND sm.status <> ?
|
||||
// WHERE t1.deleted_at = ? AND t1.status <> ? AND t1.lng > ? AND t1.lng < ? AND t1.lat > ? AND t1.lat < ?
|
||||
// AND sm.is_order <> ?
|
||||
// AND t1.id <> ?
|
||||
// ORDER BY t1.id
|
||||
// `
|
||||
// sqlParams = []interface{}{
|
||||
// model.VendorIDJX, utils.DefaultTimeValue, model.StoreStatusDisabled,
|
||||
// utils.DefaultTimeValue, model.StoreStatusDisabled, jxutils.StandardCoordinate2Int(lng1), jxutils.StandardCoordinate2Int(lng2), jxutils.StandardCoordinate2Int(lat1), jxutils.StandardCoordinate2Int(lat2),
|
||||
// model.YES,
|
||||
// model.MatterStoreID,
|
||||
// }
|
||||
// } else {
|
||||
// sql = `
|
||||
// SELECT t1.*,
|
||||
// city.name city_name
|
||||
// FROM store t1
|
||||
// JOIN place city ON city.code = t1.city_code
|
||||
// JOIN store_map sm ON sm.store_id = t1.id AND sm.vendor_id = ? AND sm.deleted_at = ? AND sm.status = ?
|
||||
// WHERE t1.deleted_at = ? AND t1.status = ? AND t1.lng > ? AND t1.lng < ? AND t1.lat > ? AND t1.lat < ?
|
||||
// AND sm.is_order <> ?
|
||||
// AND t1.id <> ?
|
||||
// ORDER BY t1.id
|
||||
// `
|
||||
// sqlParams = []interface{}{
|
||||
// model.VendorIDJDShop, utils.DefaultTimeValue, model.StoreStatusOpened,
|
||||
// utils.DefaultTimeValue, model.StoreStatusOpened, jxutils.StandardCoordinate2Int(lng1), jxutils.StandardCoordinate2Int(lng2), jxutils.StandardCoordinate2Int(lat1), jxutils.StandardCoordinate2Int(lat2),
|
||||
// model.YES,
|
||||
// model.MatterStoreID,
|
||||
// }
|
||||
// }
|
||||
// var storeList1 []*Store4User
|
||||
// if err = dao.GetRows(dao.GetDB(), &storeList1, sql, sqlParams...); err == nil {
|
||||
// var storeList2 []*Store4User
|
||||
// for _, v := range storeList1 {
|
||||
// distance := jxutils.Point2StoreDistance(lng, lat, v.Lng, v.Lat, v.DeliveryRangeType, v.DeliveryRange)
|
||||
// if distance > 0 || (lng == jxutils.IntCoordinate2Standard(v.Lng) && lat == jxutils.IntCoordinate2Standard(v.Lat)) {
|
||||
// v.Distance = distance
|
||||
// storeList2 = append(storeList2, v)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // 为了审核用
|
||||
// if len(storeList2) == 0 {
|
||||
// sql2 := `
|
||||
// SELECT t1.*,
|
||||
// city.name city_name
|
||||
// FROM store t1
|
||||
// JOIN place city ON city.code = t1.city_code
|
||||
// WHERE t1.deleted_at = ? AND t1.status <> ? AND t1.id = ?
|
||||
// `
|
||||
// sqlParams2 := []interface{}{
|
||||
// // model.VendorIDJX, utils.DefaultTimeValue, model.StoreStatusDisabled,
|
||||
// utils.DefaultTimeValue,
|
||||
// model.StoreStatusDisabled,
|
||||
// // jxutils.StandardCoordinate2Int(0),
|
||||
// // jxutils.StandardCoordinate2Int(10000),
|
||||
// // jxutils.StandardCoordinate2Int(0),
|
||||
// // jxutils.StandardCoordinate2Int(10000),
|
||||
// // model.YES,
|
||||
// 102919, //商城模板店
|
||||
// }
|
||||
// dao.GetRows(dao.GetDB(), &storeList2, sql2, sqlParams2...)
|
||||
// // if len(storeList2) > 1 {
|
||||
// // storeList2 = storeList2[:1]
|
||||
// // }
|
||||
// }
|
||||
//
|
||||
// // 如果要求以步行距离来算
|
||||
// if needWalkDistance {
|
||||
// var coordList []*autonavi.Coordinate
|
||||
// for _, v := range storeList2 {
|
||||
// coordList = append(coordList, &autonavi.Coordinate{
|
||||
// Lng: v.FloatLng,
|
||||
// Lat: v.FloatLat,
|
||||
// })
|
||||
// }
|
||||
// if distanceList, err2 := api.AutonaviAPI.BatchWalkingDistance(lng, lat, coordList); err2 == nil {
|
||||
// for k, v := range storeList2 {
|
||||
// v.WalkDistance = int(distanceList[k])
|
||||
// }
|
||||
// } else {
|
||||
// return nil, err2
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// sort.Sort(Store4UserList(storeList2))
|
||||
// storeList = storeList2
|
||||
// if len(storeList) > maxStoreCount4User {
|
||||
// storeList = storeList[:maxStoreCount4User]
|
||||
// }
|
||||
// }
|
||||
// return storeList, err
|
||||
//}
|
||||
|
||||
@@ -1,33 +1,182 @@
|
||||
package event
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxstore/financial"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
"github.com/gorilla/websocket"
|
||||
)
|
||||
|
||||
var (
|
||||
NoUseEventMap = map[string]string{
|
||||
"CreateQrOrBarCode": "CreateQrOrBarCode",
|
||||
"StatisticsReportForOrders": "StatisticsReportForOrders",
|
||||
"UpdateUser": "UpdateUser",
|
||||
}
|
||||
regexpToken = regexp.MustCompile(`,"token":".*"`)
|
||||
wsClient = &WSClient{}
|
||||
//广播频道(通道)
|
||||
broadcast = make(chan *model.ImMessageRecord)
|
||||
)
|
||||
|
||||
type CheckCookie struct {
|
||||
VendorID int `json:"vendorID"`
|
||||
VendorOrgCode string `json:"vendorOrgCode"`
|
||||
Status string `json:"status"`
|
||||
const (
|
||||
sysMessageTitle = ""
|
||||
)
|
||||
|
||||
//连接的客户端,吧每个客户端都放进来
|
||||
type WSClient struct {
|
||||
Clients map[int]map[string]*websocket.Conn
|
||||
ClientsHeart map[string]*websocket.Conn
|
||||
s *sync.RWMutex
|
||||
}
|
||||
|
||||
func init() {
|
||||
clients := make(map[int]map[string]*websocket.Conn)
|
||||
clientsHeart := make(map[string]*websocket.Conn)
|
||||
wsClient.Clients = clients
|
||||
wsClient.ClientsHeart = clientsHeart
|
||||
wsClient.s = new(sync.RWMutex)
|
||||
go handleMessages()
|
||||
}
|
||||
|
||||
//广播推送消息
|
||||
func handleMessages() {
|
||||
for {
|
||||
//读取通道中的消息
|
||||
msg := <-broadcast
|
||||
if msg.GroupID == 0 {
|
||||
// globals.SugarLogger.Debugf("heart %v", utils.Format4Output(msg, false))
|
||||
if wsClient.ClientsHeart[msg.UserID] != nil {
|
||||
if err := wsClient.ClientsHeart[msg.UserID].WriteJSON(&model.ImMessageRecord{
|
||||
Key: "pang",
|
||||
}); err != nil {
|
||||
globals.SugarLogger.Debugf("heart client.WriteJSON error: %v", err)
|
||||
wsClient.ClientsHeart[msg.UserID].Close() //关闭
|
||||
delete(wsClient.ClientsHeart, msg.UserID)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
globals.SugarLogger.Debugf("clients len %v", len(wsClient.Clients))
|
||||
//循环map客户端
|
||||
for userID, client := range wsClient.Clients[msg.GroupID] {
|
||||
//把通道中的消息发送给客户端
|
||||
user, err := dao.GetUser(dao.GetDB(), msg.UserID)
|
||||
if err == nil {
|
||||
msg.UserInfo = user
|
||||
}
|
||||
globals.SugarLogger.Debugf("msg %v", utils.Format4Output(msg, false))
|
||||
if msg.CreatedAt == utils.ZeroTimeValue {
|
||||
msg.CreatedAt = time.Now()
|
||||
}
|
||||
err = client.WriteJSON(msg)
|
||||
if err != nil {
|
||||
globals.SugarLogger.Debugf("client.WriteJSON error: %v", err)
|
||||
client.Close() //关闭
|
||||
delete(wsClient.Clients[msg.GroupID], userID)
|
||||
// delete(clients, client) //删除map中的客户端
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ImMessage(userID string, ws *websocket.Conn) (err error) {
|
||||
var (
|
||||
clientUser = make(map[string]*websocket.Conn)
|
||||
db = dao.GetDB()
|
||||
)
|
||||
//将当前客户端放入map中
|
||||
messageGroups, _ := dao.GetUserMessageGroups(dao.GetDB(), userID)
|
||||
if len(messageGroups) == 0 {
|
||||
return
|
||||
}
|
||||
wsClient.s.Lock()
|
||||
clientUser[userID] = ws
|
||||
wsClient.ClientsHeart[userID] = ws
|
||||
for _, v := range messageGroups {
|
||||
if len(wsClient.Clients[v.GroupID]) > 0 {
|
||||
wsClient.Clients[v.GroupID][userID] = ws
|
||||
} else {
|
||||
wsClient.Clients[v.GroupID] = clientUser
|
||||
}
|
||||
}
|
||||
wsClient.s.Unlock()
|
||||
globals.SugarLogger.Debugf("userID :%v ,clients :%v", userID, utils.Format4Output(wsClient.Clients, false))
|
||||
|
||||
var s *model.ImMessageRecord
|
||||
for {
|
||||
//接收客户端的消息
|
||||
err := ws.ReadJSON(&s)
|
||||
if err != nil {
|
||||
globals.SugarLogger.Debugf("页面可能断开啦 ws.ReadJSON error: %v", err.Error())
|
||||
for k, _ := range wsClient.Clients {
|
||||
delete(wsClient.Clients[k], userID)
|
||||
}
|
||||
delete(wsClient.ClientsHeart, userID)
|
||||
// delete(clients, ws) //删除map中的客户端
|
||||
break //结束循环
|
||||
} else {
|
||||
//接受消息 业务逻辑
|
||||
broadcast <- s
|
||||
if s.GroupID != 0 {
|
||||
if s.GroupID != model.SysGroupID {
|
||||
//发聊天消息时,这个组所有的成员包括创建者都在userIDs里
|
||||
userIDs := []string{}
|
||||
if results, err := dao.GetMessageGroups(db, "", s.GroupID, 0, true, ""); err == nil {
|
||||
for _, v := range results {
|
||||
userIDs = append(userIDs, v.UserID)
|
||||
for _, vv := range v.MessageGroupMembers {
|
||||
userIDs = append(userIDs, vv.UserID)
|
||||
}
|
||||
}
|
||||
}
|
||||
//如果这些人不在这个组的ws池子里就打上未读标记
|
||||
for _, v := range userIDs {
|
||||
if wsClient.ClientsHeart[v] == nil {
|
||||
messageGroupReads, _ := dao.GetMessageGroupRead(db, v, s.GroupID)
|
||||
for _, vv := range messageGroupReads {
|
||||
vv.UnReadCount++
|
||||
dao.UpdateEntity(db, vv, "UnReadCount")
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if wsClient.ClientsHeart[s.ToUserID] == nil {
|
||||
messageGroupReads, _ := dao.GetMessageGroupRead(db, s.ToUserID, s.GroupID)
|
||||
for _, vv := range messageGroupReads {
|
||||
vv.UnReadCount++
|
||||
dao.UpdateEntity(db, vv, "UnReadCount")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
utils.CallFuncAsync(func() {
|
||||
if s.GroupID != 0 {
|
||||
dao.WrapAddIDCULDEntity(s, "")
|
||||
dao.CreateEntity(db, s)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
ws.Close()
|
||||
return err
|
||||
}
|
||||
|
||||
func GetOnlineUserCount() (count int) {
|
||||
wsClient.s.RLock()
|
||||
count = len(wsClient.ClientsHeart)
|
||||
wsClient.s.RUnlock()
|
||||
return count
|
||||
}
|
||||
|
||||
func AddOperateEvent(ctx *jxcontext.Context, accessUUID, jsonData string, errCode, errMsg string, useTime int, apiFunctionSpec string) (err error) {
|
||||
@@ -48,7 +197,7 @@ func AddOperateEvent(ctx *jxcontext.Context, accessUUID, jsonData string, errCod
|
||||
}
|
||||
if apiFunction != "" {
|
||||
if apiFunction[0:3] == "Get" || NoUseEventMap[apiFunction] != "" {
|
||||
return errors.New("未知错误")
|
||||
return err
|
||||
}
|
||||
}
|
||||
if accessUUID != "" {
|
||||
@@ -68,7 +217,7 @@ func AddOperateEvent(ctx *jxcontext.Context, accessUUID, jsonData string, errCod
|
||||
ErrMsg: errMsg,
|
||||
UseTime: useTime,
|
||||
}
|
||||
txDB, err := dao.Begin(db)
|
||||
txDB, _ := dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
dao.Rollback(db, txDB)
|
||||
@@ -135,66 +284,505 @@ func GetOperateEvents(ctx *jxcontext.Context, name string, apiFunctions []string
|
||||
return pageInfo, err
|
||||
}
|
||||
|
||||
func GetCheckVendorCookie(ctx *jxcontext.Context, vendorIDs []int, isAuto bool) (ccList []*CheckCookie, err error) {
|
||||
func CreateMessageGroup(ctx *jxcontext.Context, userID, userID2, groupName string, dividePercentage, quitPrice int) (messageGroupResult *dao.GetMessageGroupsResult, err error) {
|
||||
var (
|
||||
ebaiOrderID = "1577329467196263592"
|
||||
ebaiErr = "return not json"
|
||||
ebaiErr2 = "系统错误"
|
||||
mtStoreID = "7388603"
|
||||
mtErr = "返回结果格式不正常"
|
||||
jdUpcCode = "6952395700895"
|
||||
jdErr = "请输入用户名"
|
||||
// mtpsErr = "用户未登录"
|
||||
errMsg = ""
|
||||
db = dao.GetDB()
|
||||
groupID int
|
||||
)
|
||||
for _, v := range vendorIDs {
|
||||
cc := &CheckCookie{}
|
||||
var flag = false
|
||||
switch v {
|
||||
case model.VendorIDEBAI:
|
||||
resultMap, err := api.EbaiAPI.GetStoreOrderInfo(ebaiOrderID)
|
||||
if len(resultMap) < 1 && err != nil {
|
||||
if strings.Contains(err.Error(), ebaiErr) || strings.Contains(err.Error(), ebaiErr2) {
|
||||
errMsg += fmt.Sprintf(" 饿百账号:[%v]的Cookie无效了!", v)
|
||||
flag = true
|
||||
}
|
||||
for {
|
||||
groupID = jxutils.GenRand6()
|
||||
temp := &model.MessageGroup{
|
||||
GroupID: groupID,
|
||||
}
|
||||
dao.GetEntity(db, temp, "GroupID")
|
||||
if temp.UserID == "" {
|
||||
break
|
||||
}
|
||||
}
|
||||
if userID2 != "" {
|
||||
messageGroups, err := dao.GetMessageGroups(db, userID, 0, model.GroupTypeSingle, true, userID2)
|
||||
if len(messageGroups) > 0 && len(messageGroups[0].MessageGroupMembers) > 0 {
|
||||
return messageGroups[0], err
|
||||
}
|
||||
user, err := dao.GetUserByID(db, "user_id", userID2)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if user == nil {
|
||||
return nil, fmt.Errorf("无法找到要联系的用户!")
|
||||
}
|
||||
messageGroup := &model.MessageGroup{
|
||||
GroupID: groupID,
|
||||
UserID: userID,
|
||||
// Name: user.Name,
|
||||
Type: model.GroupTypeSingle,
|
||||
MaxCount: 2,
|
||||
}
|
||||
messageGroupMember := &model.MessageGroupMember{
|
||||
GroupID: groupID,
|
||||
MemberUserID: userID2,
|
||||
Type: model.GroupMemberTypeNormal,
|
||||
}
|
||||
dao.WrapAddIDCULDEntity(messageGroup, ctx.GetUserName())
|
||||
dao.WrapAddIDCULDEntity(messageGroupMember, ctx.GetUserName())
|
||||
err = dao.CreateEntity(db, messageGroup)
|
||||
err = dao.CreateEntity(db, messageGroupMember)
|
||||
if err == nil {
|
||||
messageGroupRead := &model.MessageGroupRead{
|
||||
GroupID: groupID,
|
||||
UserID: userID,
|
||||
}
|
||||
case model.VendorIDMTWM:
|
||||
_, err := api.MtwmAPI.PackagePriceGet(mtStoreID)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), mtErr) {
|
||||
errMsg += fmt.Sprintf(" 美团账号:[%v]的Cookie无效了!", v)
|
||||
flag = true
|
||||
}
|
||||
}
|
||||
case model.VendorIDJD:
|
||||
result, err := api.JdAPI.GetJdUpcCodeByName("", jdUpcCode, 1, 5)
|
||||
if len(result) < 1 && err != nil {
|
||||
if strings.Contains(err.Error(), jdErr) {
|
||||
errMsg += fmt.Sprintf(" 京东账号:[%v]的Cookie无效了!", v)
|
||||
flag = true
|
||||
}
|
||||
}
|
||||
case model.VendorIDJDShop:
|
||||
_, err := api.JdShopAPI.OrderDetail("124350112427")
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "登录") {
|
||||
errMsg += fmt.Sprintf("京东商城:[%v]的Cookie无效了!", v)
|
||||
flag = true
|
||||
dao.WrapAddIDCULEntity(messageGroupRead, ctx.GetUserName())
|
||||
messageGroupRead2 := messageGroupRead
|
||||
messageGroupRead2.UserID = userID2
|
||||
dao.CreateEntity(db, messageGroupRead)
|
||||
if err = dao.CreateEntity(db, messageGroupRead2); err == nil {
|
||||
if messageGroupReads, err := dao.GetMessageGroupRead(db, userID2, model.SysGroupID); len(messageGroupReads) == 0 && err == nil {
|
||||
messageGroupRead := &model.MessageGroupRead{
|
||||
GroupID: model.SysGroupID,
|
||||
UserID: userID2,
|
||||
}
|
||||
dao.WrapAddIDCULEntity(messageGroupRead, ctx.GetUserName())
|
||||
dao.CreateEntity(db, messageGroupRead)
|
||||
}
|
||||
}
|
||||
}
|
||||
cc.VendorID = v
|
||||
cc.VendorOrgCode = ""
|
||||
if flag {
|
||||
cc.Status = "无效"
|
||||
} else {
|
||||
cc.Status = "有效"
|
||||
} else {
|
||||
userMembers, err := dao.GetUserMember(db, userID, model.MemberTypeNormal)
|
||||
messageGroupsResult, err := dao.GetMessageGroups(db, userID, 0, model.GroupTypeMulit, false, "")
|
||||
messageGroupMembers, err := dao.GetMessageGroupMembers(db, 0, model.GroupTypeMulit, userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(userMembers) == 0 {
|
||||
return nil, fmt.Errorf("抱歉,只有会员才能创建群聊!")
|
||||
}
|
||||
if len(messageGroupsResult) > 0 {
|
||||
return nil, fmt.Errorf("您已经有群组了,请勿重复创建!群号为:%d", messageGroupsResult[0].GroupID)
|
||||
}
|
||||
if len(messageGroupMembers) > 0 {
|
||||
return nil, fmt.Errorf("您已加入了[%v]群,请先退出后再创建!", messageGroupMembers[0].GroupID)
|
||||
}
|
||||
messageGroup := &model.MessageGroup{
|
||||
GroupID: groupID,
|
||||
UserID: userID,
|
||||
Name: groupName,
|
||||
Type: model.GroupTypeMulit,
|
||||
MaxCount: 2000,
|
||||
DividePercentage: dividePercentage,
|
||||
QuitPrice: quitPrice,
|
||||
}
|
||||
user, err := dao.GetUserByID(db, "user_id", userID)
|
||||
if groupName == "" {
|
||||
messageGroup.Name = user.Name + "的集团"
|
||||
}
|
||||
dao.WrapAddIDCULDEntity(messageGroup, ctx.GetUserName())
|
||||
if err = dao.CreateEntity(db, messageGroup); err == nil {
|
||||
messageGroupRead := &model.MessageGroupRead{
|
||||
GroupID: groupID,
|
||||
UserID: userID,
|
||||
}
|
||||
dao.WrapAddIDCULEntity(messageGroupRead, ctx.GetUserName())
|
||||
dao.CreateEntity(db, messageGroupRead)
|
||||
}
|
||||
ccList = append(ccList, cc)
|
||||
}
|
||||
if isAuto && errMsg != "" {
|
||||
globals.SugarLogger.Warnf("GetCheckVendorCookie:[%v]", errMsg)
|
||||
if err == nil {
|
||||
if messageGroupReads, err := dao.GetMessageGroupRead(db, userID, model.SysGroupID); len(messageGroupReads) == 0 && err == nil {
|
||||
messageGroupRead := &model.MessageGroupRead{
|
||||
GroupID: model.SysGroupID,
|
||||
UserID: userID,
|
||||
}
|
||||
dao.WrapAddIDCULEntity(messageGroupRead, ctx.GetUserName())
|
||||
dao.CreateEntity(db, messageGroupRead)
|
||||
}
|
||||
}
|
||||
return ccList, err
|
||||
return messageGroupResult, err
|
||||
}
|
||||
|
||||
func GetMessageGroupByUser(ctx *jxcontext.Context, userID string) (messageGroupResult []*dao.GetMessageGroupsResult, err error) {
|
||||
var (
|
||||
db = dao.GetDB()
|
||||
)
|
||||
messageGroups, err := dao.GetMessageGroups(db, "", model.SysGroupID, 0, false, "")
|
||||
messageGroups2, err := dao.GetMessageGroups(db, userID, 0, 0, true, "")
|
||||
messageGroups = append(messageGroups, messageGroups2...)
|
||||
messageGroupMembers, err := dao.GetMessageGroupMembers(db, 0, 0, userID)
|
||||
for _, v := range messageGroupMembers {
|
||||
if messageGroupList, err := dao.GetMessageGroups(db, "", v.GroupID, 0, false, ""); err == nil {
|
||||
messageGroups = append(messageGroups, messageGroupList...)
|
||||
}
|
||||
}
|
||||
for _, v := range messageGroups {
|
||||
//是这个人创建的群聊,如果是单聊就返回对方的头像
|
||||
if v.Type == model.GroupTypeSingle {
|
||||
var userID2 string
|
||||
if v.UserID == userID {
|
||||
userID2 = v.MessageGroupMembers[0].MemberUserID
|
||||
} else {
|
||||
userID2 = userID
|
||||
}
|
||||
if user, err := dao.GetUserByID(db, "user_id", userID2); err == nil {
|
||||
v.Avatar = user.Avatar
|
||||
v.Name = user.Name
|
||||
}
|
||||
}
|
||||
var (
|
||||
imMessageRecord *model.ImMessageRecord
|
||||
sql string
|
||||
sqlParams = []interface{}{}
|
||||
)
|
||||
if v.GroupID != model.SysGroupID {
|
||||
//最后一条记录和时间和人
|
||||
sql = `
|
||||
SELECT * FROM im_message_record WHERE group_id = ? ORDER BY created_at DESC LIMIT 1
|
||||
`
|
||||
sqlParams = append(sqlParams, v.GroupID)
|
||||
} else {
|
||||
//最后一条记录和时间和人
|
||||
sql = `
|
||||
SELECT * FROM im_message_record WHERE group_id = ? AND to_user_id = ? ORDER BY created_at DESC LIMIT 1
|
||||
`
|
||||
sqlParams = append(sqlParams, v.GroupID, userID)
|
||||
}
|
||||
if err = dao.GetRow(db, &imMessageRecord, sql, sqlParams); err == nil {
|
||||
v.LastTime = imMessageRecord.CreatedAt
|
||||
v.LastContent = imMessageRecord.Content
|
||||
v.LastMessageType = imMessageRecord.MessageType
|
||||
if user3, err := dao.GetUserByID(db, "user_id", imMessageRecord.UserID); err == nil {
|
||||
v.LastUserName = user3.Name
|
||||
}
|
||||
} else {
|
||||
err = nil
|
||||
}
|
||||
//该用户各组的未读消息数
|
||||
var unReadCount int
|
||||
if messageGroupReads, err := dao.GetMessageGroupRead(db, userID, v.GroupID); err == nil && len(messageGroupReads) > 0 {
|
||||
for _, vv := range messageGroupReads {
|
||||
unReadCount += vv.UnReadCount
|
||||
}
|
||||
}
|
||||
v.UnReadMessageCount = unReadCount
|
||||
}
|
||||
return messageGroups, err
|
||||
}
|
||||
|
||||
func AddMessageGroup(ctx *jxcontext.Context, groupID int, userID string) (err error) {
|
||||
var (
|
||||
db = dao.GetDB()
|
||||
)
|
||||
messageGroupMembers, err := dao.GetMessageGroupMembers(db, groupID, 0, userID)
|
||||
messageGroupMembers3, err := dao.GetMessageGroupMembers(db, 0, 0, userID)
|
||||
messageGroupsResult, err := dao.GetMessageGroups(db, userID, groupID, model.GroupTypeMulit, false, "")
|
||||
messageGroupsResult2, err := dao.GetMessageGroups(db, "", groupID, model.GroupTypeMulit, false, "")
|
||||
messageGroupsResult3, err := dao.GetMessageGroups(db, userID, 0, model.GroupTypeMulit, false, "")
|
||||
messageGroupMembers2, err := dao.GetMessageGroupMembers(db, groupID, 0, "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(messageGroupMembers) > 0 {
|
||||
return fmt.Errorf("此用户已经在该群组中了!")
|
||||
}
|
||||
if len(messageGroupMembers3) > 0 {
|
||||
return fmt.Errorf("您已经有群组[%v]了,不能申请加入其它群!", messageGroupMembers3[0].GroupID)
|
||||
}
|
||||
if len(messageGroupsResult) > 0 {
|
||||
return fmt.Errorf("请不要加入自己创建的群!")
|
||||
}
|
||||
if len(messageGroupsResult2) > 0 && len(messageGroupMembers2) > 0 {
|
||||
if len(messageGroupMembers2)+1 > messageGroupsResult2[0].MaxCount {
|
||||
return fmt.Errorf("抱歉该群组已经满员了!")
|
||||
}
|
||||
}
|
||||
if len(messageGroupsResult3) > 0 {
|
||||
return fmt.Errorf("您已经拥有[%v]群了,不能再加入其它群!", messageGroupsResult3[0].GroupID)
|
||||
}
|
||||
|
||||
messageGroupMember := &model.MessageGroupMember{
|
||||
GroupID: groupID,
|
||||
MemberUserID: userID,
|
||||
Type: model.GroupMemberTypeNormal,
|
||||
}
|
||||
dao.WrapAddIDCULDEntity(messageGroupMember, ctx.GetUserName())
|
||||
if err = dao.CreateEntity(db, messageGroupMember); err == nil {
|
||||
messageGroupRead := &model.MessageGroupRead{
|
||||
GroupID: groupID,
|
||||
UserID: userID,
|
||||
}
|
||||
dao.WrapAddIDCULEntity(messageGroupRead, ctx.GetUserName())
|
||||
if err = dao.CreateEntity(db, messageGroupRead); err == nil {
|
||||
if messageGroupReads, err := dao.GetMessageGroupRead(db, userID, model.SysGroupID); len(messageGroupReads) == 0 && err == nil {
|
||||
messageGroupRead := &model.MessageGroupRead{
|
||||
GroupID: model.SysGroupID,
|
||||
UserID: userID,
|
||||
}
|
||||
dao.WrapAddIDCULEntity(messageGroupRead, ctx.GetUserName())
|
||||
dao.CreateEntity(db, messageGroupRead)
|
||||
}
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func UpdateMessageGroup(ctx *jxcontext.Context, groupID int, payload map[string]interface{}) (num int64, err error) {
|
||||
var (
|
||||
db = dao.GetDB()
|
||||
messageGroup = &model.MessageGroup{
|
||||
GroupID: groupID,
|
||||
}
|
||||
)
|
||||
if err = dao.GetEntity(db, messageGroup, "GroupID"); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if messageGroup.UserID != ctx.GetUserID() {
|
||||
return 0, fmt.Errorf("只有群主才能修改群信息!")
|
||||
}
|
||||
valid := dao.StrictMakeMapByStructObject(payload, messageGroup, ctx.GetUserName())
|
||||
if len(valid) > 0 {
|
||||
txDB, _ := dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
dao.Rollback(db, txDB)
|
||||
panic(r)
|
||||
}
|
||||
}()
|
||||
if num, err = dao.UpdateEntityLogically(db, messageGroup, valid, ctx.GetUserName(), nil); err != nil {
|
||||
dao.Rollback(db, txDB)
|
||||
return 0, err
|
||||
}
|
||||
dao.Commit(db, txDB)
|
||||
}
|
||||
return num, err
|
||||
}
|
||||
|
||||
func DeleteMessageGroup(ctx *jxcontext.Context, groupID int, userID string, flag bool) (errCode string, err error) {
|
||||
var (
|
||||
db = dao.GetDB()
|
||||
messageGroup = &model.MessageGroup{
|
||||
GroupID: groupID,
|
||||
}
|
||||
)
|
||||
if err = dao.GetEntity(db, messageGroup, "GroupID"); err != nil {
|
||||
return errCode, err
|
||||
}
|
||||
//解散群
|
||||
if flag {
|
||||
if messageGroup.UserID != ctx.GetUserID() {
|
||||
return errCode, fmt.Errorf("只有群主才能解散群!")
|
||||
}
|
||||
messageGroup.DeletedAt = time.Now()
|
||||
messageGroup.LastOperator = ctx.GetUserName()
|
||||
dao.UpdateEntity(db, messageGroup, "DeletedAt", "LastOperator")
|
||||
messageGroupMembers, _ := dao.GetMessageGroupMembers(db, groupID, 0, "")
|
||||
for _, v := range messageGroupMembers {
|
||||
v.DeletedAt = time.Now()
|
||||
v.LastOperator = ctx.GetUserName()
|
||||
dao.UpdateEntity(db, v, "DeletedAt", "LastOperator")
|
||||
}
|
||||
} else {
|
||||
//token中用户与传入user不一致就判定为踢人
|
||||
if ctx.GetUserID() != userID {
|
||||
if messageGroup.UserID != ctx.GetUserID() {
|
||||
messageGroupMembers, err := dao.GetMessageGroupMembers(db, groupID, 0, ctx.GetUserID())
|
||||
if err != nil {
|
||||
return errCode, err
|
||||
}
|
||||
if messageGroupMembers[0].Type == model.GroupMemberTypeNormal {
|
||||
return errCode, fmt.Errorf("只有创建者和管理员才能踢人!")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
quitPrice := messageGroup.QuitPrice
|
||||
userBill, err := dao.GetUserBill(db, userID, "")
|
||||
userBillGroupMaster, err := dao.GetUserBill(db, messageGroup.UserID, "")
|
||||
if err != nil {
|
||||
return errCode, err
|
||||
}
|
||||
if userBill.AccountBalance < quitPrice {
|
||||
return model.ErrCodeAccountBalanceNotEnough, fmt.Errorf("用户余额不足,请充值!")
|
||||
}
|
||||
txDB, _ := dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
dao.Rollback(db, txDB)
|
||||
panic(r)
|
||||
}
|
||||
}()
|
||||
//账户支出
|
||||
if err = financial.AddExpendUpdateAccount(txDB, userBill, model.BillTypeQuitGroup, quitPrice, 0); err != nil {
|
||||
dao.Rollback(db, txDB)
|
||||
return errCode, err
|
||||
}
|
||||
//群主收到退团金额
|
||||
if err = financial.AddIncomeUpdateAccount(txDB, userBillGroupMaster, model.BillTypeQuitGroup, quitPrice, 0); err != nil {
|
||||
dao.Rollback(db, txDB)
|
||||
return errCode, err
|
||||
}
|
||||
dao.Commit(db, txDB)
|
||||
}
|
||||
messageGroupMembers, err := dao.GetMessageGroupMembers(db, groupID, 0, userID)
|
||||
if err != nil {
|
||||
return errCode, err
|
||||
}
|
||||
messageGroupMembers[0].DeletedAt = time.Now()
|
||||
messageGroupMembers[0].LastOperator = ctx.GetUserName()
|
||||
dao.UpdateEntity(db, messageGroupMembers[0], "DeletedAt", "LastOperator")
|
||||
}
|
||||
return errCode, err
|
||||
}
|
||||
|
||||
func TransferMessageGroupMaster(ctx *jxcontext.Context, groupID int, userID string) (err error) {
|
||||
var (
|
||||
db = dao.GetDB()
|
||||
messageGroup = &model.MessageGroup{
|
||||
GroupID: groupID,
|
||||
}
|
||||
)
|
||||
if err = dao.GetEntity(db, messageGroup, "GroupID"); err != nil {
|
||||
return err
|
||||
}
|
||||
if messageGroup.UserID != ctx.GetUserID() {
|
||||
return fmt.Errorf("只有群主才能转让群主!")
|
||||
}
|
||||
//群主换成选的那个人
|
||||
messageGroup.UserID = userID
|
||||
messageGroup.LastOperator = ctx.GetUserName()
|
||||
//之前那个群成员换成之前的群主
|
||||
messageGroupMembers, err := dao.GetMessageGroupMembers(db, groupID, 0, userID)
|
||||
if err != nil && len(messageGroupMembers) == 0 {
|
||||
return err
|
||||
}
|
||||
messageGroupMember := messageGroupMembers[0]
|
||||
messageGroupMember.MemberUserID = ctx.GetUserID()
|
||||
messageGroupMember.LastOperator = ctx.GetUserName()
|
||||
txDB, _ := dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
dao.Rollback(db, txDB)
|
||||
panic(r)
|
||||
}
|
||||
}()
|
||||
if _, err = dao.UpdateEntity(db, messageGroup, "UserID", "LastOperator"); err != nil {
|
||||
dao.Rollback(db, txDB)
|
||||
return err
|
||||
}
|
||||
if _, err = dao.UpdateEntity(db, messageGroupMember, "MemberUserID", "LastOperator"); err != nil {
|
||||
dao.Rollback(db, txDB)
|
||||
return err
|
||||
}
|
||||
dao.Commit(db, txDB)
|
||||
return err
|
||||
}
|
||||
|
||||
func SendSysMessageSimple(content, toUserID string) (err error) {
|
||||
return SendSysMessage(jxcontext.AdminCtx, &model.ImMessageRecord{
|
||||
Content: sysMessageTitle + " " + content,
|
||||
ToUserID: toUserID,
|
||||
GroupID: model.SysGroupID,
|
||||
MessageType: 1, // 普通文字消息
|
||||
})
|
||||
}
|
||||
|
||||
func SendSysMessage(ctx *jxcontext.Context, imMessageRecord *model.ImMessageRecord) (err error) {
|
||||
var (
|
||||
db = dao.GetDB()
|
||||
userID = imMessageRecord.ToUserID
|
||||
groupID = imMessageRecord.GroupID
|
||||
)
|
||||
if groupID != model.SysGroupID {
|
||||
return fmt.Errorf("只能给系统组发消息!")
|
||||
}
|
||||
imMessageRecord.CreatedAt = time.Now()
|
||||
imMessageRecord.LastOperator = ctx.GetUserName()
|
||||
imMessageRecord.DeletedAt = utils.DefaultTimeValue
|
||||
imMessageRecord.UpdatedAt = utils.DefaultTimeValue
|
||||
imMessageRecord.Seq = time.Now().Unix()
|
||||
err = dao.CreateEntity(db, imMessageRecord)
|
||||
if userID == "" {
|
||||
//循环map客户端
|
||||
for _, client := range wsClient.Clients[groupID] {
|
||||
globals.SugarLogger.Debugf("msg %v", utils.Format4Output(imMessageRecord, false))
|
||||
err = client.WriteJSON(imMessageRecord)
|
||||
if err != nil {
|
||||
globals.SugarLogger.Debugf("client.WriteJSON error: %v", err)
|
||||
client.Close() //关闭
|
||||
// delete(wsClient.Clients[msg.GroupID], userID)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
client := wsClient.Clients[groupID][userID]
|
||||
globals.SugarLogger.Debugf("msg %v", utils.Format4Output(imMessageRecord, false))
|
||||
if client == nil {
|
||||
return
|
||||
}
|
||||
err = client.WriteJSON(imMessageRecord)
|
||||
if err != nil {
|
||||
globals.SugarLogger.Debugf("client.WriteJSON error: %v", err)
|
||||
client.Close() //关闭
|
||||
// delete(wsClient.Clients[msg.GroupID], userID)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func DeleteMessageRecord(ctx *jxcontext.Context) (err error) {
|
||||
var (
|
||||
db = dao.GetDB()
|
||||
)
|
||||
sql := `
|
||||
DELETE FROM im_message_record WHERE created_at < ? AND group_id <> ?
|
||||
`
|
||||
sqlParams := []interface{}{
|
||||
time.Now().AddDate(0, 0, -3), model.SysGroupID,
|
||||
}
|
||||
_, err = dao.ExecuteSQL(db, sql, sqlParams)
|
||||
return err
|
||||
}
|
||||
|
||||
func UpdateUserMessageGroupRead(ctx *jxcontext.Context, reads []*model.MessageGroupRead) (err error) {
|
||||
var (
|
||||
db = dao.GetDB()
|
||||
userID = ctx.GetUserID()
|
||||
)
|
||||
for _, v := range reads {
|
||||
if messageReads, err := dao.GetMessageGroupRead(db, userID, v.GroupID); err == nil {
|
||||
if len(messageReads) > 0 {
|
||||
messageReads[0].UnReadCount += v.UnReadCount
|
||||
dao.UpdateEntity(db, messageReads[0], "UnReadCount")
|
||||
} else {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
type GetUserStatisticsResult struct {
|
||||
RegisterUserCount int `json:"registerUserCount"` //注册数
|
||||
OnlineUserCount int `json:"onlineUserCount"` //在线用户数
|
||||
ConsumeUserCount int `json:"consumeUserCount"` //消费用户数
|
||||
MemberUserCount int `json:"memberUserCount"` //会员用户数
|
||||
}
|
||||
|
||||
func GetUserStatistics(ctx *jxcontext.Context) (getUserStatisticsResult *GetUserStatisticsResult, err error) {
|
||||
var (
|
||||
db = dao.GetDB()
|
||||
)
|
||||
getUserStatisticsResult = &GetUserStatisticsResult{}
|
||||
sql := `
|
||||
SELECT a.member_user_count, b.consume_user_count FROM
|
||||
( SELECT DISTINCT COUNT(a.user_id) member_user_count
|
||||
FROM user a
|
||||
JOIN user_member b ON a.user_id = b.user_id AND b.deleted_at = ? )a,
|
||||
( SELECT DISTINCT COUNT(a.user_id) consume_user_count
|
||||
FROM user a
|
||||
JOIN ` + "`order`" + `b ON a.user_id = b.user_id AND b.status = ?)b
|
||||
`
|
||||
sqlParams := []interface{}{
|
||||
utils.DefaultTimeValue, model.OrderStatusFinished,
|
||||
}
|
||||
err = dao.GetRow(db, &getUserStatisticsResult, sql, sqlParams)
|
||||
paged, _ := dao.GetUsers2(db, "", "", 0, "", utils.ZeroTimeValue, utils.ZeroTimeValue, 0, nil, nil, 0, -1)
|
||||
getUserStatisticsResult.RegisterUserCount = paged.TotalCount
|
||||
getUserStatisticsResult.OnlineUserCount = GetOnlineUserCount()
|
||||
return getUserStatisticsResult, err
|
||||
}
|
||||
|
||||
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()
|
||||
Pool.Wait()
|
||||
Pool.Stop()
|
||||
return
|
||||
}
|
||||
}
|
||||
Pool.AddJob(fn)
|
||||
}
|
||||
}
|
||||
|
||||
func handleConn(c net.Conn) error {
|
||||
if c == nil {
|
||||
return errors.New("conn is nil")
|
||||
}
|
||||
for {
|
||||
buffer, n, err := ConnRead(c)
|
||||
printRemoteAddr := c.RemoteAddr().String()
|
||||
printRemoteAddr = strings.Split(printRemoteAddr, ":")[0]
|
||||
printNoByIP, _ := PrintAddrAndIp.GetPrintAddrAndIp(printRemoteAddr)
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
fmt.Println("connection close")
|
||||
} else {
|
||||
fmt.Println("ReadString err:", err)
|
||||
}
|
||||
globals.SugarLogger.Debugf("--------printRemoteAddr := %s,printNo := %s", printRemoteAddr, printNoByIP)
|
||||
if printNo, ok := PrintAddrAndIp.GetPrintAddrAndIp(printRemoteAddr); ok {
|
||||
PrintAddrAndIp.DelPrintAddrAndIp(printRemoteAddr)
|
||||
PrintObject.DelPrintObj(printNo)
|
||||
PrintIpAndAddr.DelPrintIpAndAddr(printRemoteAddr)
|
||||
dao.ExecuteSQL(dao.GetDB(), `UPDATE printer SET status = -1,is_online = -1 WHERE print_no = ? `, []interface{}{printNo}...)
|
||||
} else {
|
||||
printStatusOff := make(map[string]int, 0)
|
||||
for ip, pn := range PrintAddrAndIp.PrintObject {
|
||||
if ip == printRemoteAddr {
|
||||
PrintAddrAndIp.DelPrintAddrAndIp(printRemoteAddr)
|
||||
PrintIpAndAddr.DelPrintIpAndAddr(pn)
|
||||
PrintObject.DelPrintObj(printNo)
|
||||
} else if pn != "" {
|
||||
printStatusOff[pn] = 1
|
||||
}
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
//看是心跳还是打印回调
|
||||
data := hex.EncodeToString(buffer[:n])
|
||||
var (
|
||||
printNo string = "" //打印机编号
|
||||
heartbeat bool = false
|
||||
callback bool = false
|
||||
)
|
||||
if strings.Contains(data, heartText) || strings.Contains(data, heartTextNew) {
|
||||
printNoData, _ := hex.DecodeString(data[len(heartText) : len(data)-8])
|
||||
printNo = string(printNoData)
|
||||
heartbeat = true
|
||||
} else if strings.Contains(data, printText) || strings.Contains(data, printTextNew) { //打印回调
|
||||
_, printNo = getCallbackMsgInfo(data)
|
||||
callback = true
|
||||
}
|
||||
|
||||
t, ok := PrintObject.GetPrintObj(printNo)
|
||||
if !ok || t.Clients[printNo] == nil || time.Now().Sub(t.Clients[printNo].StatusTime).Seconds() >= 120 {
|
||||
t = NewTcpClient()
|
||||
}
|
||||
|
||||
if heartbeat {
|
||||
// 证明是心跳
|
||||
Heartbeat(c, t, data, printNo, printRemoteAddr)
|
||||
} else if callback {
|
||||
// 打印回调
|
||||
Callback(c, t, data, printNo)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (t *TcpClient) printFail() (err error) {
|
||||
//新开机的打印失败和错误的
|
||||
var (
|
||||
db = dao.GetDB()
|
||||
)
|
||||
prints, _ := dao.GetPrintMsgs(db, "", []int{printMsgFail, printMsgErr, PrintMsgAlreadyLoad, printMsgAlreadySend}, time.Now().Add(-time.Hour*3), time.Now(), 0, 999)
|
||||
for _, printMsg := range prints {
|
||||
t.addMsgChan(printMsg)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (t *TcpClient) changePrintMsg(data string, orderNo int64, printNo string) (err error) {
|
||||
var (
|
||||
db = dao.GetDB()
|
||||
comment string
|
||||
status int
|
||||
)
|
||||
//1、先找出打印机编号和订单序列号,这两个确定唯一一条消息?
|
||||
//通过参数传进来
|
||||
//2、打印成功改变打印表的状态
|
||||
if strings.Contains(data, printSuccessText) || strings.Contains(data, printSuccessTextNew) {
|
||||
status = printMsgSuccess
|
||||
comment = "回调成功,修改打印状态"
|
||||
} else {
|
||||
//打印失败也改变状态并更新失败原因
|
||||
status = printMsgFail
|
||||
comment = printErrMap[data[12:14]]
|
||||
}
|
||||
//这里序号重复会有问题
|
||||
if printMsgs, err := dao.GetPrintMsgNoPage(db, printNo, orderNo); err != nil {
|
||||
globals.SugarLogger.Debugf("changePrintMsg err :[%v]", err)
|
||||
return err
|
||||
} else if len(printMsgs) == 0 {
|
||||
globals.SugarLogger.Debugf("changePrintMsg err ,not found printMsg printNo:[%v], orderNo :[%v]", printNo, orderNo)
|
||||
} else if len(printMsgs) > 0 {
|
||||
for _, v := range printMsgs {
|
||||
v.Comment = comment
|
||||
v.Status = status
|
||||
dao.UpdateEntity(db, v, "Comment", "Status")
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func HandleTcpMessages(t *TcpClient, printNo string) {
|
||||
var (
|
||||
db = dao.GetDB()
|
||||
offset, pageSize = 0, 10
|
||||
)
|
||||
if !t.isExistMsg(printNo) {
|
||||
return
|
||||
}
|
||||
|
||||
fn := func() {
|
||||
//for {
|
||||
// time.Sleep(2 * time.Second)
|
||||
if t.TimeoutMap[printNo] == true {
|
||||
timeNow := time.Now()
|
||||
timeStart := time.Date(timeNow.Year(), timeNow.Month(), timeNow.Day(), 0, 0, 0, 0, timeNow.Location())
|
||||
timeEnd := time.Date(timeNow.Year(), timeNow.Month(), timeNow.Day(), 23, 59, 59, 0, timeNow.Location())
|
||||
prints, _ := dao.GetPrintMsgs(db, printNo, []int{PrintMsgWait}, timeStart.AddDate(0, 0, -1), timeEnd, offset, pageSize)
|
||||
for _, printMsg := range prints {
|
||||
printMsg.Status = PrintMsgAlreadyLoad
|
||||
//先避免重复读再插到channel?
|
||||
if _, err := dao.UpdateEntity(db, printMsg, "Status"); err == nil {
|
||||
if err = t.addMsgChan(printMsg); err != nil {
|
||||
globals.SugarLogger.Debugf("HandleTcpMessages addMsgChan Err: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
globals.SugarLogger.Debugf("HandleTcpMessages timeout")
|
||||
return
|
||||
}
|
||||
}
|
||||
Pool.AddJob(fn)
|
||||
}
|
||||
|
||||
func (t *TcpClient) readTimeoutMap(key string) bool {
|
||||
t.Lock()
|
||||
defer t.Unlock()
|
||||
return t.TimeoutMap[key]
|
||||
}
|
||||
|
||||
func doPrint(t *TcpClient, key string) (err error) {
|
||||
var (
|
||||
db = dao.GetDB()
|
||||
)
|
||||
|
||||
if !t.isExistMsg(key) {
|
||||
return err
|
||||
}
|
||||
|
||||
fn := func() {
|
||||
for {
|
||||
if t.TimeoutMap[key] == true {
|
||||
select {
|
||||
case printMsg, ok := <-t.MsgMap[key]:
|
||||
if !ok {
|
||||
globals.SugarLogger.Debugf("doPrint err !ok ...")
|
||||
return
|
||||
}
|
||||
var (
|
||||
data []byte
|
||||
c net.Conn
|
||||
)
|
||||
if printMsg == nil {
|
||||
globals.SugarLogger.Debugf("print msg is nil")
|
||||
continue
|
||||
}
|
||||
|
||||
if err = checkPrintMsg(db, printMsg); err == nil {
|
||||
status := t.getPrintStatus(printMsg.PrintNo)
|
||||
switch status {
|
||||
//只有在线才打印内容
|
||||
case printerStatusOnline:
|
||||
if c = t.getPrintConn(printMsg.PrintNo); c != nil {
|
||||
data, err = buildMsg(printMsg)
|
||||
}
|
||||
case printerStatusOffline:
|
||||
err = fmt.Errorf("打印机离线!")
|
||||
case printerStatusOnlineWithoutPaper:
|
||||
err = fmt.Errorf("打印机缺纸!")
|
||||
default:
|
||||
err = fmt.Errorf("打印机状态未知!")
|
||||
}
|
||||
}
|
||||
|
||||
if c == nil {
|
||||
if printRemoteAddrIP, have := PrintIpAndAddr.GetPrintIpAndAddr(key); have {
|
||||
PrintIpAndAddr.DelPrintIpAndAddr(key)
|
||||
PrintAddrAndIp.DelPrintAddrAndIp(printRemoteAddrIP)
|
||||
PrintObject.DelPrintObj(key)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
printMsg.Status = printMsgErr
|
||||
printMsg.Comment = err.Error()
|
||||
dao.UpdateEntity(db, printMsg, "Status", "Comment")
|
||||
|
||||
if printRemoteAddrIP, have := PrintIpAndAddr.GetPrintIpAndAddr(key); have {
|
||||
PrintIpAndAddr.DelPrintIpAndAddr(key)
|
||||
PrintAddrAndIp.DelPrintAddrAndIp(printRemoteAddrIP)
|
||||
PrintObject.DelPrintObj(key)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if _, err = c.Write(data); err != nil {
|
||||
globals.SugarLogger.Debugf("handleTcpMessages err [%v]", err)
|
||||
if printRemoteAddrIP, have := PrintIpAndAddr.GetPrintIpAndAddr(key); have {
|
||||
PrintIpAndAddr.DelPrintIpAndAddr(key)
|
||||
PrintAddrAndIp.DelPrintAddrAndIp(printRemoteAddrIP)
|
||||
PrintObject.DelPrintObj(key)
|
||||
}
|
||||
|
||||
} else {
|
||||
//等待回调
|
||||
dataStr := <-t.CallBackMap[key]
|
||||
if dataStr != "" {
|
||||
a, b := getCallbackMsgInfo(dataStr)
|
||||
t.changePrintMsg(dataStr, a, b)
|
||||
// 查询打印机是否扣费,未扣费就扣费,已经扣费不做处理
|
||||
have, err2 := dao.QueryOrderDeductionRecord(db, b, utils.Int64ToStr(a))
|
||||
if err2 == nil && !have {
|
||||
// 扣除打印机账号金额
|
||||
if err = dao.DeductionPrintBalance(db, b); err != nil {
|
||||
globals.SugarLogger.Debugf("扣除用户打印机金额错误 %s", err)
|
||||
} else {
|
||||
// 添加打印记录(支出记录)
|
||||
if err = dao.AddPrintRecord(db, &model.PrintBillRecord{
|
||||
CreatedAt: time.Now(),
|
||||
UpdatedAt: time.Now(),
|
||||
PrintNo: b,
|
||||
PayType: 2,
|
||||
PayMoney: 1, // 固定支出一分钱
|
||||
OrderId: utils.Int64ToStr(a),
|
||||
UserId: "",
|
||||
}); err != nil {
|
||||
globals.SugarLogger.Debugf("添加打印机订单支付记录错误 %s", err)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
globals.SugarLogger.Debugf("今天已经扣除过了! %v %d %s", err2, a, b)
|
||||
}
|
||||
// 回调重置打印机状态时间
|
||||
t.Clients[b].StatusTime = time.Now()
|
||||
//判断音频暂停?
|
||||
//收到打印成功回调后,如果消息中有音频,需要等待一下,等上一个音频播完
|
||||
//暂停时间就暂时取的sound标签内内容长度/2
|
||||
if sounds := regexpSoundSpan.FindStringSubmatch(printMsg.Content); len(sounds) > 0 {
|
||||
sound := sounds[1]
|
||||
lenTime := time.Duration(utf8.RuneCountInString(sound)) * time.Second
|
||||
time.Sleep(lenTime / 2)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
globals.SugarLogger.Debugf("doPrint timeout")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
Pool.AddJob(fn)
|
||||
return err
|
||||
}
|
||||
|
||||
// HandleCheckTcpHeart 检测心跳
|
||||
func HandleCheckTcpHeart(t *TcpClient, key string) {
|
||||
if t.TimeoutMap[key] == true {
|
||||
statusTime := t.getPrintStatusTime(key)
|
||||
if !utils.IsTimeZero(statusTime) {
|
||||
//1分钟内没心跳判断打印机掉线了
|
||||
if time.Now().Sub(statusTime) > time.Second*75 {
|
||||
globals.SugarLogger.Debugf("超过一分十秒没有心跳的打印机[%s],当前心跳时间: %s ,上一次心跳时间 : %s", key, utils.Time2TimeStr(time.Now()), utils.Time2TimeStr(statusTime))
|
||||
changePrinterStatus(key, printerStatusOffline)
|
||||
|
||||
// 链接出错,彻底删除换成
|
||||
if printRemoteAddrIP, have := PrintIpAndAddr.GetPrintIpAndAddr(key); have {
|
||||
PrintIpAndAddr.DelPrintIpAndAddr(key)
|
||||
PrintAddrAndIp.DelPrintAddrAndIp(printRemoteAddrIP)
|
||||
PrintObject.DelPrintObj(key)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
} else {
|
||||
t.getClients(key).C.Close()
|
||||
close(t.MsgMap[key])
|
||||
close(t.CallBackMap[key])
|
||||
//t.delConn(key)
|
||||
t.clear(key)
|
||||
|
||||
// 链接出错,彻底删除换成
|
||||
if printRemoteAddrIP, have := PrintIpAndAddr.GetPrintIpAndAddr(key); have {
|
||||
PrintIpAndAddr.DelPrintIpAndAddr(key)
|
||||
PrintAddrAndIp.DelPrintAddrAndIp(printRemoteAddrIP)
|
||||
PrintObject.DelPrintObj(key)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
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)
|
||||
}
|
||||
157
business/jxstore/event/timing_task.go
Normal file
157
business/jxstore/event/timing_task.go
Normal file
@@ -0,0 +1,157 @@
|
||||
package event
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 全局单例线程池(初始化500个worker)
|
||||
var Pool *WorkerPool
|
||||
|
||||
func init() {
|
||||
Pool = NewWorkerPool(500, 1024) // 500个worker,任务队列长度1024
|
||||
Pool.Start()
|
||||
}
|
||||
|
||||
// Job 任务定义
|
||||
type Job func()
|
||||
|
||||
// Worker 工作协程
|
||||
type Worker struct {
|
||||
id int
|
||||
jobChan chan Job
|
||||
quitChan chan struct{}
|
||||
closeOnce sync.Once
|
||||
}
|
||||
|
||||
// WorkerPool 线程池
|
||||
type WorkerPool struct {
|
||||
workers []*Worker
|
||||
jobChan chan Job
|
||||
wg sync.WaitGroup
|
||||
closeOnce sync.Once
|
||||
closed bool
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
// ----------------------------------------------------
|
||||
// 创建 Worker
|
||||
// ----------------------------------------------------
|
||||
func NewWorker(id int, jobChan chan Job) *Worker {
|
||||
return &Worker{
|
||||
id: id,
|
||||
jobChan: jobChan,
|
||||
quitChan: make(chan struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
// Start 启动Worker(自带panic恢复)
|
||||
func (w *Worker) Start() {
|
||||
go func() {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
// 打印panic日志,防止整个worker崩溃
|
||||
// log.Printf("worker %d panic recovered: %v", w.id, r)
|
||||
}
|
||||
}()
|
||||
|
||||
for {
|
||||
select {
|
||||
case job, ok := <-w.jobChan:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
job()
|
||||
case <-w.quitChan:
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// Stop 安全停止Worker
|
||||
func (w *Worker) Stop() {
|
||||
w.closeOnce.Do(func() {
|
||||
close(w.quitChan)
|
||||
})
|
||||
}
|
||||
|
||||
// ----------------------------------------------------
|
||||
// 创建线程池
|
||||
// ----------------------------------------------------
|
||||
func NewWorkerPool(workerCount int, queueSize int) *WorkerPool {
|
||||
jobChan := make(chan Job, queueSize) // 带缓冲队列,高并发不阻塞
|
||||
|
||||
pool := &WorkerPool{
|
||||
workers: make([]*Worker, workerCount),
|
||||
jobChan: jobChan,
|
||||
}
|
||||
|
||||
for i := 0; i < workerCount; i++ {
|
||||
pool.workers[i] = NewWorker(i, jobChan)
|
||||
}
|
||||
return pool
|
||||
}
|
||||
|
||||
// Start 启动所有worker
|
||||
func (p *WorkerPool) Start() {
|
||||
for _, w := range p.workers {
|
||||
w.Start()
|
||||
}
|
||||
}
|
||||
|
||||
// AddJob 提交任务(非阻塞、安全、不panic)
|
||||
func (p *WorkerPool) AddJob(job Job) bool {
|
||||
p.mu.Lock()
|
||||
closed := p.closed
|
||||
p.mu.Unlock()
|
||||
|
||||
if closed {
|
||||
return false
|
||||
}
|
||||
|
||||
p.wg.Add(1)
|
||||
select {
|
||||
case p.jobChan <- func() {
|
||||
defer p.wg.Done()
|
||||
job()
|
||||
}:
|
||||
return true
|
||||
case <-time.After(10 * time.Millisecond):
|
||||
// 队列满了,不阻塞,快速失败
|
||||
p.wg.Done()
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// Wait 等待所有任务执行完成
|
||||
func (p *WorkerPool) Wait() {
|
||||
p.wg.Wait()
|
||||
}
|
||||
|
||||
// Stop 优雅关闭线程池(安全不panic)
|
||||
func (p *WorkerPool) Stop() {
|
||||
p.closeOnce.Do(func() {
|
||||
p.mu.Lock()
|
||||
p.closed = true
|
||||
p.mu.Unlock()
|
||||
|
||||
// 1. 关闭任务通道
|
||||
close(p.jobChan)
|
||||
|
||||
// 2. 停止所有worker
|
||||
for _, w := range p.workers {
|
||||
w.Stop()
|
||||
}
|
||||
|
||||
// 3. 等待所有任务执行完
|
||||
p.Wait()
|
||||
})
|
||||
}
|
||||
|
||||
// IsClosed 判断线程池是否关闭
|
||||
func (p *WorkerPool) IsClosed() bool {
|
||||
p.mu.Lock()
|
||||
defer p.mu.Unlock()
|
||||
return p.closed
|
||||
}
|
||||
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,122 +1,410 @@
|
||||
package financial
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"crypto/hmac"
|
||||
"crypto/md5"
|
||||
"crypto/sha256"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"mime/multipart"
|
||||
"path"
|
||||
"github.com/astaxie/beego/client/orm"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/tonglianpayapi"
|
||||
"git.rosy.net.cn/baseapi/platformapi/wxpayapi"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/weixinmsg"
|
||||
"git.rosy.net.cn/jx-callback/business/auth2/authprovider/weixin"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/model/legacymodel"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
"github.com/qiniu/api.v7/storage"
|
||||
)
|
||||
|
||||
type tUploadFileInfo struct {
|
||||
FileHeader *multipart.FileHeader
|
||||
StoreID int
|
||||
const (
|
||||
sigKey = "sign"
|
||||
sigTypeMd5 = "MD5"
|
||||
sigTypeSha256 = "HMAC-SHA256"
|
||||
)
|
||||
|
||||
var (
|
||||
payMap = map[string]*wxpayapi.API{
|
||||
"weixinapp": api.WxpayAPI,
|
||||
"weixinmini": api.WxpayAPI2,
|
||||
}
|
||||
)
|
||||
|
||||
func (p *PayHandler) CreatePay(txDB orm.TxOrmer, subAppID string) (err error) {
|
||||
switch p.PayType {
|
||||
case model.PayTypeTL:
|
||||
param := &tonglianpayapi.CreateUnitorderOrderParam{
|
||||
Trxamt: p.Order.PayPrice,
|
||||
NotifyUrl: globals.TLPayNotifyURL,
|
||||
Reqsn: p.Order.OrderID,
|
||||
PayType: p.VendorPayType,
|
||||
}
|
||||
//暂时做兼容处理
|
||||
if p.VendorPayType == "JSAPI" {
|
||||
param.PayType = tonglianpayapi.PayTypeWxXcx
|
||||
}
|
||||
if p.VendorPayType == tonglianpayapi.PayTypeWxXcx {
|
||||
param.SubAppID = subAppID
|
||||
authInfo, err := p.Ctx.GetV2AuthInfo()
|
||||
// 微信小程序支付
|
||||
if err == nil && authInfo.GetAuthType() == weixin.AuthTypeMini && authInfo.GetAuthTypeID() == subAppID {
|
||||
param.Acct = authInfo.GetAuthID()
|
||||
}
|
||||
}
|
||||
if p.VendorPayType == tonglianpayapi.PayTypeZfbJS || p.VendorPayType == tonglianpayapi.PayTypeZfbApp {
|
||||
if authInfo, err := p.Ctx.GetV2AuthInfo(); err == nil {
|
||||
param.Acct = authInfo.GetAuthID()
|
||||
}
|
||||
if param.Acct == "" {
|
||||
return fmt.Errorf("未找到用户的认证ID!")
|
||||
}
|
||||
}
|
||||
if p.VendorPayType == tonglianpayapi.PayTypeH5 {
|
||||
param2 := &tonglianpayapi.CreateH5UnitorderOrderParam{
|
||||
Trxamt: p.Order.PayPrice,
|
||||
NotifyUrl: globals.TLPayNotifyURL,
|
||||
Body: "冲天猴",
|
||||
Charset: "UTF-8",
|
||||
}
|
||||
err = api.TLpayAPI.CreateH5UnitorderOrder(param2)
|
||||
} else {
|
||||
result, err := api.TLpayAPI.CreateUnitorderOrder(param)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var result2 tonglianpayapi.PayInfo
|
||||
json.Unmarshal([]byte(result.PayInfo), &result2)
|
||||
p.Order.PrepayID = result2.Package[strings.LastIndex(result2.Package, "=")+1 : len(result2.Package)]
|
||||
p.Order.TransactionID = result.TrxID
|
||||
|
||||
if _, err = dao.UpdateEntityTx(txDB, p.Order, "PrepayID", "TransactionID"); err != nil {
|
||||
return err
|
||||
}
|
||||
wxPay := &WxPayParam{
|
||||
Prepayid: p.Order.PrepayID,
|
||||
Noncestr: result2.NonceStr,
|
||||
Timestamp: utils.Int64ToStr(utils.MustInterface2Int64(result2.TimeStamp)),
|
||||
Package: result2.Package,
|
||||
Partnerid: "", // 商户Id
|
||||
Appid: result2.AppID,
|
||||
Sign: result2.PaySign,
|
||||
}
|
||||
p.WxPayParam = wxPay
|
||||
}
|
||||
// 暂时不支持微信直接支付
|
||||
case model.PayTypeWX:
|
||||
param := &wxpayapi.CreateOrderParam{
|
||||
OutTradeNo: p.Order.OrderID,
|
||||
Body: "冲天猴儿App账户充值",
|
||||
NotifyURL: globals.WxpayNotifyURL,
|
||||
SpbillCreateIP: p.Ctx.GetRealRemoteIP(),
|
||||
TradeType: p.VendorPayType,
|
||||
TotalFee: p.Order.PayPrice,
|
||||
TimeStart: wxpayapi.Time2PayTime(time.Now()),
|
||||
// ProfitSharing: wxpayapi.OptYes,
|
||||
}
|
||||
authBinds, err := dao.GetUserBindAuthInfo(dao.GetDB(), p.Ctx.GetUserID(), model.AuthBindTypeAuth, []string{p.Order.Way}, "", "", "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(authBinds) == 0 {
|
||||
return fmt.Errorf("未绑定微信认证方式!")
|
||||
}
|
||||
param.OpenID = authBinds[0].AuthID
|
||||
result, err2 := payMap[p.Order.Way].CreateUnifiedOrder(param)
|
||||
if err2 == nil {
|
||||
param2 := make(map[string]interface{})
|
||||
param2["prepayid"] = result.PrepayID
|
||||
param2["noncestr"] = utils.GetUUID()
|
||||
param2["timestamp"] = time.Now().Unix()
|
||||
param2["package"] = "Sign=WXPay"
|
||||
param2["partnerid"] = result.MchID
|
||||
param2["appid"] = result.AppID
|
||||
sign := signParam(sigTypeMd5, param2)
|
||||
wxPay := &WxPayParam{
|
||||
Prepayid: param2["prepayid"].(string),
|
||||
Noncestr: param2["noncestr"].(string),
|
||||
Timestamp: utils.Int64ToStr(utils.MustInterface2Int64(param2["timestamp"])),
|
||||
Package: param2["package"].(string),
|
||||
Partnerid: param2["partnerid"].(string),
|
||||
Appid: param2["appid"].(string),
|
||||
Sign: sign,
|
||||
}
|
||||
p.WxPayParam = wxPay
|
||||
p.Order.PrepayID = result.PrepayID
|
||||
p.Order.Comment = result.CodeURL
|
||||
_, err = dao.UpdateEntityTx(txDB, p.Order, "PrepayID", "Comment")
|
||||
} else {
|
||||
return err2
|
||||
}
|
||||
default:
|
||||
err = fmt.Errorf("支付方式:%d当前不支持", p.PayType)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func SendFilesToStores(ctx *jxcontext.Context, files []*multipart.FileHeader, title, shopName string, isAsync bool, userName string) (hint string, err error) {
|
||||
if len(files) == 0 {
|
||||
return "", errors.New("没有文件上传!")
|
||||
}
|
||||
|
||||
fileList := make([]*tUploadFileInfo, len(files))
|
||||
for k, fileHeader := range files {
|
||||
fileList[k] = &tUploadFileInfo{
|
||||
FileHeader: fileHeader,
|
||||
}
|
||||
fileNameParts := strings.Split(fileHeader.Filename, "_")
|
||||
if len(fileNameParts) < 3 {
|
||||
return "", fmt.Errorf("文件名:%s不规范,没有包含三个必要的部分", fileHeader.Filename)
|
||||
}
|
||||
fileList[k].StoreID = int(utils.Str2Int64WithDefault(fileNameParts[0], 0))
|
||||
// 果园和菜市账号冲突,果园门店ID调整变大
|
||||
//if fileList[k].StoreID < 100000 || fileList[k].StoreID > 1000000 {
|
||||
// return "", fmt.Errorf("文件名:%s不规范,不以合法的京西门店ID开始", fileHeader.Filename)
|
||||
//}
|
||||
}
|
||||
putPolicy := storage.PutPolicy{
|
||||
Scope: globals.QiniuBucket,
|
||||
Expires: 10 * 60,
|
||||
}
|
||||
upToken := putPolicy.UploadToken(api.QiniuAPI)
|
||||
cfg := &storage.Config{}
|
||||
task := tasksch.NewParallelTask("SendFilesToStores", tasksch.NewParallelConfig().SetIsContinueWhenError(true), ctx,
|
||||
func(t *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
fileInfo := batchItemList[0].(*tUploadFileInfo)
|
||||
fileHeader := fileInfo.FileHeader
|
||||
db := dao.GetDB()
|
||||
storeID, _ := dao.GetRealLinkStoreID(db, fileInfo.StoreID)
|
||||
storeDetail, _ := dao.GetStoreDetail(db, storeID, 0, "")
|
||||
if storeDetail != nil && storeDetail.PushBill == 1 {
|
||||
return retVal, err
|
||||
func signParam(signType string, params map[string]interface{}) (sig string) {
|
||||
var valueList []string
|
||||
for k, v := range params {
|
||||
if k != sigKey {
|
||||
if str := fmt.Sprint(v); str != "" {
|
||||
valueList = append(valueList, fmt.Sprintf("%s=%s", k, str))
|
||||
}
|
||||
file, err := fileHeader.Open()
|
||||
if err == nil {
|
||||
ret := storage.PutRet{}
|
||||
key := "storeBill/" + utils.Int2Str(storeID) + "_" + strings.ToLower(utils.GetUUID()) + path.Ext(fileHeader.Filename)
|
||||
formUploader := storage.NewFormUploader(cfg)
|
||||
for i := 0; i < 3; i++ {
|
||||
if err = formUploader.Put(context.Background(), &ret, upToken, key, file, fileHeader.Size, &storage.PutExtra{}); err == nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
file.Close()
|
||||
if err == nil {
|
||||
billRec := &legacymodel.StoreBill{
|
||||
Date: time.Now(),
|
||||
Url: strings.Replace(jxutils.ComposeQiniuResURL(ret.Key), "http://", "https://", -1),
|
||||
StoreId: storeID,
|
||||
BillName: fileHeader.Filename,
|
||||
ShopName: shopName,
|
||||
BillTitle: title,
|
||||
}
|
||||
if err = dao.CreateEntity(db, billRec); err == nil {
|
||||
err = weixinmsg.NotifySaleBill(storeID, title, shopName, fmt.Sprintf("%s/billshow/?path=%s", globals.BackstageHost, billRec.Url))
|
||||
if err != nil {
|
||||
globals.SugarLogger.Infof("SendFilesToStores NotifySaleBill file:%s error:%v", fileHeader.Filename, err)
|
||||
}
|
||||
err = nil // 忽略微信发送错误
|
||||
} else {
|
||||
globals.SugarLogger.Warnf("SendFilesToStores CreateEntity file:%s error:%v", fileHeader.Filename, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
sort.Sort(sort.StringSlice(valueList))
|
||||
valueList = append(valueList, fmt.Sprintf("key=%s", globals.WxpayAppKey))
|
||||
sig = strings.Join(valueList, "&")
|
||||
var binSig []byte
|
||||
if signType == sigTypeSha256 {
|
||||
mac := hmac.New(sha256.New, []byte(globals.WxpayAppKey))
|
||||
mac.Write([]byte(sig))
|
||||
binSig = mac.Sum(nil)
|
||||
} else {
|
||||
binSig2 := md5.Sum([]byte(sig))
|
||||
binSig = binSig2[:]
|
||||
}
|
||||
sig = fmt.Sprintf("%X", binSig)
|
||||
// baseapi.SugarLogger.Debug(sig)
|
||||
return sig
|
||||
}
|
||||
|
||||
func (p *PayHandler) CreateRefund() (err error) {
|
||||
switch p.PayType {
|
||||
case model.PayTypeTL: // 收费贵,不适用
|
||||
case model.PayTypeAliPay: // 支付宝支付
|
||||
|
||||
case model.PayTypeWX: // 需要保持账号每天有交易流水,不适用
|
||||
//企业付款(提现)
|
||||
if p.VendorPayType == model.VendorPayTypeCompanyPay {
|
||||
param := &wxpayapi.TransfersParam{
|
||||
PartnerTradeNo: p.Order.OrderID,
|
||||
CheckName: wxpayapi.CheckName,
|
||||
Desc: "冲天猴儿app提现到账",
|
||||
SpbillCreateIP: p.Ctx.GetRealRemoteIP(),
|
||||
}
|
||||
//1元以下免费,以上收取对应城市手续费
|
||||
place, err := dao.GetPlaceByCode(dao.GetDB(), p.Order.CityCode)
|
||||
if err != nil || place == nil {
|
||||
return fmt.Errorf("未找到该城市!code:%v", p.Order.CityCode)
|
||||
}
|
||||
if p.Order.PayPrice < 100 {
|
||||
param.Amount = p.Order.PayPrice
|
||||
} else {
|
||||
param.Amount = p.Order.PayPrice * place.DividePercentage / 100 //手续费
|
||||
}
|
||||
if authInfo, err := p.Ctx.GetV2AuthInfo(); err == nil {
|
||||
param.OpenID = authInfo.GetAuthID()
|
||||
}
|
||||
globals.SugarLogger.Debugf("CreateRefund wx param: %v", utils.Format4Output(param, false))
|
||||
result, err2 := payMap[p.Order.Way].Transfers(param)
|
||||
if err2 == nil {
|
||||
p.Order.PayFinishedAt = utils.Str2Time(result.PaymentTime)
|
||||
p.Order.Comment = result.DeviceInfo
|
||||
p.Order.OriginalData = utils.Format4Output(result, true)
|
||||
if result.ReturnMsg == "" {
|
||||
p.Order.Status = model.OrderStatusFinished
|
||||
} else {
|
||||
globals.SugarLogger.Warnf("SendFilesToStores file:%s failed with error:%v", fileHeader.Filename, err)
|
||||
p.Order.Status = model.OrderStatusCanceled
|
||||
}
|
||||
dao.UpdateEntity(dao.GetDB(), p.Order)
|
||||
if result.ReturnMsg == "" {
|
||||
err = OnCashFinished(p.Order)
|
||||
}
|
||||
} else {
|
||||
globals.SugarLogger.Warnf("SendFilesToStores open file:%s failed with error:%v", fileHeader.Filename, err)
|
||||
return err2
|
||||
}
|
||||
return retVal, err
|
||||
}, fileList)
|
||||
tasksch.HandleTask(task, nil, true).Run()
|
||||
hint = task.ID
|
||||
if !isAsync {
|
||||
_, err = task.GetResult(0)
|
||||
err = OnCashFinished(p.Order)
|
||||
} else if p.VendorPayType == model.VendorPayTypeTransferAccount {
|
||||
p.Order.PayFinishedAt = time.Now()
|
||||
p.Order.Comment = "手动转账"
|
||||
p.Order.Status = model.OrderStatusFinished
|
||||
if _, err := dao.UpdateEntity(dao.GetDB(), p.Order); err == nil {
|
||||
err = OnCashFinished(p.Order)
|
||||
}
|
||||
}
|
||||
}
|
||||
return task.ID, err
|
||||
return err
|
||||
}
|
||||
|
||||
func GetStoreBills(ctx *jxcontext.Context, storeID int) (bills []*legacymodel.StoreBill, err error) {
|
||||
db := dao.GetDB()
|
||||
if err = dao.GetRows(db, &bills, `
|
||||
SELECT *
|
||||
FROM store_bill
|
||||
WHERE store_id = ?
|
||||
ORDER BY date DESC
|
||||
LIMIT 10
|
||||
`, storeID); err != nil {
|
||||
return nil, err
|
||||
func OnTLPayCallback(call *tonglianpayapi.CallBackResult) (err error) {
|
||||
globals.SugarLogger.Debugf("OnTLPayCallback msg:%s", utils.Format4Output(call, true))
|
||||
switch call.TrxCode {
|
||||
case tonglianpayapi.MsgTypePay:
|
||||
err = onTLpayFinished(call)
|
||||
case tonglianpayapi.MsgTypeRefund:
|
||||
err = onTLpayRefund(call)
|
||||
}
|
||||
return bills, err
|
||||
return err
|
||||
}
|
||||
|
||||
func onTLpayFinished(call *tonglianpayapi.CallBackResult) (err error) {
|
||||
order := &model.Order{
|
||||
OrderID: call.CusorderID,
|
||||
TransactionID: call.TrxID,
|
||||
}
|
||||
db := dao.GetDB()
|
||||
if err = dao.GetEntity(db, order, "OrderID"); err == nil {
|
||||
if order.Status != model.OrderStatusWait4Pay {
|
||||
globals.SugarLogger.Debugf("already pay msg:%s, err:%v", utils.Format4Output(call, true), err)
|
||||
return err
|
||||
}
|
||||
loc, _ := time.LoadLocation("Local")
|
||||
t1, _ := time.ParseInLocation("20060102150405", call.PayTime, loc)
|
||||
order.PayFinishedAt = t1
|
||||
order.OriginalData = utils.Format4Output(call, true)
|
||||
payStatus := model.PayStatusNo
|
||||
//order.PayMethod = 2 // 通联微信支付
|
||||
if call.TrxStatus == tonglianpayapi.TrxStatusSuccess {
|
||||
order.Status = model.OrderStatusFinished
|
||||
payStatus = model.OrderStatusSuccessPay
|
||||
} else {
|
||||
order.Status = model.OrderStatusCanceled
|
||||
payStatus = model.OrderStatusFailPay
|
||||
}
|
||||
|
||||
//充值会员 增加微信支付处理业务
|
||||
if (order.OrderType == model.OrderTypeMember || order.OrderType == model.OrderTypeMemberYear) && call.TrxStatus == tonglianpayapi.TrxStatusSuccess {
|
||||
return OnWXPayFinished(order)
|
||||
}
|
||||
// 充值话费
|
||||
if order.OrderType == model.OrderTypeMobile && call.TrxStatus == tonglianpayapi.TrxStatusSuccess {
|
||||
return OnWxPayTelephone(order)
|
||||
}
|
||||
// 发快递
|
||||
if order.OrderType == model.OrderTypeDelivery && call.TrxStatus == tonglianpayapi.TrxStatusSuccess {
|
||||
return OnWxPaySendPage(db, order, call, payStatus)
|
||||
}
|
||||
//需要充值到余额方式 购买的
|
||||
if order.OrderType == model.OrderTypeBalance && call.TrxStatus == tonglianpayapi.TrxStatusSuccess {
|
||||
if err := dao.UpdateUserBill(order.UserID, order.PayPrice); err != nil {
|
||||
return err
|
||||
}
|
||||
order.Status = 110
|
||||
if _, err := dao.UpdateEntity(db, order, "Status"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
globals.SugarLogger.Debugf("onTLpayFinished msg:%s, err:%v", utils.Format4Output(call, true), err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func onTLpayRefund(call *tonglianpayapi.CallBackResult) (err error) {
|
||||
orderPayRefund := &model.OrderPayRefund{
|
||||
RefundID: call.CusorderID,
|
||||
}
|
||||
db := dao.GetDB()
|
||||
if err = dao.GetEntity(db, orderPayRefund, "RefundID"); err == nil {
|
||||
if call.TrxStatus == tonglianpayapi.TrxStatusSuccess {
|
||||
orderPayRefund.Status = model.RefundStatusYes
|
||||
} else {
|
||||
orderPayRefund.Status = model.RefundStatusFailed
|
||||
}
|
||||
orderPayRefund.OriginalData = utils.Format4Output(call, true)
|
||||
dao.UpdateEntity(db, orderPayRefund)
|
||||
} else if dao.IsNoRowsError(err) {
|
||||
globals.SugarLogger.Warnf("收到异常的退款事件, call:%s", utils.Format4Output(call, true))
|
||||
}
|
||||
|
||||
orderPay := &model.Order{
|
||||
OrderID: orderPayRefund.VendorOrderID,
|
||||
}
|
||||
if err = dao.GetEntity(db, orderPay, "VendorOrderID"); err == nil {
|
||||
orderPay.Status = model.OrderStatusCancel
|
||||
}
|
||||
if orderPay.OrderType == model.PayType4Express {
|
||||
tx, _ := dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
dao.Rollback(db, tx)
|
||||
panic(r)
|
||||
}
|
||||
}()
|
||||
|
||||
if _, err = dao.UpdateEntityTx(tx, orderPay); err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
if _, err = dao.UpdateEntityTx(tx, &model.UserVendorOrder{LocalWayBill: call.CusorderID, OrderStatus: model.OrderStatusCancel}, "OrderStatus"); err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
tx.Commit()
|
||||
return err
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func OnWxPayCallback(msg *wxpayapi.CallbackMsg) (err error) {
|
||||
globals.SugarLogger.Debugf("OnWxPayCallback msg:%s", utils.Format4Output(msg, true))
|
||||
switch msg.MsgType {
|
||||
case wxpayapi.MsgTypePay:
|
||||
err = onWxpayFinished(msg.Data.(*wxpayapi.PayResultMsg))
|
||||
case wxpayapi.MsgTypeRefund:
|
||||
// err = onWxpayRefund(msg.Data.(*wxpayapi.RefundResultMsg))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func onWxpayFinished(msg *wxpayapi.PayResultMsg) (err error) {
|
||||
order := &model.Order{
|
||||
OrderID: msg.OutTradeNo,
|
||||
}
|
||||
db := dao.GetDB()
|
||||
if err = dao.GetEntity(db, order, "OrderID"); err == nil {
|
||||
order.PayFinishedAt = wxpayapi.PayTime2Time(msg.TimeEnd)
|
||||
order.TransactionID = msg.TransactionID
|
||||
order.OriginalData = utils.Format4Output(msg, true)
|
||||
if msg.ResultCode == wxpayapi.ResponseCodeSuccess {
|
||||
order.Status = model.OrderStatusFinished
|
||||
} else {
|
||||
order.Status = model.OrderStatusCanceled
|
||||
}
|
||||
dao.UpdateEntity(db, order)
|
||||
if msg.ResultCode == wxpayapi.ResponseCodeSuccess {
|
||||
err = OnPayFinished(order)
|
||||
}
|
||||
} else {
|
||||
globals.SugarLogger.Debugf("onWxpayFinished msg:%s, err:%v", utils.Format4Output(msg, true), err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// func onWxpayRefund(msg *wxpayapi.RefundResultMsg) (err error) {
|
||||
// orderPayRefund := &model.OrderPayRefund{
|
||||
// RefundID: msg.ReqInfoObj.OutRefundNo,
|
||||
// }
|
||||
// db := dao.GetDB()
|
||||
// if err = dao.GetEntity(db, orderPayRefund, "RefundID"); err == nil {
|
||||
// if msg.ResultCode == wxpayapi.ResponseCodeSuccess {
|
||||
// orderPayRefund.Status = model.RefundStatusYes
|
||||
// } else {
|
||||
// orderPayRefund.Status = model.RefundStatusFailed
|
||||
// }
|
||||
// orderPayRefund.OriginalData = utils.Format4Output(msg, true)
|
||||
// dao.UpdateEntity(db, orderPayRefund)
|
||||
// } else if dao.IsNoRowsError(err) {
|
||||
// globals.SugarLogger.Warnf("收到异常的退款事件, msg:%s", utils.Format4Output(msg, true))
|
||||
// }
|
||||
|
||||
// orderPay := &model.OrderPay{
|
||||
// VendorOrderID: orderPayRefund.VendorOrderID,
|
||||
// VendorID: jxutils.GetPossibleVendorIDFromVendorOrderID(orderPayRefund.VendorOrderID),
|
||||
// PayType: model.PayTypeWX,
|
||||
// Status: model.PayStatusYes,
|
||||
// }
|
||||
// orderPay.DeletedAt = utils.DefaultTimeValue
|
||||
// if err = dao.GetEntity(db, orderPay, "VendorOrderID", "VendorID", "PayType", "Status", "DeletedAt"); err == nil {
|
||||
// orderPay.Status = model.PayStatusRefund
|
||||
// dao.UpdateEntity(db, orderPay)
|
||||
// }
|
||||
// return err
|
||||
// }
|
||||
|
||||
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
|
||||
}
|
||||
@@ -2,13 +2,12 @@ package initdata
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"git.rosy.net.cn/baseapi/platformapi/tencent_map"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/autonavi"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
)
|
||||
|
||||
@@ -17,9 +16,9 @@ func TruncateTable(db *dao.DaoDB, tableName string) (err error) {
|
||||
return err
|
||||
}
|
||||
|
||||
func insertPlace(ctx *jxcontext.Context, db *dao.DaoDB, parent *tencent_map.District, placeList []*tencent_map.District) (err error) {
|
||||
func insertPlace(ctx *jxcontext.Context, db *dao.DaoDB, parent *autonavi.District, placeList []*autonavi.District) (err error) {
|
||||
for _, v := range placeList {
|
||||
if v.Level <= tencent_map.DistrictLevelDistrict {
|
||||
if v.Level <= autonavi.DistrictLevelDistrict {
|
||||
place := &model.Place{
|
||||
Code: int(utils.Str2Int64(v.Adcode)),
|
||||
Name: v.Name,
|
||||
@@ -43,8 +42,7 @@ func insertPlace(ctx *jxcontext.Context, db *dao.DaoDB, parent *tencent_map.Dist
|
||||
}
|
||||
|
||||
func InitPlace(ctx *jxcontext.Context) (err error) {
|
||||
// 这个地方是更新全国的place表,因为两个不兼容且上传时间不会发送改变,暂时不做返回
|
||||
placeList, err2 := api.TencentMapAPI.GetDistricts(tencent_map.DistrictLevelDistrict, "", 0)
|
||||
placeList, err2 := api.AutonaviAPI.GetDistricts(autonavi.DistrictLevelDistrict, "")
|
||||
if err = err2; err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -69,124 +67,10 @@ func InitPlace(ctx *jxcontext.Context) (err error) {
|
||||
if err = insertPlace(ctx, db, nil, placeList); err != nil {
|
||||
return err
|
||||
}
|
||||
updateSqls := []string{
|
||||
`
|
||||
UPDATE place t1
|
||||
JOIN jde_city t2 ON t1.code = t2.col_tencentAddressCode
|
||||
SET t1.jd_code = t2.col_areaCode;
|
||||
`,
|
||||
`
|
||||
UPDATE place t1
|
||||
JOIN place t2 ON t1.parent_code = t2.code AND t2.jd_code != 0
|
||||
JOIN jde_district t3 ON t1.name = t3.col_areaName AND t2.jd_code = t3.col_cityCode
|
||||
SET t1.jd_code = t3.col_areaCode
|
||||
WHERE t1.level = 3;
|
||||
`,
|
||||
`
|
||||
UPDATE
|
||||
place t1
|
||||
JOIN ebde_places t2 ON t1.name = t2.col_city_name
|
||||
SET t1.ebai_code = t2.col_city_id
|
||||
WHERE t1.level = 1 OR t1.level = 2;
|
||||
`,
|
||||
`
|
||||
UPDATE
|
||||
place t1
|
||||
JOIN place t1p ON t1.parent_code = t1p.code
|
||||
JOIN ebde_places t2 ON t1.name = t2.col_city_name
|
||||
JOIN ebde_places t2p ON t2.col_parent_id = t2p.col_city_id AND t1p.ebai_code = t2p.col_city_id
|
||||
SET t1.ebai_code = t2.col_city_id
|
||||
WHERE t1.level = 3;
|
||||
`,
|
||||
`
|
||||
UPDATE
|
||||
place t1
|
||||
JOIN mtpsdeliveryprice t2 ON t1.code = t2.citycode
|
||||
SET t1.mtps_price = t2.price;
|
||||
`,
|
||||
`
|
||||
UPDATE
|
||||
place t1
|
||||
JOIN mtpsdeliveryprice t2 ON t1.name LIKE CONCAT(t2.cityname, '%')
|
||||
SET t1.mtps_price = t2.price
|
||||
WHERE t1.level = 2 AND t1.mtps_price = 0;
|
||||
`,
|
||||
`
|
||||
UPDATE place t1
|
||||
LEFT JOIN (
|
||||
SELECT DISTINCT city_code
|
||||
FROM store
|
||||
UNION DISTINCT
|
||||
SELECT DISTINCT place_code city_code
|
||||
FROM sku_name_place_bind
|
||||
) t2 ON t1.code = t2.city_code
|
||||
SET t1.enabled = 0
|
||||
WHERE t1.level = 2 AND t2.city_code IS NULL;
|
||||
`,
|
||||
}
|
||||
for _, v := range updateSqls {
|
||||
if _, err = dao.ExecuteSQL(db, v); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
dao.Commit(db, txDB)
|
||||
return err
|
||||
}
|
||||
|
||||
func InitVendorCategory(ctx *jxcontext.Context, vendorID int, isAsync bool) (hint string, err error) {
|
||||
if handler := partner.GetPurchasePlatformFromVendorID(vendorID); handler != nil {
|
||||
var cats []*model.SkuVendorCategory
|
||||
rootTask := tasksch.NewSeqTask(fmt.Sprintf("创建%s的平台分类", model.VendorChineseNames[vendorID]), ctx,
|
||||
func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
|
||||
switch step {
|
||||
case 0:
|
||||
cats, err = handler.GetVendorCategories(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case 1:
|
||||
db := dao.GetDB()
|
||||
txDB, _ := dao.Begin(db)
|
||||
defer func() {
|
||||
if r := recover(); r != nil || err != nil {
|
||||
dao.Rollback(db, txDB)
|
||||
if r != nil {
|
||||
panic(r)
|
||||
}
|
||||
}
|
||||
}()
|
||||
sql := `
|
||||
DELETE
|
||||
FROM sku_vendor_category
|
||||
WHERE vendor_id = ?
|
||||
`
|
||||
if _, err = dao.ExecuteSQL(db, sql, vendorID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, cat := range cats {
|
||||
dao.WrapAddIDCULEntity(cat, ctx.GetUserName())
|
||||
}
|
||||
if err = dao.CreateMultiEntities(db, cats); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dao.Commit(db, txDB)
|
||||
}
|
||||
return nil, err
|
||||
}, 2)
|
||||
tasksch.HandleTask(rootTask, nil, true).Run()
|
||||
if !isAsync {
|
||||
if _, err = rootTask.GetResult(0); err == nil {
|
||||
hint = utils.Int2Str(len(cats))
|
||||
}
|
||||
} else {
|
||||
hint = rootTask.ID
|
||||
}
|
||||
} else {
|
||||
err = fmt.Errorf("找不到平台:%d", vendorID)
|
||||
}
|
||||
return hint, err
|
||||
}
|
||||
|
||||
func UploadImg4Vendors(ctx *jxcontext.Context, isAsync, isContinueWhenError bool) (hint string, err error) {
|
||||
// db := dao.GetDB()
|
||||
// rootTask := tasksch.NewSeqTask("合并SkuName图片至DataResource", ctx,
|
||||
|
||||
@@ -1,119 +0,0 @@
|
||||
package knowledge
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"git.rosy.net.cn/baseapi/platformapi/weixinapi"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/weixinmsg"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func GetKnowledgeDepot(ctx *jxcontext.Context, keyword string, offset, pageSize int) (page *model.PagedInfo, err error) {
|
||||
return dao.GetKnowledgeDepot(dao.GetDB(), keyword, offset, pageSize)
|
||||
}
|
||||
func AddKnowledgeDepot(ctx *jxcontext.Context, title, content string) (err error) {
|
||||
var (
|
||||
db = dao.GetDB()
|
||||
)
|
||||
know := &model.KnowledgeDepot{
|
||||
Title: title,
|
||||
Content: content,
|
||||
}
|
||||
dao.WrapAddIDCULDEntity(know, ctx.GetUserName())
|
||||
dao.CreateEntity(db, know)
|
||||
return err
|
||||
}
|
||||
|
||||
func UpdateKnowledgeDepot(ctx *jxcontext.Context, id int, content string, isDel bool) (err error) {
|
||||
var (
|
||||
db = dao.GetDB()
|
||||
know = &model.KnowledgeDepot{}
|
||||
)
|
||||
know.ID = id
|
||||
err = dao.GetEntity(db, know)
|
||||
if isDel {
|
||||
dao.DeleteEntity(db, know)
|
||||
} else {
|
||||
if content != know.Content {
|
||||
know.Content = content
|
||||
dao.UpdateEntity(db, know, "Content")
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
type SNSUploadImgResult struct {
|
||||
URL string `json:"url"`
|
||||
MediaID string `json:"mediaID"`
|
||||
}
|
||||
|
||||
func SNSUploadImg(ctx *jxcontext.Context, files []*multipart.FileHeader, isThumb bool) (snsUploadImgResult *SNSUploadImgResult, err error) {
|
||||
var (
|
||||
fileHeader = files[0]
|
||||
fileName = fileHeader.Filename
|
||||
data = make([]byte, fileHeader.Size)
|
||||
)
|
||||
snsUploadImgResult = &SNSUploadImgResult{}
|
||||
file, err := fileHeader.Open()
|
||||
file.Read(data)
|
||||
if len(data) == 0 {
|
||||
return snsUploadImgResult, fmt.Errorf("未读取到文件!")
|
||||
}
|
||||
//如果不是缩略图,只会返url
|
||||
//如果是封面缩略图,则还会返mediaID
|
||||
if !isThumb {
|
||||
if url, err := api.WeixinAPI.CBUploadImg(data, fileName, http.DetectContentType(data)); err == nil && url != "" {
|
||||
snsUploadImgResult.URL = url
|
||||
}
|
||||
} else {
|
||||
if mediaID, url, err := api.WeixinAPI.CBUploadThumb(data, fileName, http.DetectContentType(data)); err == nil && url != "" && mediaID != "" {
|
||||
snsUploadImgResult.URL = url
|
||||
snsUploadImgResult.MediaID = mediaID
|
||||
}
|
||||
}
|
||||
file.Close()
|
||||
return snsUploadImgResult, err
|
||||
}
|
||||
|
||||
func AddMaterial(ctx *jxcontext.Context, knowIDs []int, param *weixinapi.CBAddNewsParam) (err error) {
|
||||
var (
|
||||
db = dao.GetDB()
|
||||
content = ""
|
||||
)
|
||||
if len(knowIDs) == 0 {
|
||||
return fmt.Errorf("请至少勾选一条!")
|
||||
}
|
||||
knows, err := dao.GetKnowledgeDepotNoPage(db, knowIDs)
|
||||
for k, v := range knows {
|
||||
if k != 0 {
|
||||
content += weixinapi.SNSCutLine
|
||||
}
|
||||
content += v.Content
|
||||
}
|
||||
if content != "" {
|
||||
param.Content = content
|
||||
api.WeixinAPI.CBAddNews(param)
|
||||
} else {
|
||||
return fmt.Errorf("读取内容错误!")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func SendSNSMediaMsg(ctx *jxcontext.Context, storeIDs []int, mediaID string) (err error) {
|
||||
var (
|
||||
openIDs []string
|
||||
)
|
||||
for _, v := range storeIDs {
|
||||
if results := weixinmsg.GetWeixinOpenIDsFromStoreID(v); len(results) > 0 {
|
||||
openIDs = append(openIDs, results...)
|
||||
}
|
||||
}
|
||||
if len(openIDs) > 0 {
|
||||
return weixinmsg.MediaMessageSendGroup(openIDs, mediaID)
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -1,825 +1,76 @@
|
||||
package misc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"git.rosy.net.cn/jx-callback/business/jxstore/partner/pdd"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
bidaServer "git.rosy.net.cn/jx-callback/business/q_bida"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/bidding"
|
||||
"git.rosy.net.cn/jx-callback/business/partner/delivery"
|
||||
"git.rosy.net.cn/jx-callback/business/jxstore/event"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/partner/purchase/jdshop"
|
||||
|
||||
"git.rosy.net.cn/baseapi/platformapi/jdapi"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/partner/purchase/jx/localjx"
|
||||
"git.rosy.net.cn/jx-callback/globals/api"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/jxstore/report"
|
||||
"git.rosy.net.cn/jx-callback/business/jxstore/cms"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/baseapi/utils/errlist"
|
||||
"git.rosy.net.cn/jx-callback/business/jxcallback/orderman"
|
||||
"git.rosy.net.cn/jx-callback/business/jxcallback/scheduler/defsch"
|
||||
"git.rosy.net.cn/jx-callback/business/jxstore/act"
|
||||
"git.rosy.net.cn/jx-callback/business/jxstore/cms"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/netprinter"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/business/netspider"
|
||||
"git.rosy.net.cn/jx-callback/business/partner"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
beego "github.com/astaxie/beego/server/web"
|
||||
)
|
||||
|
||||
const (
|
||||
SpecialTaskID = "Running"
|
||||
TaskNameSyncStoreSku = "SyncStoreSku"
|
||||
)
|
||||
|
||||
var (
|
||||
dailyHeartbeat = []string{
|
||||
"09:00:00",
|
||||
}
|
||||
dailyWorkTimeList = []string{
|
||||
"21:30:00",
|
||||
"00:18:35",
|
||||
}
|
||||
dailyWorkTimeList2 = []string{
|
||||
"02:30:00",
|
||||
stationTimeList = []string{
|
||||
"11:35:00",
|
||||
}
|
||||
priceReferTimeList = []string{
|
||||
"03:00:00",
|
||||
}
|
||||
checkCookieList = []string{
|
||||
"08:00:00",
|
||||
"12:00:00",
|
||||
"18:00:00",
|
||||
}
|
||||
createStorePriceTimeList = []string{
|
||||
startDeleteTime = []string{
|
||||
"04:00:00",
|
||||
}
|
||||
refreshPageActTimeList = []string{
|
||||
"7:00:00",
|
||||
//"8:00:00",
|
||||
"9:00:00",
|
||||
//"10:00:00",
|
||||
"11:00:00",
|
||||
//"12:00:00",
|
||||
"13:00:00",
|
||||
//"14:00:00",
|
||||
"15:00:00",
|
||||
//"16:00:00",
|
||||
"17:00:00",
|
||||
//"18:00:00",
|
||||
"19:00:00",
|
||||
"22:00:00",
|
||||
}
|
||||
// 七牛云流量检查
|
||||
ChangeStoreSkuSaleStatusList = []string{
|
||||
//"7:00:00",
|
||||
//"8:00:00",
|
||||
//"9:00:00",
|
||||
/* //"10:00:00",
|
||||
//"11:00:00",
|
||||
//"12:00:00",
|
||||
//"13:00:00",
|
||||
//"14:00:00",
|
||||
//"15:00:00",
|
||||
//"16:00:00",
|
||||
//"17:00:00",
|
||||
//"18:00:00",
|
||||
//"19:00:00",
|
||||
//"20:00:00",*/
|
||||
}
|
||||
openRemoteStoreTimeList = []string{
|
||||
"04:30:00",
|
||||
"23:30:00",
|
||||
}
|
||||
updateActStatusTimeList = []string{
|
||||
"00:01:00",
|
||||
}
|
||||
sendSecKillWarnList = []string{
|
||||
"9:00:00",
|
||||
}
|
||||
autoPayForPopluarManList = []string{
|
||||
"10:30:00",
|
||||
}
|
||||
|
||||
autoSaleStoreSkuTimeList = []string{
|
||||
cms.AutoSaleAtStr,
|
||||
}
|
||||
|
||||
backUpStoreSkuBindList = []string{
|
||||
"23:30:00",
|
||||
}
|
||||
|
||||
exSyncList = []string{
|
||||
"11:30:00",
|
||||
}
|
||||
|
||||
importantTaskMap = &sync.Map{}
|
||||
|
||||
cancelPayTimeOutOrderList = localjx.GetHalfHoursList()
|
||||
discountActJxList = localjx.GetDiscountActHoursList()
|
||||
|
||||
//ebaiStorePageCookieExdTOKEN string
|
||||
//ebaiStorePageCookieWMUSS2 string
|
||||
//ebaiStorePageCookieWMSTOKEN2 string
|
||||
ebaiStorePageCookie string
|
||||
//ebaiStorePageCookieWMSTOKEN string
|
||||
mtwmCookieStr string
|
||||
mtpsStoreToken string
|
||||
jd2StorePageCookie string
|
||||
JdStorePageCookie string
|
||||
yinbaoCookie string
|
||||
feiePageCookie string
|
||||
jdStorePageEarning string
|
||||
//jdsCookie string
|
||||
// jdsCookie2 string
|
||||
)
|
||||
|
||||
func GetImportantTaskID(taskName string) string {
|
||||
if value, ok := importantTaskMap.Load(taskName); ok {
|
||||
return value.(string)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func SaveImportantTaskID(taskName, taskID string) {
|
||||
importantTaskMap.Store(taskName, taskID)
|
||||
}
|
||||
|
||||
func IsImportantTaskRunning(taskName string) bool {
|
||||
taskID := GetImportantTaskID(taskName)
|
||||
if taskID == "" {
|
||||
return false
|
||||
} else if taskID == SpecialTaskID {
|
||||
return true
|
||||
}
|
||||
return tasksch.IsTaskRunning(taskID)
|
||||
}
|
||||
|
||||
func Init() {
|
||||
if globals.IsProductEnv() {
|
||||
//ScheduleTimerFunc("doDailyWork2", doDailyWork2, dailyWorkTimeList2)
|
||||
if globals.IsMainProductEnv() {
|
||||
|
||||
//京东的订单信息解密密钥获取
|
||||
//拼多多订单轮询
|
||||
ScheduleTimerFuncByInterval(func() {
|
||||
jdshop.InitKey()
|
||||
}, 5*time.Second, 8*time.Hour)
|
||||
|
||||
ScheduleTimerFuncByInterval(func() {
|
||||
RefreshRealMobile(jxcontext.AdminCtx, model.VendorIDEBAI, time.Now().Add(-24*time.Hour), utils.DefaultTimeValue, false, true)
|
||||
report.RefreshStoreManageState(jxcontext.AdminCtx, nil, []int{model.VendorIDJD})
|
||||
}, 5*time.Second, 1*time.Hour)
|
||||
|
||||
// 定时任务通知:签约门店过期通知
|
||||
ScheduleTimerFunc("GetExpireShopNoticeUser", func() {
|
||||
bidding.GetExpireShopNoticeUser()
|
||||
}, []string{
|
||||
"10:00:00",
|
||||
})
|
||||
|
||||
//每天晚上23:00更新抖店 审核状态
|
||||
ScheduleTimerFunc("UpdateStorePoiStatus", func() {
|
||||
cms.UpdateStorePoiStatus(jxcontext.AdminCtx)
|
||||
}, []string{
|
||||
"22:00:00",
|
||||
})
|
||||
//每天晚上23:00获取门店 电子围栏、仓库、限售模板、运费模板ID同步进数据库
|
||||
ScheduleTimerFunc("UpdateStoreRelInformation", func() {
|
||||
cms.UpdateStoreRelInformation(jxcontext.AdminCtx)
|
||||
}, []string{
|
||||
"22:00:00",
|
||||
})
|
||||
// 更新抖店订单的结算信息
|
||||
ScheduleTimerFunc("UpdateTiktokShopTotalMoney", func() {
|
||||
orderman.UpdateTiktokShopTotalMoney(0, utils.DefaultTimeValue, utils.DefaultTimeValue)
|
||||
}, []string{
|
||||
"07:00:00",
|
||||
"09:00:00",
|
||||
"15:00:00",
|
||||
"19:00:00",
|
||||
"22:00:00",
|
||||
"02:00:00",
|
||||
"05:00:00",
|
||||
})
|
||||
|
||||
ScheduleTimerFunc("UpdateMtActivityInfo", func() {
|
||||
bidding.GetMTInfo()
|
||||
}, []string{
|
||||
"13:00:00",
|
||||
})
|
||||
/// 更新淘鲜达结算信息
|
||||
//ScheduleTimerFunc("UpdateTaoTotalMoney", func() {
|
||||
// orderman.UpdateTaoSettleInfo()
|
||||
//}, []string{
|
||||
// "06:30:00",
|
||||
// "01:45:00",
|
||||
//})
|
||||
|
||||
// 每分钟轮询一次,推送骑手信息(假的订单)
|
||||
ScheduleTimerFuncByInterval(func() {
|
||||
delivery.UpdateFakeWayBillToTiktok()
|
||||
}, 10*time.Second, 20*time.Second)
|
||||
|
||||
// 每五分钟轮询一次推送骑手信息坐标给美团/抖音(真订单,真自送)
|
||||
ScheduleTimerFuncByInterval(func() {
|
||||
delivery.GetOrderRiderInfoToPlatform("", 0)
|
||||
}, 10*time.Second, 20*time.Second)
|
||||
|
||||
// (自动发单拣货,设置骑手) 刷单用
|
||||
//ScheduleTimerFuncByInterval(func() {
|
||||
// auto_delivery.Init() // 初始化骑手列表
|
||||
// auto_delivery.AutoSettingFakeDelivery()
|
||||
//}, 10*time.Second, 5*time.Minute)
|
||||
|
||||
// 定时任务更新负责人信息
|
||||
ScheduleTimerFunc("RefreshStoreOperator", func() {
|
||||
cms.UpdateStoreOperatorConfig()
|
||||
}, []string{
|
||||
"04:00:00",
|
||||
})
|
||||
|
||||
// 每天更新美团-门店结算方式[结算给企业/结算给个人](取消了平台运单的骑手计费)
|
||||
ScheduleTimerFunc("LoadingStoreOrderSettleAmount", func() {
|
||||
delivery.LoadingStoreOrderSettleAmount(0, 0, nil)
|
||||
}, []string{
|
||||
"12:50:00",
|
||||
})
|
||||
|
||||
ScheduleTimerFunc("UpdateStoreName ", func() {
|
||||
cms.UpdateStoreName()
|
||||
}, []string{
|
||||
"13:35:00",
|
||||
})
|
||||
|
||||
// 定时任务更新昨天的都要商品和本地商品id的映射关系
|
||||
//ScheduleTimerFunc("RefreshStoreOperator", func() {
|
||||
// t := time.Now()
|
||||
// cms.SyncTiktokMainIdToLocal(jxcontext.AdminCtx, &tiktok_store.MainSku{
|
||||
// AppOrgCode: "",
|
||||
// CheckStatus: 3,
|
||||
// StartTime: time.Date(t.Year(), t.Month(), t.Day()-1, 0, 0, 1, 0, time.Local).Unix(),
|
||||
// EndTime: time.Date(t.Year(), t.Month(), t.Day()-1, 23, 59, 59, 0, time.Local).Unix(),
|
||||
// Page: 1,
|
||||
// PageSize: 100,
|
||||
// })
|
||||
//}, []string{
|
||||
// "04:30:00",
|
||||
//})
|
||||
|
||||
ScheduleTimerFuncByInterval(func() {
|
||||
defsch.FixedScheduler.ConfirmSelfTakeOrders(jxcontext.AdminCtx, []int{model.VendorIDJD}, time.Now().Add(-48*time.Hour), time.Now().Add(-30*time.Minute), true, true)
|
||||
}, 5*time.Second, 10*time.Minute)
|
||||
|
||||
ScheduleTimerFuncByInterval(func() {
|
||||
report.RefreshStoreManageState(jxcontext.AdminCtx, nil, []int{model.VendorIDMTWM, model.VendorIDEBAI})
|
||||
}, 5*time.Second, 40*time.Minute)
|
||||
|
||||
ScheduleTimerFuncByInterval(func() {
|
||||
orderman.SaveJdsOrders(jxcontext.AdminCtx, time.Now().Add(-30*time.Minute), time.Now())
|
||||
orderman.UpdateJdsOrdersStatus(jxcontext.AdminCtx, time.Now().AddDate(0, 0, -1), time.Now())
|
||||
pdd.GetUnionOrders()
|
||||
}, 5*time.Second, 5*time.Minute)
|
||||
|
||||
// 抖音更新门店商品 ,接口收费暂不使用
|
||||
//if beego.BConfig.RunMode != "jxgy" {
|
||||
// ScheduleTimerFunc("RefreshSyncSkuList", func() {
|
||||
// syncStoreSkuTiktok()
|
||||
// }, []string{"13:00:00"})
|
||||
//}
|
||||
ScheduleTimerFunc("doDailyWork", doDailyWork, dailyWorkTimeList)
|
||||
|
||||
//if beego.BConfig.RunMode != model.ServerTypeFruits && beego.BConfig.RunMode != model.ServerTypePet {
|
||||
// ScheduleTimerFunc("RefreshSyncSkuListTao", func() {
|
||||
// syncStoreSkuTao()
|
||||
// }, []string{
|
||||
// "03:50:00",
|
||||
// })
|
||||
//}
|
||||
ScheduleTimerFunc("InitStation", func() {
|
||||
//同步油站信息
|
||||
cms.InitStation(jxcontext.AdminCtx)
|
||||
}, stationTimeList)
|
||||
|
||||
// 刷新抖音门店token
|
||||
if beego.BConfig.RunMode != model.ServerTypeFruits && beego.BConfig.RunMode != model.ServerTypePet {
|
||||
ScheduleTimerFuncByInterval(func() {
|
||||
cms.RefreshTiktokShopToken(jxcontext.AdminCtx)
|
||||
}, 60*time.Second, 30*time.Minute)
|
||||
}
|
||||
// 定时删除打印信息
|
||||
ScheduleTimerFunc("DeleteTimeOutPrintMsg", func() {
|
||||
dao.DeletePrintMsg()
|
||||
}, stationTimeList)
|
||||
|
||||
// 定时任务刷新当前订单的物流信息
|
||||
ScheduleTimerFunc("RefreshMaterialLogistics", func() {
|
||||
bidding.LoadingLogistics(nil)
|
||||
}, []string{
|
||||
"02:45:00",
|
||||
})
|
||||
|
||||
//刷新京东物竞天择订单结算价
|
||||
ScheduleTimerFunc("RefreshJdShopOrdersEarningPrice", func() {
|
||||
orderman.RefreshJdShopOrdersEarningPrice(jxcontext.AdminCtx, utils.Time2Str(time.Now().AddDate(0, 0, -2)), utils.Time2Str(time.Now().AddDate(0, 0, -2)))
|
||||
orderman.RefreshJdShopOrdersEarningPrice(jxcontext.AdminCtx, utils.Time2Str(time.Now().AddDate(0, 0, -1)), utils.Time2Str(time.Now().AddDate(0, 0, -1)))
|
||||
}, []string{
|
||||
"05:00:00",
|
||||
})
|
||||
//刷新京东售后单结算价
|
||||
ScheduleTimerFunc("RefreshJdAfsOrderTotalShopMoney", func() {
|
||||
orderman.RefreshJdAfsOrderTotalShopMoney()
|
||||
}, []string{
|
||||
"05:30:00",
|
||||
})
|
||||
|
||||
ScheduleTimerFunc("auto enable remote store", func() {
|
||||
cms.EnableHaveRestStores(jxcontext.AdminCtx, false, true)
|
||||
// cms.OpenRemoteStoreByJxStatus(jxcontext.AdminCtx, nil, nil, false, false, true)
|
||||
}, openRemoteStoreTimeList)
|
||||
|
||||
// ScheduleTimerFunc("SaveAndSendAlarmVendorSnapshot", func() {
|
||||
// cms.SaveAndSendAlarmVendorSnapshot(jxcontext.AdminCtx, nil, nil, false)
|
||||
// }, cms.WatchVendorStoreTimeList)
|
||||
|
||||
ScheduleTimerFunc("RefreshPageActs", func() {
|
||||
act.RefreshPageActs(jxcontext.AdminCtx, []int{model.VendorIDEBAI}, time.Now().Add(-30*24*time.Hour), false)
|
||||
}, refreshPageActTimeList)
|
||||
ScheduleTimerFunc("UpdateActStatusByTime", func() {
|
||||
dao.UpdateActStatusByTime(dao.GetDB(), time.Now())
|
||||
}, updateActStatusTimeList)
|
||||
ScheduleScoreStore()
|
||||
// ScheduleCheckStoreAlert()
|
||||
//ScheduleTimerFunc("ChangeStoreSkuSaleStatus", func() {
|
||||
// cms.CurVendorSync.ChangeStoreSkuSaleStatus(jxcontext.AdminCtx, 0, true, true)
|
||||
//}, ChangeStoreSkuSaleStatusList)
|
||||
ScheduleTimerFunc("BeginSavePriceRefer", func() {
|
||||
report.BeginSavePriceRefer(jxcontext.AdminCtx, nil, nil, true, true)
|
||||
}, priceReferTimeList)
|
||||
ScheduleTimerFunc("CreateStorePriceScore", func() {
|
||||
cms.CreateStorePriceScore(jxcontext.AdminCtx)
|
||||
}, createStorePriceTimeList)
|
||||
//ScheduleTimerFunc("AutoFocusStoreSkusForTopSkus", func() {
|
||||
// cms.AutoFocusStoreSkusForTopSkus(jxcontext.AdminCtx, true, true)
|
||||
//}, createStorePriceTimeList)
|
||||
//ScheduleTimerFunc("GetCheckVendorCookie", func() {
|
||||
// event.GetCheckVendorCookie(jxcontext.AdminCtx, []int{model.VendorIDEBAI, model.VendorIDJD, model.VendorIDMTWM, model.VendorIDMTPS, model.VendorIDJDShop}, true)
|
||||
//}, checkCookieList)
|
||||
//ScheduleTimerFunc("SendSeckillSkusCountMsg", func() {
|
||||
// cms.SendSeckillSkusCountMsg(jxcontext.AdminCtx, []int{model.VendorIDEBAI, model.VendorIDJD, model.VendorIDMTWM}, false, true)
|
||||
//}, sendSecKillWarnList)
|
||||
// ScheduleTimerFunc("每日报警心跳", func() {
|
||||
// globals.SugarLogger.Warnf("每日报警心跳,这不是报警。启动时间:%s", cms.GetServiceInfo(jxcontext.AdminCtx)["startupTime"])
|
||||
// }, dailyHeartbeat)
|
||||
ScheduleTimerFunc("AutoPayForPopluarMan", func() {
|
||||
localjx.AutoPayForPopluarMan(jxcontext.AdminCtx)
|
||||
}, autoPayForPopluarManList)
|
||||
ScheduleTimerFunc("CancelPayTimeOutOrder", func() {
|
||||
localjx.CancelPayTimeOutOrder(jxcontext.AdminCtx)
|
||||
}, cancelPayTimeOutOrderList)
|
||||
ScheduleTimerFunc("BackUpStoreSkuBind", func() {
|
||||
cms.BackUpStoreSkuBind(jxcontext.AdminCtx, true, true)
|
||||
}, backUpStoreSkuBindList)
|
||||
// ScheduleTimerFunc("SendNoCatSkusToOperater", func() {
|
||||
// cms.SendNoCatSkusToOperater(jxcontext.AdminCtx)
|
||||
// }, autoPayForPopluarManList)
|
||||
ScheduleTimerFunc("CleanStoreIsBoughtMatter", func() {
|
||||
cms.CleanStoreIsBoughtMatter(jxcontext.AdminCtx)
|
||||
}, priceReferTimeList)
|
||||
ScheduleTimerFunc("CleanUserOrderSMSMark", func() {
|
||||
cms.CleanUserOrderSMSMark(jxcontext.AdminCtx)
|
||||
}, priceReferTimeList)
|
||||
ScheduleTimerFunc("CreateOrderByPriceDefend", func() {
|
||||
localjx.CreateOrderByPriceDefend(jxcontext.AdminCtx)
|
||||
}, []string{
|
||||
"22:00:00",
|
||||
})
|
||||
//ScheduleTimerFunc("ChangeJxPriceByDiscountAct", func() {
|
||||
// act.ChangeJxPriceByDiscountAct(jxcontext.AdminCtx)
|
||||
//}, discountActJxList)
|
||||
ScheduleTimerFunc("RefreshUserMemberStatus", func() {
|
||||
cms.RefreshUserMemberStatus(jxcontext.AdminCtx)
|
||||
}, updateActStatusTimeList)
|
||||
//刷优惠券状态
|
||||
ScheduleTimerFunc("RefreshCouponsStatus", func() {
|
||||
localjx.RefreshCouponsStatus(jxcontext.AdminCtx)
|
||||
}, updateActStatusTimeList)
|
||||
//刷新美团商超门店Token
|
||||
ScheduleTimerFunc("RefreshMTWMToken", func() {
|
||||
cms.RefreshMTWMToken(jxcontext.AdminCtx)
|
||||
}, updateActStatusTimeList)
|
||||
|
||||
//获取最新平台流量活动
|
||||
ScheduleTimerFunc("GetNewVendorPopActs", func() {
|
||||
act.GetNewVendorPopActs(jxcontext.AdminCtx)
|
||||
}, dailyHeartbeat)
|
||||
//企业微信群人数通告(暂时取消)
|
||||
//ScheduleTimerFunc("SendQywxPeopleCount", func() {
|
||||
// cms.SendQywxPeopleCount(jxcontext.AdminCtx)
|
||||
//}, dailyHeartbeat)
|
||||
ScheduleTimerFunc("doDailyWork1", func() {
|
||||
//同步商品额外前缀和水印图(打标记)
|
||||
cms.SyncSkuExperfixAndWatermark(jxcontext.AdminCtx)
|
||||
}, dailyWorkTimeList)
|
||||
/*ScheduleTimerFunc("BuildFakeMatterOrder", func() {
|
||||
orderman.BuildFakeMatterOrder()
|
||||
}, []string{
|
||||
"09:00:00",
|
||||
"15:00:00",
|
||||
"23:00:00",
|
||||
})*/
|
||||
ScheduleTimerFunc("doDailyWork2", func() {
|
||||
//刷新京东会员
|
||||
//report.RefreshJDMembers(jxcontext.AdminCtx)
|
||||
cms.SetSingleStoreSkuSyncModifyStatus(dao.GetDB(), []int{1, 3})
|
||||
}, dailyWorkTimeList)
|
||||
ScheduleTimerFunc("doDailyWork2-1", func() {
|
||||
// 刷新商品,换个时间节点,房子请求超时
|
||||
cms.CurVendorSync.SyncStoresSkus2(jxcontext.AdminCtx, nil, 0, dao.GetDB(), []int{1, 3}, nil, false, nil, nil, model.SyncFlagSaleMask, true, true)
|
||||
// 刷新门店平台商品
|
||||
//syncStoreSku()
|
||||
}, []string{"02:00:00"})
|
||||
|
||||
ScheduleTimerFunc("doDailyWork3", func() {
|
||||
dao.SetStoresMapSyncStatus(dao.GetDB(), nil, nil, model.SyncFlagStoreStatus)
|
||||
cms.CurVendorSync.SyncStore2Time(jxcontext.AdminCtx, dao.GetDB(), []int{model.VendorIDMTWM, model.VendorIDJD, model.VendorIDEBAI, model.VendorIDDD}, nil, true, true)
|
||||
|
||||
InitEx()
|
||||
cms.SyncStoresCourierInfo(jxcontext.AdminCtx, nil, false, true)
|
||||
netprinter.RebindAllPrinters(jxcontext.AdminCtx, false, true)
|
||||
}, dailyWorkTimeList)
|
||||
|
||||
//if beego.BConfig.RunMode != model.ServerTypePet {
|
||||
ScheduleTimerFunc("doDailyWork4", func() {
|
||||
curDate := utils.Time2Date(time.Now())
|
||||
orderman.FixedOrderManager.AmendMissingOrders(jxcontext.AdminCtx, []int{model.VendorIDJD, model.VendorIDMTWM, model.VendorIDEBAI, model.VendorIDDD}, 0, curDate.Add(-72*time.Hour), curDate, true, true)
|
||||
//只传toDate默认刷新toDate到5天以前的订单
|
||||
orderman.RefreshOrdersWithoutJxStoreID(jxcontext.AdminCtx, "", "", true, true)
|
||||
//禁用没有绑定的门店
|
||||
cms.DisabledStoreWithoutVendor(jxcontext.AdminCtx, true, true)
|
||||
}, dailyWorkTimeList)
|
||||
//}
|
||||
if beego.BConfig.RunMode == model.ServerTypeFruits /*|| beego.BConfig.RunMode == model.ServerTypePet*/ {
|
||||
ScheduleTimerFuncByInterval(func() {
|
||||
fromData := utils.Time2Date(time.Now())
|
||||
toData := time.Now()
|
||||
orderman.FixedOrderManager.AmendMissingOrders(jxcontext.AdminCtx, []int{model.VendorIDJD, model.VendorIDMTWM, model.VendorIDEBAI, model.VendorIDDD}, 0, fromData, toData, true, true)
|
||||
}, 5*time.Second, 5*time.Minute)
|
||||
}
|
||||
|
||||
ScheduleTimerFunc("doDailyWork5", func() {
|
||||
//刷新物料订单状态
|
||||
localjx.RefreshAllMatterOrderStatus(jxcontext.AdminCtx)
|
||||
//同步美团配送与否状态及美团门店是否存在
|
||||
//cms.SetMTPSStatus(jxcontext.AdminCtx, 0, 0)
|
||||
cms.SetMTPSStatus2(0)
|
||||
//售后单如果超过12小时没有审核,就自动通过
|
||||
//RefreshAfsOrderStatusAccess(jxcontext.AdminCtx)
|
||||
//刷新门店分组管理
|
||||
cms.RefreshStoreBind(jxcontext.AdminCtx)
|
||||
//更新所有门店的上下线状态
|
||||
cms.RefreshStoreIsOnline(jxcontext.AdminCtx)
|
||||
}, dailyWorkTimeList)
|
||||
ScheduleTimerFunc("RrefreshMtwmVendorAct", func() {
|
||||
//刷新美团平台活动
|
||||
act.RrefreshMtwmVendorAct(jxcontext.AdminCtx)
|
||||
//刷新饿百平台活动
|
||||
act.RrefreshEbaiVendorAct(jxcontext.AdminCtx)
|
||||
}, dailyWorkTimeList2)
|
||||
// 轮询每天更新当前时间一个月
|
||||
ScheduleTimerFunc("UpdateOrder2Complete", func() {
|
||||
delivery.UpdateOrder2Complete()
|
||||
}, []string{
|
||||
"04:00:00",
|
||||
})
|
||||
// 每两小时更新一下订单信息UpdateOrderStatus
|
||||
ScheduleTimerFuncByInterval(func() {
|
||||
bidaServer.UpdateOrderStatus()
|
||||
}, 5*time.Second, 2*time.Hour)
|
||||
}
|
||||
//update xuhang 2022/04/06用于同步京东数据以取代爬取订单 但由于京东的v2API已不支持手机号 因此以下代码暂时注释 后续接入虚拟号可再次open
|
||||
/* ScheduleTimerFuncByInterval(func() {
|
||||
jdshop.InitKey()
|
||||
}, 10*time.Second, 8*time.Hour)*/
|
||||
//此处需要新增一个message 存储操作 服务器启动的30s后开始执行 每10s刷新一次
|
||||
//进行一个JCQ队列定时任务执行
|
||||
/* ScheduleTimerFuncByInterval(func() {
|
||||
jcq.JCQSchedule()
|
||||
}, 10*time.Second, 10*time.Second)*/
|
||||
//ScheduleTimerFuncByInterval(func() {
|
||||
// jdslogin.RefreshQRCode()
|
||||
//}, 10*time.Second, 10*time.Minute)
|
||||
ScheduleTimerFunc("AutoSaleStoreSku", func() {
|
||||
cms.AutoSaleStoreSku(jxcontext.AdminCtx, nil, true)
|
||||
}, autoSaleStoreSkuTimeList)
|
||||
|
||||
// 菜市无聊信息同步到果园
|
||||
if beego.BConfig.RunMode == model.ServerTypeFruits {
|
||||
ScheduleTimerFunc("SyncMatterC4ToGy", func() {
|
||||
cms.SyncMatterC4ToGy(jxcontext.AdminCtx, true, true)
|
||||
}, dailyWorkTimeList)
|
||||
}
|
||||
if beego.BConfig.RunMode == "beta" {
|
||||
//ScheduleTimerFunc("CancelPayTimeOutOrder", func() {
|
||||
// localjx.CancelPayTimeOutOrder(jxcontext.AdminCtx)
|
||||
//}, cancelPayTimeOutOrderList)
|
||||
ScheduleTimerFunc("GetAndStoreCitiesShops", func() {
|
||||
netspider.GetAndStoreCitiesShops(jxcontext.AdminCtx, nil, nil, 0, 0, false, false)
|
||||
}, []string{
|
||||
"04:05:06",
|
||||
})
|
||||
//京东的订单信息解密密钥获取
|
||||
//ScheduleTimerFuncByInterval(func() {
|
||||
// jdshop.InitKey()
|
||||
//}, 10*time.Second, 8*time.Hour)
|
||||
ScheduleTimerFunc("ChangeJxPriceByDiscountAct", func() {
|
||||
act.ChangeJxPriceByDiscountAct(jxcontext.AdminCtx)
|
||||
}, discountActJxList)
|
||||
//ScheduleTimerFunc("CreateOrderByPriceDefend", func() {
|
||||
// localjx.CreateOrderByPriceDefend(jxcontext.AdminCtx)
|
||||
//}, []string{
|
||||
// "22:00:00",
|
||||
//})
|
||||
//刷新门店数据坐标等
|
||||
ScheduleTimerFunc("RefreshPageStore", func() {
|
||||
cms.RefreshPageStore()
|
||||
}, []string{
|
||||
"20:00:00",
|
||||
})
|
||||
}
|
||||
if configs, err := dao.QueryConfigs(dao.GetDB(), "ebaiStorePageCookie", model.ConfigTypeCookie, ""); err == nil {
|
||||
ebaiStorePageCookie = configs[0].Value
|
||||
}
|
||||
if configs, err := dao.QueryConfigs(dao.GetDB(), "mtwmCookieStr", model.ConfigTypeCookie, ""); err == nil {
|
||||
mtwmCookieStr = configs[0].Value
|
||||
}
|
||||
if configs, err := dao.QueryConfigs(dao.GetDB(), "mtpsStoreToken", model.ConfigTypeCookie, ""); err == nil {
|
||||
mtpsStoreToken = configs[0].Value
|
||||
}
|
||||
if configs, err := dao.QueryConfigs(dao.GetDB(), "jdStorePageCookie", model.ConfigTypeCookie, ""); err == nil {
|
||||
JdStorePageCookie = configs[0].Value
|
||||
}
|
||||
if configs, err := dao.QueryConfigs(dao.GetDB(), "jdStorePageEarning", model.ConfigTypeCookie, ""); err == nil {
|
||||
jdStorePageEarning = configs[0].Value
|
||||
}
|
||||
if configs, err := dao.QueryConfigs(dao.GetDB(), "jd2StorePageCookie", model.ConfigTypeCookie, ""); err == nil {
|
||||
jd2StorePageCookie = configs[0].Value
|
||||
}
|
||||
if configs, err := dao.QueryConfigs(dao.GetDB(), "feiePageCookie", model.ConfigTypeCookie, ""); err == nil {
|
||||
feiePageCookie = configs[0].Value
|
||||
}
|
||||
//if configs, err := dao.QueryConfigs(dao.GetDB(), "jdsCookie", model.ConfigTypeCookie, ""); err == nil {
|
||||
// jdsCookie = configs[0].Value
|
||||
// api.JdShopAPI.SetCookieWithStr(jdsCookie)
|
||||
//}
|
||||
//if configs, err := dao.QueryConfigs(dao.GetDB(), "yinbaoCookie", model.ConfigTypeCookie, ""); err == nil {
|
||||
// yinbaoCookie := configs[0].Value
|
||||
// api.YinBaoAPI.SetCookie(".POSPALAUTH30220", yinbaoCookie)
|
||||
//}
|
||||
if globals.Jd2OrgCode != "" {
|
||||
api.Jd2API.SetJdCookie(jd2StorePageCookie)
|
||||
}
|
||||
//api.EbaiAPI.SetCookie("PASSPORT_DELIMONT_TOKEN", ebaiStorePageCookieExdTOKEN)
|
||||
//api.EbaiAPI.SetCookie("WMUSS", ebaiStorePageCookieWMUSS)
|
||||
//api.EbaiAPI.SetCookie("WMSTOKEN", ebaiStorePageCookieWMSTOKEN)
|
||||
//api.Ebai2API.SetCookie("PASSPORT_DELIMONT_TOKEN", ebaiStorePageCookieExdTOKEN)
|
||||
//api.Ebai2API.SetCookie("WMUSS", ebaiStorePageCookieWMUSS2)
|
||||
//api.Ebai2API.SetCookie("WMSTOKEN", ebaiStorePageCookieWMSTOKEN2)
|
||||
api.EbaiAPI.SetCookieWithStr(ebaiStorePageCookie)
|
||||
api.MtwmAPI.SetCookieWithStr(mtwmCookieStr)
|
||||
api.MtpsAPI.SetCookie("token", mtpsStoreToken)
|
||||
//api.JdAPI.SetJdCookie(JdStorePageCookie)
|
||||
api.JdAPI.SetCookieWithStr(JdStorePageCookie)
|
||||
api.JdAPI.SetCookie("user", jdStorePageEarning)
|
||||
api.JdPageAPI.SetCookie(jdapi.AccessStorePageCookieName, JdStorePageCookie)
|
||||
api.JdPageAPI.SetCookie(jdapi.AccessStorePageCookieName2, JdStorePageCookie)
|
||||
api.FeieAPI.SetCookieWithStr(feiePageCookie)
|
||||
}
|
||||
|
||||
func syncStoreSku() {
|
||||
syncFlag := 0
|
||||
syncFlag |= model.SyncFlagPriceMask // SyncFlagSaleMask
|
||||
task := tasksch.NewParallelTask("同步京西与平台数据", nil, jxcontext.AdminCtx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
step := batchItemList[0].(int)
|
||||
errList := errlist.New()
|
||||
db := dao.GetDB()
|
||||
switch step {
|
||||
case 0:
|
||||
if beego.BConfig.RunMode != model.ServerTypeFruits && beego.BConfig.RunMode != model.ServerTypePet {
|
||||
errList.AddErr(cms.DeleteSkuNameExPrefixOverdue(db))
|
||||
errList.AddErr(cms.SetMultiStoreSkuSyncModifyStatus(db, partner.GetMultiStoreVendorIDs()))
|
||||
|
||||
_, err = cms.CurVendorSync.LoopMultiStoresVendors(jxcontext.AdminCtx, db, "同步多门店平台商品库", false, true,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
vendorInfo := batchItemList[0].(*cms.MultiStoreVendorInfo)
|
||||
_, err = cms.FullSyncVendorStuff(jxcontext.AdminCtx, task, 0, vendorInfo.VendorID, vendorInfo.OrgCode, false, true)
|
||||
return retVal, err
|
||||
})
|
||||
errList.AddErr(err)
|
||||
|
||||
_, err = cms.CurVendorSync.SyncStoresSkus2(jxcontext.AdminCtx, nil, 0, db, nil, nil, false, nil, []int{27379}, syncFlag, true, true)
|
||||
//_, err = cms.CurVendorSync.FullSyncStoresSkus(jxcontext.AdminCtx, db, partner.GetMultiStoreVendorIDs(), nil, false, []int{27379}, true, true)
|
||||
errList.AddErr(err)
|
||||
}
|
||||
case 1:
|
||||
//TODO 暂时不同步银豹(可能要从银豹到京西),2020-04-27
|
||||
//errList.AddErr(cms.SetSingleStoreSkuSyncModifyStatus(db, []int{1, 3}))
|
||||
|
||||
// errList.AddErr(cms.SetSingleStoreSkuSyncModifyStatus(db, partner.GetSingleStoreVendorIDs()))
|
||||
// _, err = cms.CurVendorSync.AmendAndPruneStoreStuff(jxcontext.AdminCtx, []int{1, 3}, nil, false, true, cms.AmendPruneAll, false)
|
||||
|
||||
// _, err = cms.CurVendorSync.AmendAndPruneStoreStuff(jxcontext.AdminCtx, partner.GetSingleStoreVendorIDs(), nil, false, true, cms.AmendPruneAll, false)
|
||||
errList.AddErr(err)
|
||||
|
||||
SaveImportantTaskID(TaskNameSyncStoreSku, SpecialTaskID)
|
||||
//taskID, err2 := cms.CurVendorSync.SyncStoresSkus2(jxcontext.AdminCtx, nil, 0, db, []int{1, 3}, nil, false, nil, nil, syncFlag, true, true)
|
||||
// taskID, err2 := cms.CurVendorSync.SyncStoresSkus2(jxcontext.AdminCtx, nil, 0, db, partner.GetSingleStoreVendorIDs(), nil, false, nil, nil, syncFlag, true, true)
|
||||
|
||||
//errList.AddErr(err2)
|
||||
//SaveImportantTaskID(TaskNameSyncStoreSku, taskID)
|
||||
}
|
||||
err = errList.GetErrListAsOne()
|
||||
return retVal, err
|
||||
}, []int{0, 1})
|
||||
tasksch.HandleTask(task, nil, true).Run()
|
||||
}
|
||||
|
||||
func syncStoreSkuTiktok() {
|
||||
//syncFlag := 0 | model.SyncFlagSaleMask
|
||||
syncFlag := 0
|
||||
task := tasksch.NewParallelTask("同步京西商品到抖音平台,方案二使用", nil, jxcontext.AdminCtx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
step := batchItemList[0].(int)
|
||||
errList := errlist.New()
|
||||
db := dao.GetDB()
|
||||
switch step {
|
||||
case 0:
|
||||
if beego.BConfig.RunMode != model.ServerTypeFruits && beego.BConfig.RunMode != model.ServerTypePet {
|
||||
_, err = cms.CurVendorSync.SyncStoresSkus2(jxcontext.AdminCtx, nil, 0, db, []int{model.VendorIDDD}, nil, false, nil, nil, syncFlag, true, true)
|
||||
errList.AddErr(err)
|
||||
}
|
||||
case 1:
|
||||
errList.AddErr(err)
|
||||
SaveImportantTaskID(TaskNameSyncStoreSku, SpecialTaskID)
|
||||
}
|
||||
err = errList.GetErrListAsOne()
|
||||
return retVal, err
|
||||
}, []int{0, 1})
|
||||
tasksch.HandleTask(task, nil, true).Run()
|
||||
}
|
||||
|
||||
// syncStoreSkuTao 同步商品到淘鲜达
|
||||
func syncStoreSkuTao() {
|
||||
syncFlag := 0
|
||||
task := tasksch.NewParallelTask("syncStoreSkuTao ", nil, jxcontext.AdminCtx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
step := batchItemList[0].(int)
|
||||
errList := errlist.New()
|
||||
db := dao.GetDB()
|
||||
switch step {
|
||||
case 0:
|
||||
_, err = cms.CurVendorSync.SyncStoresSkus2(jxcontext.AdminCtx, nil, 0, db, []int{model.VendorIDTaoVegetable}, nil, false, nil, nil, syncFlag, true, true)
|
||||
errList.AddErr(err)
|
||||
case 1:
|
||||
SaveImportantTaskID(TaskNameSyncStoreSku, SpecialTaskID)
|
||||
}
|
||||
err = errList.GetErrListAsOne()
|
||||
return retVal, err
|
||||
}, []int{0, 1})
|
||||
tasksch.HandleTask(task, nil, true).Run()
|
||||
}
|
||||
|
||||
func doDailyWork2() {
|
||||
if beego.BConfig.RunMode == "jxgy" {
|
||||
syncStoreSku()
|
||||
refreshPointOrderNewEarningPrice()
|
||||
}
|
||||
//同步京东商城门店的商品
|
||||
// cms.CurVendorSync.SyncJdsStoresSkus(jxcontext.AdminCtx, nil, true, true)
|
||||
//刷新京东商城的门店库存
|
||||
// cms.SyncJdsStoreStock(jxcontext.AdminCtx, true, true)
|
||||
}
|
||||
|
||||
func doDailyWork() {
|
||||
//同步商品额外前缀和水印图(打标记)
|
||||
cms.SyncSkuExperfixAndWatermark(jxcontext.AdminCtx)
|
||||
|
||||
dao.SetStoresMapSyncStatus(dao.GetDB(), nil, nil, model.SyncFlagStoreStatus)
|
||||
cms.CurVendorSync.SyncStore2(jxcontext.AdminCtx, dao.GetDB(), []int{model.VendorIDMTWM, model.VendorIDJD, model.VendorIDEBAI}, nil, true, true)
|
||||
|
||||
if beego.BConfig.RunMode == "prod" {
|
||||
syncStoreSku()
|
||||
}
|
||||
InitEx()
|
||||
cms.SyncStoresCourierInfo(jxcontext.AdminCtx, nil, false, true)
|
||||
netprinter.RebindAllPrinters(jxcontext.AdminCtx, false, true)
|
||||
|
||||
// 每天补全前一天与当天的订单
|
||||
// curDate := utils.Time2Date(time.Now())
|
||||
// orderman.FixedOrderManager.AmendMissingOrders(jxcontext.AdminCtx, nil, 0, curDate.Add(-72*time.Hour), curDate, true, true)
|
||||
//订单门店归属补漏
|
||||
//fromDate, toDate都不传默认刷新当前天5天以前的订单,只传fromDate默认刷新fromDate到当天的订单
|
||||
//只传toDate默认刷新toDate到5天以前的订单
|
||||
orderman.RefreshOrdersWithoutJxStoreID(jxcontext.AdminCtx, "", "", true, true)
|
||||
//刷新京东门店的等级
|
||||
// cms.RefreshJdLevel(jxcontext.AdminCtx)
|
||||
//删除操作日志
|
||||
// event.DeleteOperateEventAndDetail(jxcontext.AdminCtx, time.Now().AddDate(0, -3, 0))
|
||||
//禁用没有绑定的门店
|
||||
cms.DisabledStoreWithoutVendor(jxcontext.AdminCtx, true, true)
|
||||
//刷新物料订单状态
|
||||
localjx.RefreshAllMatterOrderStatus(jxcontext.AdminCtx)
|
||||
//同步银豹到京西
|
||||
// cms.CurVendorSync.SyncStoreSkusFromYb(jxcontext.AdminCtx, nil, true, true)
|
||||
//同步上架京东商城待售商品
|
||||
// cms.RefreshJdsSkusStatus(jxcontext.AdminCtx)
|
||||
//同步美团配送与否状态及美团门店是否存在
|
||||
cms.SetMTPSStatus(jxcontext.AdminCtx, 0, 0)
|
||||
//售后单如果超过12小时没有审核,就自动通过
|
||||
//RefreshAfsOrderStatusAccess(jxcontext.AdminCtx)
|
||||
//刷新京东商城订单结算价
|
||||
orderman.RefreshJdShopOrdersEarningPrice(jxcontext.AdminCtx, utils.Time2Str(time.Now().AddDate(0, 0, -2)), utils.Time2Str(time.Now()))
|
||||
//刷新门店分组管理
|
||||
cms.RefreshStoreBind(jxcontext.AdminCtx)
|
||||
//刷新京东会员
|
||||
report.RefreshJDMembers(jxcontext.AdminCtx)
|
||||
}
|
||||
|
||||
func refreshPointOrderNewEarningPrice() {
|
||||
var (
|
||||
db = dao.GetDB()
|
||||
orders []*model.GoodsOrder
|
||||
)
|
||||
sql := `
|
||||
SELECT * FROM goods_order WHERE earning_type = 2 AND status = 110 AND order_created_at > ?
|
||||
`
|
||||
sqlParams := []interface{}{time.Now().AddDate(0, 0, -1)}
|
||||
dao.GetRows(db, &orders, sql, sqlParams)
|
||||
if len(orders) > 0 {
|
||||
for _, v := range orders {
|
||||
if v.NewEarningPrice == 0 {
|
||||
v.NewEarningPrice = int64(int(v.TotalShopMoney) * (100 - v.OrderPayPercentage/2) / 100)
|
||||
dao.UpdateEntity(db, v, "NewEarningPrice")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//func RefreshAfsOrderStatusAccess(ctx *jxcontext.Context) {
|
||||
// var (
|
||||
// offset = 0
|
||||
// pageSize = 9999
|
||||
// db = dao.GetDB()
|
||||
// )
|
||||
// afsOrderList, _, err := dao.GetAfsOrdersByPage(db, "", "", "", time.Now().AddDate(0, 0, -7), time.Now(), offset, pageSize)
|
||||
// if err != nil {
|
||||
// return
|
||||
// }
|
||||
// for _, v := range afsOrderList {
|
||||
// if v.Status == model.AfsOrderStatusWait4Approve && time.Now().Sub(v.AfsCreatedAt).Hours() > 12 {
|
||||
// defsch.FixedScheduler.AgreeOrRefuseRefund(ctx, v.AfsOrderID, v.VendorID, model.AfsTypePartRefund, "超时系统同意")
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
func RefreshRealMobile(ctx *jxcontext.Context, vendorID int, fromTime, toTime time.Time, isAsync, isContinueWhenError bool) (hint string, err error) {
|
||||
handler := partner.GetPurchasePlatformFromVendorID(vendorID)
|
||||
if handler == nil {
|
||||
return "", fmt.Errorf("不合法的vendorID:%d", vendorID)
|
||||
}
|
||||
sql := `
|
||||
SELECT *
|
||||
FROM goods_order
|
||||
WHERE vendor_id = ? AND consignee_mobile2 = ''
|
||||
`
|
||||
sqlParams := []interface{}{
|
||||
vendorID,
|
||||
}
|
||||
if !utils.IsTimeZero(fromTime) {
|
||||
sql += " AND order_created_at >= ?"
|
||||
sqlParams = append(sqlParams, fromTime)
|
||||
}
|
||||
if !utils.IsTimeZero(toTime) {
|
||||
sql += " AND order_created_at <= ?"
|
||||
sqlParams = append(sqlParams, toTime)
|
||||
}
|
||||
var orderList []*model.GoodsOrder
|
||||
db := dao.GetDB()
|
||||
if err = dao.GetRows(db, &orderList, sql, sqlParams...); err == nil && len(orderList) > 0 {
|
||||
task := tasksch.NewParallelTask("misc RefreshRealMobile", tasksch.NewParallelConfig().SetIsContinueWhenError(isContinueWhenError), ctx,
|
||||
func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
order := batchItemList[0].(*model.GoodsOrder)
|
||||
mobile, err2 := handler.GetOrderRealMobile(ctx, order)
|
||||
if err = err2; err == nil {
|
||||
//mobile = jxutils.FormalizeMobile(mobile)
|
||||
//if jxutils.IsStringLikeMobile(mobile) && strings.Index(order.ConsigneeMobile, mobile) == -1 {
|
||||
order.ConsigneeMobile2 = mobile
|
||||
_, err = dao.UpdateEntity(db, order, "ConsigneeMobile2")
|
||||
//}
|
||||
} else {
|
||||
globals.SugarLogger.Infof("RefreshRealMobile orderID:%s failed with error:%v", order.VendorOrderID, err)
|
||||
}
|
||||
return nil, err
|
||||
}, orderList)
|
||||
tasksch.HandleTask(task, nil, true).Run()
|
||||
hint = task.ID
|
||||
if !isAsync {
|
||||
_, err = task.GetResult(0)
|
||||
}
|
||||
}
|
||||
return hint, err
|
||||
globals.SugarLogger.Debug("doDailyWork")
|
||||
//刷新任务过期状态
|
||||
cms.RefreshJobStatus(jxcontext.AdminCtx)
|
||||
//刷新任务标签状态
|
||||
cms.RefreshJobSpan(jxcontext.AdminCtx)
|
||||
//刷新用户会员时间
|
||||
cms.RefreshUserMemberStatus(jxcontext.AdminCtx)
|
||||
//删除聊天记录
|
||||
event.DeleteMessageRecord(jxcontext.AdminCtx)
|
||||
//自动确认收货(刷新状态)
|
||||
cms.RefreshDropShippingJob(jxcontext.AdminCtx)
|
||||
//刷新京东快递
|
||||
cms.RefreshJdDelivery(jxcontext.AdminCtx)
|
||||
//美团联盟活动自动创建
|
||||
cms.MtUnionJobAutoUpdate(jxcontext.AdminCtx)
|
||||
}
|
||||
|
||||
// 按时间序列循环
|
||||
@@ -827,7 +78,9 @@ func ScheduleTimerFunc(name string, handler func(), timeList []string) {
|
||||
now := time.Now()
|
||||
nextTime := jxutils.GetNextTimeFromList(now, timeList)
|
||||
duration := nextTime.Sub(now) + 1*time.Second
|
||||
globals.SugarLogger.Debugf("ScheduleTimerFunc, func:%s, duration:%v", name, duration)
|
||||
utils.AfterFuncWithRecover(duration, func() {
|
||||
globals.SugarLogger.Debugf("ScheduleTimerFunc func:%s", name)
|
||||
handler()
|
||||
ScheduleTimerFunc(name, handler, timeList)
|
||||
})
|
||||
@@ -838,12 +91,15 @@ func ScheduleTimerFuncOnce(name string, handler func(interface{}), timeStr strin
|
||||
now := time.Now()
|
||||
nextTime := jxutils.GetNextTimeFromList(now, []string{timeStr})
|
||||
duration := nextTime.Sub(now) + 1*time.Second
|
||||
globals.SugarLogger.Debugf("ScheduleTimerFuncOnce, func:%s, duration:%v", name, duration)
|
||||
utils.AfterFuncWithRecover(duration, func() {
|
||||
globals.SugarLogger.Debugf("ScheduleTimerFuncOnce func:%s", name)
|
||||
handler(param)
|
||||
})
|
||||
}
|
||||
|
||||
func ScheduleTimerFuncByInterval(handler func(), delay, inerval time.Duration) {
|
||||
globals.SugarLogger.Debugf("ScheduleTimerFuncByInterval, delay:%v, inerval:%v", delay, inerval)
|
||||
utils.AfterFuncWithRecover(delay, func() {
|
||||
beginTime := time.Now()
|
||||
handler()
|
||||
|
||||
@@ -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,18 +0,0 @@
|
||||
package misc
|
||||
|
||||
import (
|
||||
"git.rosy.net.cn/jx-callback/business/jxstore/cms"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"testing"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
)
|
||||
|
||||
func TestStartOrEndOpStore(t *testing.T) {
|
||||
StartOrEndOpStore(jxcontext.AdminCtx, true, nil, nil, 0, 0, false, true)
|
||||
}
|
||||
|
||||
func TestIssny(t *testing.T) {
|
||||
cms.CurVendorSync.SyncStore2(jxcontext.AdminCtx, dao.GetDB(), []int{model.VendorIDMTWM, model.VendorIDJD, model.VendorIDEBAI}, nil, true, true)
|
||||
}
|
||||
@@ -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,903 +0,0 @@
|
||||
package misc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"reflect"
|
||||
"sort"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"git.rosy.net.cn/baseapi"
|
||||
"git.rosy.net.cn/baseapi/utils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxstore/cms"
|
||||
"git.rosy.net.cn/jx-callback/business/jxstore/permission"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
|
||||
"git.rosy.net.cn/jx-callback/business/model"
|
||||
"git.rosy.net.cn/jx-callback/business/model/dao"
|
||||
"git.rosy.net.cn/jx-callback/globals"
|
||||
"git.rosy.net.cn/jx-callback/globals/refutil"
|
||||
)
|
||||
|
||||
const (
|
||||
EnableScheduleScoreStore = true
|
||||
ParallelCount = 1
|
||||
|
||||
GoldMedalScore = 90
|
||||
SilverMedalScore = 80
|
||||
BronzeMedalScore = 70
|
||||
GoldMedalLevel = 1
|
||||
SilverMedalLevel = 2
|
||||
BronzeMedalLevel = 3
|
||||
|
||||
ItemTotalScore = 10
|
||||
|
||||
StoreOpenTimeNormalTime = 12.0 //小时
|
||||
SaleSkuNormalCount = 1000 //数量
|
||||
SaleSkuScorePerUnit = float64(ItemTotalScore) / SaleSkuNormalCount //分数
|
||||
PromotionSkuNormalCount = 20 //数量
|
||||
AveragePickupTimeNormalTime = 10.0 //分钟
|
||||
BadCommentOrderNormalRatio = 0.2 //百分比
|
||||
UnfinishOrderNormalRatio = 1.0 //百分比
|
||||
AbsentGoodsOrderNormalRatio = 1.0 //百分比
|
||||
StoreRangeGoodRadius = 2.0 //千米
|
||||
StoreRangeBadRadius = 1.0 //千米
|
||||
SaleSkuPriceRatio = 90 //千米
|
||||
SaleSkuCheckRange = 5.0 //千米
|
||||
|
||||
WeekNum = 5 //得到门店近期周的数量
|
||||
)
|
||||
|
||||
var (
|
||||
scoreStoreTimeList = []string{
|
||||
"23:00:00",
|
||||
}
|
||||
scoreStoreCheckTimeEnd = "23:30:00"
|
||||
fullVendorList = map[int]bool{
|
||||
model.VendorIDJD: true,
|
||||
model.VendorIDMTWM: true,
|
||||
model.VendorIDEBAI: true,
|
||||
}
|
||||
storeScoreFieldName = []string{
|
||||
model.FieldStoreOpenTime,
|
||||
model.FieldSaleSkuCount,
|
||||
model.FieldAveragePickupTime,
|
||||
model.FieldBadCommentOrder,
|
||||
model.FieldUnfinishOrder,
|
||||
model.FieldAbsentGoodsOrder,
|
||||
model.FieldPromotionSku,
|
||||
model.FieldFullVendor,
|
||||
model.FieldStoreRange,
|
||||
model.FieldSaleSkuPrice,
|
||||
}
|
||||
|
||||
storeScoreDataWrapper StoreScoreDataWrapper
|
||||
allStoreSkusWrapper AllStoreSkusWrapper
|
||||
scoreDate time.Time
|
||||
isScoring bool
|
||||
)
|
||||
|
||||
type AllStoreSkusWrapper struct {
|
||||
allStoreSkus map[int]map[int]int
|
||||
locker sync.RWMutex
|
||||
}
|
||||
|
||||
func (a *AllStoreSkusWrapper) InitData() {
|
||||
a.allStoreSkus = make(map[int]map[int]int)
|
||||
}
|
||||
|
||||
func (a *AllStoreSkusWrapper) ClearData() {
|
||||
a.allStoreSkus = nil
|
||||
}
|
||||
|
||||
func (a *AllStoreSkusWrapper) SetData(storeID int, skuMapData map[int]int) {
|
||||
a.locker.Lock()
|
||||
defer a.locker.Unlock()
|
||||
a.allStoreSkus[storeID] = skuMapData
|
||||
}
|
||||
|
||||
func (a *AllStoreSkusWrapper) GetData(storeID int) map[int]int {
|
||||
a.locker.RLock()
|
||||
defer a.locker.RUnlock()
|
||||
return a.allStoreSkus[storeID]
|
||||
}
|
||||
|
||||
type StoreScoreDataWrapper struct {
|
||||
storeScoreData map[int]*model.StoreScore
|
||||
dailyBadCommentOrderCount map[int]int
|
||||
dailyUnFinishOrderCount map[int]int
|
||||
dailyFinishOrderCount map[int]int
|
||||
dailyAbsentGoodsOrderCount map[int]int
|
||||
locker sync.RWMutex
|
||||
}
|
||||
|
||||
func (s *StoreScoreDataWrapper) InitData() {
|
||||
s.storeScoreData = make(map[int]*model.StoreScore)
|
||||
s.dailyBadCommentOrderCount = make(map[int]int)
|
||||
s.dailyUnFinishOrderCount = make(map[int]int)
|
||||
s.dailyFinishOrderCount = make(map[int]int)
|
||||
s.dailyAbsentGoodsOrderCount = make(map[int]int)
|
||||
}
|
||||
|
||||
func (s *StoreScoreDataWrapper) ClearData() {
|
||||
s.storeScoreData = nil
|
||||
s.dailyBadCommentOrderCount = nil
|
||||
s.dailyUnFinishOrderCount = nil
|
||||
s.dailyFinishOrderCount = nil
|
||||
s.dailyAbsentGoodsOrderCount = nil
|
||||
}
|
||||
|
||||
func (s *StoreScoreDataWrapper) SetData(storeID int, valueName string, value int) {
|
||||
s.locker.Lock()
|
||||
defer s.locker.Unlock()
|
||||
data := s.storeScoreData[storeID]
|
||||
if data == nil {
|
||||
data = &model.StoreScore{}
|
||||
data.StoreID = storeID
|
||||
data.ScoreDate = scoreDate
|
||||
s.storeScoreData[storeID] = data
|
||||
}
|
||||
valueInfo := reflect.ValueOf(data).Elem()
|
||||
valueInfo.FieldByName(valueName).SetInt(int64(value))
|
||||
}
|
||||
|
||||
func (s *StoreScoreDataWrapper) SetDailyBadCommentOrderCount(storeCountList []*model.StoreCount) {
|
||||
s.locker.Lock()
|
||||
defer s.locker.Unlock()
|
||||
for _, value := range storeCountList {
|
||||
s.dailyBadCommentOrderCount[value.StoreID] = value.Count
|
||||
}
|
||||
}
|
||||
|
||||
func (s *StoreScoreDataWrapper) GetDailyBadCommentOrderCount(storeID int) int {
|
||||
s.locker.RLock()
|
||||
defer s.locker.RUnlock()
|
||||
if count, ok := s.dailyBadCommentOrderCount[storeID]; ok {
|
||||
return count
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func (s *StoreScoreDataWrapper) SetDailyUnFinishOrderCount(storeCountList []*model.StoreCount) {
|
||||
for _, value := range storeCountList {
|
||||
s.dailyUnFinishOrderCount[value.StoreID] = value.Count
|
||||
}
|
||||
}
|
||||
|
||||
func (s *StoreScoreDataWrapper) GetDailyUnFinishOrderCount(storeID int) int {
|
||||
s.locker.RLock()
|
||||
defer s.locker.RUnlock()
|
||||
if count, ok := s.dailyUnFinishOrderCount[storeID]; ok {
|
||||
return count
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func (s *StoreScoreDataWrapper) SetDailyFinishOrderCount(storeCountList []*model.StoreCount) {
|
||||
for _, value := range storeCountList {
|
||||
s.dailyFinishOrderCount[value.StoreID] = value.Count
|
||||
}
|
||||
}
|
||||
|
||||
func (s *StoreScoreDataWrapper) GetDailyFinishOrderCount(storeID int) int {
|
||||
s.locker.RLock()
|
||||
defer s.locker.RUnlock()
|
||||
if count, ok := s.dailyFinishOrderCount[storeID]; ok {
|
||||
return count
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func (s *StoreScoreDataWrapper) SetDailyAbsentGoodsOrderCount(storeCountList []*model.StoreCount) {
|
||||
for _, value := range storeCountList {
|
||||
s.dailyAbsentGoodsOrderCount[value.StoreID] = value.Count
|
||||
}
|
||||
}
|
||||
|
||||
func (s *StoreScoreDataWrapper) GetDailyAbsentGoodsOrderCount(storeID int) int {
|
||||
s.locker.RLock()
|
||||
defer s.locker.RUnlock()
|
||||
if count, ok := s.dailyAbsentGoodsOrderCount[storeID]; ok {
|
||||
return count
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func (s *StoreScoreDataWrapper) InsertStoreScore() {
|
||||
for _, value := range s.storeScoreData {
|
||||
dao.InsertStoreScore(value)
|
||||
}
|
||||
}
|
||||
|
||||
//得到所有门店的可售商品(优化内存,只存商品的价格)
|
||||
func GetAllStoreSkus(ctx *jxcontext.Context, parentTask tasksch.ITask, storeList []*cms.StoreExt) {
|
||||
allStoreSkusWrapper.InitData()
|
||||
taskFunc := func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
storeInfo := batchItemList[0].(*cms.StoreExt)
|
||||
storeID := storeInfo.ID
|
||||
if jxSkuInfoData, err2 := cms.GetStoreSkus(ctx, storeID, []int{}, true, "", true, false, map[string]interface{}{}, 0, -1); jxSkuInfoData != nil {
|
||||
jxSkuPriceMapData := make(map[int]int)
|
||||
for _, value := range jxSkuInfoData.SkuNames {
|
||||
for _, skuInfo := range value.Skus {
|
||||
saleStatus := jxutils.MergeSkuStatus(skuInfo.SkuStatus, skuInfo.StoreSkuStatus)
|
||||
if saleStatus == model.SkuStatusNormal {
|
||||
jxSkuPriceMapData[skuInfo.SkuID] = skuInfo.BindPrice
|
||||
}
|
||||
}
|
||||
}
|
||||
allStoreSkusWrapper.SetData(storeID, jxSkuPriceMapData)
|
||||
} else {
|
||||
globals.SugarLogger.Warnf("store_score.GetAllStoreSkus %d return empty, err:%v", storeID, err2)
|
||||
}
|
||||
return retVal, err
|
||||
}
|
||||
taskParallel := tasksch.NewParallelTask("得到所有门店商品", tasksch.NewParallelConfig().SetParallelCount(ParallelCount), ctx, taskFunc, storeList)
|
||||
tasksch.HandleTask(taskParallel, parentTask, true).Run()
|
||||
taskParallel.GetResult(0)
|
||||
}
|
||||
|
||||
func GetOpenTime(opTimeList []int16) (opTime float64) {
|
||||
opTime = 0
|
||||
for index, _ := range opTimeList {
|
||||
if index%2 == 1 {
|
||||
endTime := opTimeList[index]
|
||||
startTime := opTimeList[index-1]
|
||||
diffHour := float64(endTime/100 - startTime/100)
|
||||
diffMin := float64(endTime%100-startTime%100) / 60
|
||||
opTime += diffHour + diffMin
|
||||
}
|
||||
}
|
||||
return opTime
|
||||
}
|
||||
|
||||
//营业时间12小时及以上满分,总分10分,每少一个小时扣1分
|
||||
func ScoreStoreOpenTime(storeInfo *cms.StoreExt) {
|
||||
storeID := storeInfo.ID
|
||||
storeStatus := storeInfo.Status
|
||||
isStoreOpen := storeStatus == model.StoreStatusOpened
|
||||
finalScore := 0
|
||||
if isStoreOpen {
|
||||
for _, storeMap := range storeInfo.StoreMaps {
|
||||
isSyncStoreSku := storeMap.IsSync
|
||||
vendorStoreStatus := storeMap.Status
|
||||
isVendorStoreOpen := vendorStoreStatus == model.StoreStatusOpened
|
||||
opTimeList := storeInfo.GetOpTimeList()
|
||||
if len(opTimeList) > 0 && isStoreOpen && isVendorStoreOpen && isSyncStoreSku != 0 {
|
||||
opTime := GetOpenTime(opTimeList)
|
||||
if opTime >= StoreOpenTimeNormalTime {
|
||||
finalScore = ItemTotalScore
|
||||
} else {
|
||||
decScore := int(math.Round(StoreOpenTimeNormalTime - opTime))
|
||||
finalScore = ItemTotalScore - decScore
|
||||
if finalScore < 0 {
|
||||
finalScore = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
storeScoreDataWrapper.SetData(storeID, model.FieldStoreOpenTime, finalScore)
|
||||
}
|
||||
|
||||
//可售商品数量大于1000,总分10分,按比例扣
|
||||
func ScoreSaleSkuCount(storeInfo *cms.StoreExt) {
|
||||
storeID := storeInfo.ID
|
||||
skusMapData := allStoreSkusWrapper.GetData(storeID)
|
||||
finalScore := 0
|
||||
if len(skusMapData) > 0 {
|
||||
saleSkuCount := len(skusMapData)
|
||||
finalScore = int(math.Round(float64(saleSkuCount) * SaleSkuScorePerUnit))
|
||||
if finalScore > ItemTotalScore {
|
||||
finalScore = ItemTotalScore
|
||||
}
|
||||
}
|
||||
storeScoreDataWrapper.SetData(storeID, model.FieldSaleSkuCount, finalScore)
|
||||
}
|
||||
|
||||
//平均捡货时间小于等于拣货截止时间为10分满分,每超出1分钟,减1分
|
||||
func ScoreAveragePickupTime(storeInfo *cms.StoreExt) {
|
||||
storeID := storeInfo.ID
|
||||
db := dao.GetDB()
|
||||
orderList, err := dao.GetDailyFinishOrderList(db, storeID, scoreDate)
|
||||
orderListCount := len(orderList)
|
||||
finalScore := 0
|
||||
if err == nil && orderListCount > 0 {
|
||||
totalScore := 0
|
||||
for _, value := range orderList {
|
||||
statusTime := value.StatusTime.Unix()
|
||||
pickDeadline := value.PickDeadline.Unix()
|
||||
if statusTime <= pickDeadline {
|
||||
totalScore += ItemTotalScore
|
||||
} else {
|
||||
decScore := int(math.Round(float64(statusTime-pickDeadline) / 60))
|
||||
tempScore := ItemTotalScore - decScore
|
||||
if tempScore < 0 {
|
||||
tempScore = 0
|
||||
}
|
||||
totalScore += tempScore
|
||||
}
|
||||
}
|
||||
finalScore = totalScore / orderListCount
|
||||
}
|
||||
storeScoreDataWrapper.SetData(storeID, model.FieldAveragePickupTime, finalScore)
|
||||
}
|
||||
|
||||
//差评订单和完成订单比例小于0.2%,得满分10分,每增加0.1%减1分
|
||||
func ScoreBadCommentOrder(storeInfo *cms.StoreExt) {
|
||||
storeID := storeInfo.ID
|
||||
badCommentOrderCount := storeScoreDataWrapper.GetDailyBadCommentOrderCount(storeID)
|
||||
finishOrderCount := storeScoreDataWrapper.GetDailyFinishOrderCount(storeID)
|
||||
finalScore := 0
|
||||
if finishOrderCount > 0 {
|
||||
badCommentOrderRatio := float64(badCommentOrderCount) * 100 / float64(finishOrderCount)
|
||||
if badCommentOrderRatio <= BadCommentOrderNormalRatio {
|
||||
finalScore = ItemTotalScore
|
||||
} else {
|
||||
decScore := int(math.Round((badCommentOrderRatio - BadCommentOrderNormalRatio) / 0.1))
|
||||
finalScore = ItemTotalScore - decScore
|
||||
if finalScore < 0 {
|
||||
finalScore = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
storeScoreDataWrapper.SetData(storeID, model.FieldBadCommentOrder, finalScore)
|
||||
}
|
||||
|
||||
//未完成订单和完成订单比小于1%,得满分10分,比例每增加5%,分数减1
|
||||
func ScoreUnfinishOrder(storeInfo *cms.StoreExt) {
|
||||
storeID := storeInfo.ID
|
||||
unFinishOrderCount := storeScoreDataWrapper.GetDailyUnFinishOrderCount(storeID)
|
||||
finishOrderCount := storeScoreDataWrapper.GetDailyFinishOrderCount(storeID)
|
||||
finalScore := 0
|
||||
if finishOrderCount > 0 {
|
||||
unfinishOrderRatio := float64(unFinishOrderCount) * 100 / float64(finishOrderCount)
|
||||
if unfinishOrderRatio <= UnfinishOrderNormalRatio {
|
||||
finalScore = ItemTotalScore
|
||||
} else {
|
||||
decScore := int(math.Round((unfinishOrderRatio - UnfinishOrderNormalRatio) / 5))
|
||||
finalScore = ItemTotalScore - decScore
|
||||
if finalScore < 0 {
|
||||
finalScore = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
storeScoreDataWrapper.SetData(storeID, model.FieldUnfinishOrder, finalScore)
|
||||
}
|
||||
|
||||
//缺货订单和完成订单比小于1%得10分,比例每增加0.1%减1分
|
||||
func ScoreAbsentGoodsOrder(storeInfo *cms.StoreExt) {
|
||||
storeID := storeInfo.ID
|
||||
absentGoodsOrderCount := storeScoreDataWrapper.GetDailyAbsentGoodsOrderCount(storeID)
|
||||
finishOrderCount := storeScoreDataWrapper.GetDailyFinishOrderCount(storeID)
|
||||
finalScore := 0
|
||||
if finishOrderCount > 0 {
|
||||
absentGoodsOrderRatio := float64(absentGoodsOrderCount) * 100 / float64(finishOrderCount)
|
||||
if absentGoodsOrderRatio <= AbsentGoodsOrderNormalRatio {
|
||||
finalScore = ItemTotalScore
|
||||
} else {
|
||||
decScore := int(math.Round((absentGoodsOrderRatio - AbsentGoodsOrderNormalRatio) / 0.1))
|
||||
finalScore = ItemTotalScore - decScore
|
||||
if finalScore < 0 {
|
||||
finalScore = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
storeScoreDataWrapper.SetData(storeID, model.FieldAbsentGoodsOrder, finalScore)
|
||||
}
|
||||
|
||||
//促销品数量20个以上为满分10分,每少2个扣1分
|
||||
func ScorePromotionSku(storeInfo *cms.StoreExt) {
|
||||
storeID := storeInfo.ID
|
||||
db := dao.GetDB()
|
||||
beginTime := time.Now()
|
||||
endTime := time.Now()
|
||||
actStoreSkuList, err := dao.GetEffectiveActStoreSkuInfo(db, -1, nil, model.ActTypeAll, []int{storeID}, nil, beginTime, endTime)
|
||||
finalScore := 0
|
||||
if err == nil && len(actStoreSkuList) > 0 {
|
||||
actStoreSkuMap := make(map[int]int)
|
||||
for _, value := range actStoreSkuList {
|
||||
if value.Type != model.ActSkuFake {
|
||||
actStoreSkuMap[value.SkuID] = 1
|
||||
}
|
||||
}
|
||||
promotionSkuCount := len(actStoreSkuMap)
|
||||
if promotionSkuCount >= PromotionSkuNormalCount {
|
||||
finalScore = ItemTotalScore
|
||||
} else {
|
||||
decScore := (PromotionSkuNormalCount - promotionSkuCount) / 2
|
||||
finalScore = ItemTotalScore - decScore
|
||||
if finalScore < 0 {
|
||||
finalScore = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
storeScoreDataWrapper.SetData(storeID, model.FieldPromotionSku, finalScore)
|
||||
}
|
||||
|
||||
//经营全平台满分10分,每少一个平台扣2分(一个平台没有得0分)
|
||||
func ScoreFullVendor(storeInfo *cms.StoreExt) {
|
||||
fullVendorCount := len(fullVendorList)
|
||||
finalScore := 0
|
||||
storeID := storeInfo.ID
|
||||
storeStatus := storeInfo.Status
|
||||
isStoreOpen := storeStatus == model.StoreStatusOpened
|
||||
count := 0
|
||||
for _, storeMap := range storeInfo.StoreMaps {
|
||||
isSyncStoreSku := storeMap.IsSync
|
||||
vendorStoreStatus := storeMap.Status
|
||||
isVendorStoreOpen := vendorStoreStatus == model.StoreStatusOpened
|
||||
opTimeList := storeInfo.GetOpTimeList()
|
||||
if len(opTimeList) > 0 && isStoreOpen && isVendorStoreOpen && isSyncStoreSku != 0 {
|
||||
count++
|
||||
}
|
||||
}
|
||||
if count > 0 {
|
||||
if count == fullVendorCount {
|
||||
finalScore = ItemTotalScore
|
||||
} else {
|
||||
decScore := (fullVendorCount - count) * 2
|
||||
finalScore = ItemTotalScore - decScore
|
||||
}
|
||||
}
|
||||
storeScoreDataWrapper.SetData(storeID, model.FieldFullVendor, finalScore)
|
||||
}
|
||||
|
||||
//经营范围面积大于半径2km的圆得满分10分,低于1km得分0
|
||||
func ScoreStoreRange(storeInfo *cms.StoreExt) {
|
||||
finalScore := 0
|
||||
storeID := storeInfo.ID
|
||||
if storeInfo.DeliveryRangeType == model.DeliveryRangeTypePolygon {
|
||||
if storeInfo.DeliveryRange != "" {
|
||||
points := jxutils.CoordinateStr2Points(storeInfo.DeliveryRange)
|
||||
area := jxutils.CalcPolygonAreaAutonavi(points)
|
||||
goodArea := math.Pi * StoreRangeGoodRadius * StoreRangeGoodRadius
|
||||
badArea := math.Pi * StoreRangeBadRadius * StoreRangeBadRadius
|
||||
if area >= goodArea {
|
||||
finalScore = ItemTotalScore
|
||||
} else if area <= badArea {
|
||||
finalScore = 0
|
||||
} else {
|
||||
diff := goodArea - area
|
||||
ratio := float64(ItemTotalScore) / (goodArea - badArea)
|
||||
finalScore = ItemTotalScore - int(math.Round(diff*ratio))
|
||||
}
|
||||
}
|
||||
} else if storeInfo.DeliveryRangeType == model.DeliveryRangeTypeRadius {
|
||||
deliveryRadius := utils.Str2Float64WithDefault(storeInfo.DeliveryRange, 0) / 1000
|
||||
if deliveryRadius >= StoreRangeGoodRadius {
|
||||
finalScore = ItemTotalScore
|
||||
} else if deliveryRadius <= StoreRangeBadRadius {
|
||||
finalScore = 0
|
||||
} else {
|
||||
diff := StoreRangeGoodRadius - deliveryRadius
|
||||
ratio := float64(ItemTotalScore) / (StoreRangeGoodRadius - StoreRangeBadRadius)
|
||||
finalScore = ItemTotalScore - int(math.Round(diff*ratio))
|
||||
}
|
||||
}
|
||||
if finalScore < 0 {
|
||||
finalScore = 0
|
||||
} else if finalScore > ItemTotalScore {
|
||||
finalScore = ItemTotalScore
|
||||
}
|
||||
storeScoreDataWrapper.SetData(storeID, model.FieldStoreRange, finalScore)
|
||||
}
|
||||
|
||||
//得到距离某个门店多少KM内的所有门店信息
|
||||
func GetRangeStoreList(storeID int, lng, lat, checkRange float64, storeList []*cms.StoreExt) (outStoreList []*cms.StoreExt) {
|
||||
for _, storeInfo := range storeList {
|
||||
if storeInfo.ID == storeID {
|
||||
outStoreList = append(outStoreList, storeInfo)
|
||||
} else {
|
||||
distance := jxutils.EarthDistance(lng, lat, storeInfo.FloatLng, storeInfo.FloatLat)
|
||||
if distance <= checkRange {
|
||||
outStoreList = append(outStoreList, storeInfo)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return outStoreList
|
||||
}
|
||||
|
||||
//得到给定门店列表里的同一SkuID商品的平均价格
|
||||
func GetStoreSkusAveragePrice(storeList []*cms.StoreExt) map[int]int {
|
||||
skusTotalPrice := make(map[int]int)
|
||||
skusCount := make(map[int]int)
|
||||
skusAveragePrice := make(map[int]int)
|
||||
for _, storeInfo := range storeList {
|
||||
storeID := storeInfo.ID
|
||||
storeSkuMapData := allStoreSkusWrapper.GetData(storeID)
|
||||
for skuID, skuPrice := range storeSkuMapData {
|
||||
skusTotalPrice[skuID] += skuPrice
|
||||
skusCount[skuID]++
|
||||
}
|
||||
}
|
||||
for id, totalPrice := range skusTotalPrice {
|
||||
skusAveragePrice[id] = int(math.Round(float64(totalPrice) / float64(skusCount[id])))
|
||||
}
|
||||
return skusAveragePrice
|
||||
}
|
||||
|
||||
func GetSkusCountLessEqualAvgPrice(storeID int, skusAveragePrice map[int]int) (count int) {
|
||||
storeSkuMapData := allStoreSkusWrapper.GetData(storeID)
|
||||
for skuID, skuPrice := range storeSkuMapData {
|
||||
skuAvgPrice := skusAveragePrice[skuID]
|
||||
if skuPrice <= skuAvgPrice {
|
||||
count++
|
||||
}
|
||||
}
|
||||
|
||||
return count
|
||||
}
|
||||
|
||||
//可售商品价格在附近5km内门店比较,价格低于等于平均值的商品数占90%以上满分10分,比例每降低10%减1分,100%超标得0分
|
||||
func ScoreSaleSkuPrice(storeInfo *cms.StoreExt, storeList []*cms.StoreExt) {
|
||||
finalScore := 0
|
||||
storeID := storeInfo.ID
|
||||
totalCount := len(allStoreSkusWrapper.GetData(storeID))
|
||||
if totalCount > 0 {
|
||||
rangeStoreList := GetRangeStoreList(storeID, storeInfo.FloatLng, storeInfo.FloatLat, SaleSkuCheckRange, storeList)
|
||||
skusAveragePrice := GetStoreSkusAveragePrice(rangeStoreList)
|
||||
count := GetSkusCountLessEqualAvgPrice(storeID, skusAveragePrice)
|
||||
if count > 0 {
|
||||
ratio := int(math.Round(float64(count) * 100 / float64(totalCount)))
|
||||
if ratio >= SaleSkuPriceRatio {
|
||||
finalScore = ItemTotalScore
|
||||
} else {
|
||||
decScore := (SaleSkuPriceRatio - ratio) / 10
|
||||
finalScore = ItemTotalScore - decScore
|
||||
if finalScore < 0 {
|
||||
finalScore = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
storeScoreDataWrapper.SetData(storeID, model.FieldSaleSkuPrice, finalScore)
|
||||
}
|
||||
|
||||
func GetFilterStoreListEx(storeList []*cms.StoreExt, storeIDMap map[int]int) (outStoreList []*cms.StoreExt) {
|
||||
for _, storeInfo := range storeList {
|
||||
storeID := storeInfo.ID
|
||||
if len(storeIDMap) > 0 {
|
||||
if _, ok := storeIDMap[storeID]; !ok {
|
||||
continue
|
||||
}
|
||||
}
|
||||
var tempStoreMaps []*model.StoreMap
|
||||
for _, vendorStoreInfo := range storeInfo.StoreMaps {
|
||||
vendorID := vendorStoreInfo.VendorID
|
||||
if _, ok := fullVendorList[vendorID]; !ok {
|
||||
continue
|
||||
}
|
||||
tempStoreMaps = append(tempStoreMaps, vendorStoreInfo)
|
||||
}
|
||||
if len(tempStoreMaps) > 0 {
|
||||
storeInfo.StoreMaps = tempStoreMaps
|
||||
outStoreList = append(outStoreList, storeInfo)
|
||||
}
|
||||
}
|
||||
|
||||
return outStoreList
|
||||
}
|
||||
|
||||
func ScoreStore(ctx *jxcontext.Context, storeIDList []int) (retVal interface{}, err error) {
|
||||
isScoring = true
|
||||
scoreDate = utils.GetCurDate()
|
||||
var storeList []*cms.StoreExt
|
||||
taskCount := 5
|
||||
taskSeqFunc := func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
|
||||
switch step {
|
||||
case 0:
|
||||
baseapi.SugarLogger.Debugf("ScoreStore step0 begin")
|
||||
storeScoreDataWrapper.InitData()
|
||||
storeList, err = GetStoreList(ctx)
|
||||
storeIDMap := jxutils.IntList2Map(storeIDList)
|
||||
storeList = GetFilterStoreListEx(storeList, storeIDMap)
|
||||
baseapi.SugarLogger.Debugf("ScoreStore step0 end")
|
||||
case 1:
|
||||
baseapi.SugarLogger.Debugf("ScoreStore step1 begin")
|
||||
GetAllStoreSkus(ctx, task, storeList)
|
||||
baseapi.SugarLogger.Debugf("ScoreStore step1 end")
|
||||
case 2:
|
||||
baseapi.SugarLogger.Debugf("ScoreStore step2 begin")
|
||||
db := dao.GetDB()
|
||||
storeCountList, err := dao.GetDailyBadCommentOrderCount(db, scoreDate)
|
||||
if err == nil {
|
||||
storeScoreDataWrapper.SetDailyBadCommentOrderCount(storeCountList)
|
||||
} else {
|
||||
baseapi.SugarLogger.Debugf("ScoreStore GetDailyBadCommentOrderCount %v", err)
|
||||
}
|
||||
storeCountList, err = dao.GetDailyUnFinishOrderCount(db, scoreDate)
|
||||
if err == nil {
|
||||
storeScoreDataWrapper.SetDailyUnFinishOrderCount(storeCountList)
|
||||
} else {
|
||||
baseapi.SugarLogger.Debugf("ScoreStore GetDailyUnFinishOrderCount %v", err)
|
||||
}
|
||||
storeCountList, err = dao.GetDailyFinishOrderCount(db, scoreDate)
|
||||
if err == nil {
|
||||
storeScoreDataWrapper.SetDailyFinishOrderCount(storeCountList)
|
||||
} else {
|
||||
baseapi.SugarLogger.Debugf("ScoreStore GetDailyFinishOrderCount %v", err)
|
||||
}
|
||||
storeCountList, err = dao.GetDailyAbsentGoodsOrderCount(db, scoreDate)
|
||||
if err == nil {
|
||||
storeScoreDataWrapper.SetDailyAbsentGoodsOrderCount(storeCountList)
|
||||
} else {
|
||||
baseapi.SugarLogger.Debugf("ScoreStore GetDailyAbsentGoodsOrderCount %v", err)
|
||||
}
|
||||
baseapi.SugarLogger.Debugf("ScoreStore step2 end")
|
||||
case 3:
|
||||
baseapi.SugarLogger.Debugf("ScoreStore step3 begin")
|
||||
taskFunc := func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
|
||||
storeInfo := batchItemList[0].(*cms.StoreExt)
|
||||
storeID := storeInfo.ID
|
||||
baseapi.SugarLogger.Debugf("Begin store id:%d", storeID)
|
||||
ScoreStoreOpenTime(storeInfo)
|
||||
ScoreSaleSkuCount(storeInfo)
|
||||
ScoreAveragePickupTime(storeInfo)
|
||||
ScoreBadCommentOrder(storeInfo)
|
||||
ScoreUnfinishOrder(storeInfo)
|
||||
ScoreAbsentGoodsOrder(storeInfo)
|
||||
ScorePromotionSku(storeInfo)
|
||||
ScoreFullVendor(storeInfo)
|
||||
ScoreStoreRange(storeInfo)
|
||||
ScoreSaleSkuPrice(storeInfo, storeList)
|
||||
baseapi.SugarLogger.Debugf("End store id:%d", storeID)
|
||||
return retVal, err
|
||||
}
|
||||
taskParallel := tasksch.NewParallelTask("计算门店得分", tasksch.NewParallelConfig().SetParallelCount(ParallelCount), ctx, taskFunc, storeList)
|
||||
tasksch.HandleTask(taskParallel, task, true).Run()
|
||||
taskParallel.GetResult(0)
|
||||
_, err = taskParallel.GetResult(0)
|
||||
if err != nil {
|
||||
baseapi.SugarLogger.Debugf("ScoreStore taskParallel error:%v", err)
|
||||
}
|
||||
baseapi.SugarLogger.Debugf("ScoreStore step3 end")
|
||||
case 4:
|
||||
baseapi.SugarLogger.Debugf("ScoreStore step4 begin")
|
||||
storeScoreDataWrapper.InsertStoreScore()
|
||||
storeScoreDataWrapper.ClearData()
|
||||
allStoreSkusWrapper.ClearData()
|
||||
baseapi.SugarLogger.Debugf("ScoreStore step4 end")
|
||||
isScoring = false
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
taskSeq := tasksch.NewSeqTask("门店评分-序列任务", ctx, taskSeqFunc, taskCount)
|
||||
tasksch.HandleTask(taskSeq, nil, true).Run()
|
||||
|
||||
return retVal, err
|
||||
}
|
||||
|
||||
func ScheduleScoreStore() {
|
||||
if EnableScheduleScoreStore {
|
||||
ScheduleTimerFunc("ScheduleScoreStore", func() {
|
||||
if !isScoring {
|
||||
ScoreStore(jxcontext.AdminCtx, nil)
|
||||
}
|
||||
}, scoreStoreTimeList)
|
||||
CheckScoreStore()
|
||||
}
|
||||
}
|
||||
|
||||
func CheckScoreStore() {
|
||||
if !isScoring {
|
||||
curTime := time.Now()
|
||||
checkTimeStr1 := fmt.Sprintf("%s %s", utils.Time2DateStr(curTime), scoreStoreTimeList[0])
|
||||
checkTime1 := utils.Str2Time(checkTimeStr1)
|
||||
checkTimeStr2 := fmt.Sprintf("%s %s", utils.Time2DateStr(curTime), scoreStoreCheckTimeEnd)
|
||||
checkTime2 := utils.Str2Time(checkTimeStr2)
|
||||
if curTime.Unix() >= checkTime1.Unix() && curTime.Unix() <= checkTime2.Unix() {
|
||||
db := dao.GetDB()
|
||||
hasStoreScoreData, err := dao.CheckHasStoreScoreData(db, curTime)
|
||||
if err == nil && !hasStoreScoreData {
|
||||
ScoreStore(jxcontext.AdminCtx, nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Time2Week(t time.Time) int {
|
||||
yearDay := t.YearDay()
|
||||
yearFirstDay := t.AddDate(0, 0, -yearDay+1)
|
||||
firstDayInWeek := int(yearFirstDay.Weekday())
|
||||
|
||||
firstWeekDays := 1
|
||||
if firstDayInWeek != 0 {
|
||||
firstWeekDays = 7 - firstDayInWeek + 1
|
||||
}
|
||||
var week int
|
||||
if yearDay <= firstWeekDays {
|
||||
week = 1
|
||||
} else {
|
||||
tempWeek := (float64(yearDay) - float64(firstWeekDays)) / float64(7)
|
||||
week = int(math.Ceil(tempWeek)) + 1
|
||||
}
|
||||
|
||||
return week
|
||||
}
|
||||
|
||||
func SplitToSingleWeekDataList(storeScoreList []*model.StoreScoreEx) (weekDataList [][]*model.StoreScoreEx) {
|
||||
singleWeekData := []*model.StoreScoreEx{}
|
||||
weekIndex := 0
|
||||
for _, value := range storeScoreList {
|
||||
if weekIndex == 0 {
|
||||
weekIndex = Time2Week(value.ScoreDate)
|
||||
}
|
||||
if weekIndex == Time2Week(value.ScoreDate) {
|
||||
singleWeekData = append(singleWeekData, value)
|
||||
} else {
|
||||
weekDataList = append(weekDataList, singleWeekData)
|
||||
singleWeekData = []*model.StoreScoreEx{}
|
||||
weekIndex = 0
|
||||
singleWeekData = append(singleWeekData, value)
|
||||
}
|
||||
}
|
||||
if len(singleWeekData) > 0 {
|
||||
weekDataList = append(weekDataList, singleWeekData)
|
||||
}
|
||||
|
||||
return weekDataList
|
||||
}
|
||||
|
||||
func GetStoreScoreLevel(score int) int {
|
||||
level := 0
|
||||
if score >= GoldMedalScore {
|
||||
level = GoldMedalLevel
|
||||
} else if score >= SilverMedalScore {
|
||||
level = SilverMedalLevel
|
||||
} else if score >= BronzeMedalScore {
|
||||
level = BronzeMedalLevel
|
||||
}
|
||||
|
||||
return level
|
||||
}
|
||||
|
||||
func GetWeeklyStoreScore(storeID, weekIndexParam int) (outWeeklyStoreScoreDataList []*model.WeeklyStoreScore, err error) {
|
||||
db := dao.GetDB()
|
||||
storeScoreList, err := dao.GetWeeklyStoreScoreList(db, storeID, WeekNum)
|
||||
if err == nil && len(storeScoreList) > 0 {
|
||||
weeklyStoreScoreDataList := []*model.WeeklyStoreScore{}
|
||||
weekDataList := SplitToSingleWeekDataList(storeScoreList)
|
||||
for weekIndex, weekData := range weekDataList {
|
||||
weeklyData := &model.WeeklyStoreScore{}
|
||||
weeklyData.ID = weekIndex
|
||||
weeklyData.ItemTotalScore = ItemTotalScore
|
||||
weeklyData.StoreID = storeID
|
||||
weeklyStoreScoreDataList = append(weeklyStoreScoreDataList, weeklyData)
|
||||
weekDataCount := len(weekData)
|
||||
for dayIndex, dayData := range weekData {
|
||||
for _, fieldName := range storeScoreFieldName {
|
||||
srcFieldValue := refutil.GetObjFieldByName(dayData, fieldName).(int)
|
||||
destFieldValue := refutil.GetObjFieldByName(weeklyData, fieldName).(int)
|
||||
refutil.SetObjFieldByName(weeklyData, fieldName, destFieldValue+srcFieldValue)
|
||||
}
|
||||
if weekDataCount == 1 {
|
||||
weeklyData.BeginTime = dayData.ScoreDate
|
||||
weeklyData.EndTime = dayData.ScoreDate
|
||||
} else {
|
||||
if dayIndex == 0 {
|
||||
weeklyData.EndTime = dayData.ScoreDate
|
||||
} else if dayIndex == weekDataCount-1 {
|
||||
weeklyData.BeginTime = dayData.ScoreDate
|
||||
}
|
||||
}
|
||||
weeklyData.StoreName = dayData.StoreName
|
||||
}
|
||||
for _, fieldName := range storeScoreFieldName {
|
||||
destFieldValue := refutil.GetObjFieldByName(weeklyData, fieldName).(int)
|
||||
refutil.SetObjFieldByName(weeklyData, fieldName, int(math.Round(float64(destFieldValue)/float64(weekDataCount))))
|
||||
}
|
||||
for _, fieldName := range storeScoreFieldName {
|
||||
srcFieldValue := refutil.GetObjFieldByName(weeklyData, fieldName).(int)
|
||||
destFieldValue := refutil.GetObjFieldByName(weeklyData, model.FieldTotalScore).(int)
|
||||
refutil.SetObjFieldByName(weeklyData, model.FieldTotalScore, destFieldValue+srcFieldValue)
|
||||
}
|
||||
weeklyData.Level = GetStoreScoreLevel(weeklyData.TotalScore)
|
||||
}
|
||||
if weekIndexParam == -1 {
|
||||
outWeeklyStoreScoreDataList = weeklyStoreScoreDataList
|
||||
} else {
|
||||
fmt.Println("testss", utils.Format4Output(weeklyStoreScoreDataList, false))
|
||||
outWeeklyStoreScoreDataList = []*model.WeeklyStoreScore{weeklyStoreScoreDataList[weekIndexParam]}
|
||||
}
|
||||
}
|
||||
|
||||
return outWeeklyStoreScoreDataList, err
|
||||
}
|
||||
|
||||
func GetStoreTotalScoreList(ctx *jxcontext.Context, storeIDList []int, cityCode int, keyWord string, beginTime, endTime time.Time, isDesc bool, checkScoreLow, checkScoreHigh, offset, pageSize int) (storeTotalScoreEx model.StoreTotalScoreEx, err error) {
|
||||
db := dao.GetDB()
|
||||
//权限
|
||||
if permission.IsRoled(ctx) {
|
||||
if storeIDsMap, err := permission.GetUserStoresResultMap(ctx.GetUserID()); err == nil {
|
||||
var storeIDs2 []int
|
||||
if len(storeIDList) > 0 {
|
||||
for _, v := range storeIDList {
|
||||
if storeIDsMap[v] != 0 {
|
||||
storeIDs2 = append(storeIDs2, v)
|
||||
}
|
||||
}
|
||||
if len(storeIDs2) == 0 {
|
||||
storeIDs2 = append(storeIDs2, -1)
|
||||
}
|
||||
} else {
|
||||
for k, _ := range storeIDsMap {
|
||||
storeIDs2 = append(storeIDs2, k)
|
||||
}
|
||||
}
|
||||
storeIDList = nil
|
||||
storeIDList = storeIDs2
|
||||
}
|
||||
}
|
||||
storeTotalScoreMapData := make(map[int]*model.StoreTotalScore)
|
||||
storeTotalScoreList, err := dao.GetStoreTotalScoreList(db, storeIDList, cityCode, keyWord, beginTime, endTime)
|
||||
var filterStoreTotalScoreList []*model.StoreTotalScore
|
||||
if err == nil && len(storeTotalScoreList) > 0 {
|
||||
countDayNum := make(map[int]int)
|
||||
for _, value := range storeTotalScoreList {
|
||||
storeID := value.StoreID
|
||||
if storeTotalScoreMapData[storeID] == nil {
|
||||
storeTotalScore := &model.StoreTotalScore{}
|
||||
storeTotalScore.StoreID = value.StoreID
|
||||
storeTotalScore.StoreName = value.StoreName
|
||||
storeTotalScore.CityName = value.CityName
|
||||
storeTotalScoreMapData[storeID] = storeTotalScore
|
||||
}
|
||||
storeTotalScore := storeTotalScoreMapData[storeID]
|
||||
storeTotalScore.StoreScore += value.StoreScore
|
||||
countDayNum[storeID]++
|
||||
}
|
||||
for storeID, value := range storeTotalScoreMapData {
|
||||
value.StoreScore = int(math.Round(float64(value.StoreScore) / float64(countDayNum[storeID])))
|
||||
needAdd := true
|
||||
if checkScoreLow > 0 && value.StoreScore < checkScoreLow {
|
||||
needAdd = false
|
||||
}
|
||||
if checkScoreHigh > 0 && value.StoreScore > checkScoreHigh {
|
||||
needAdd = false
|
||||
}
|
||||
if needAdd {
|
||||
filterStoreTotalScoreList = append(filterStoreTotalScoreList, value)
|
||||
}
|
||||
}
|
||||
if isDesc {
|
||||
sort.Slice(filterStoreTotalScoreList, func(i, j int) bool {
|
||||
data1 := filterStoreTotalScoreList[i]
|
||||
data2 := filterStoreTotalScoreList[j]
|
||||
if data1.StoreScore == data2.StoreScore {
|
||||
return data1.StoreID < data2.StoreID
|
||||
} else {
|
||||
return data1.StoreScore > data2.StoreScore
|
||||
}
|
||||
})
|
||||
} else {
|
||||
sort.Slice(filterStoreTotalScoreList, func(i, j int) bool {
|
||||
data1 := filterStoreTotalScoreList[i]
|
||||
data2 := filterStoreTotalScoreList[j]
|
||||
if data1.StoreScore == data2.StoreScore {
|
||||
return data1.StoreID < data2.StoreID
|
||||
} else {
|
||||
return data1.StoreScore < data2.StoreScore
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
offset = jxutils.FormalizePageOffset(offset)
|
||||
pageSize = jxutils.FormalizePageSize(pageSize)
|
||||
var pagedStoreTotalScoreList []*model.StoreTotalScore
|
||||
for i := offset; i < offset+pageSize && i < len(filterStoreTotalScoreList); i++ {
|
||||
pagedStoreTotalScoreList = append(pagedStoreTotalScoreList, filterStoreTotalScoreList[i])
|
||||
}
|
||||
|
||||
storeTotalScoreEx.TotalCount = len(filterStoreTotalScoreList)
|
||||
storeTotalScoreEx.StoreTotalScoreList = pagedStoreTotalScoreList
|
||||
|
||||
return storeTotalScoreEx, err
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
package misc
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
|
||||
"git.rosy.net.cn/jx-callback/globals/api2"
|
||||
"git.rosy.net.cn/jx-callback/globals/testinit"
|
||||
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/ebai"
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/elm"
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/jd"
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/mtwm"
|
||||
_ "git.rosy.net.cn/jx-callback/business/partner/purchase/weimob/wsc"
|
||||
)
|
||||
|
||||
func init() {
|
||||
testinit.Init()
|
||||
api2.Init()
|
||||
}
|
||||
|
||||
func TestScoreStore(t *testing.T) {
|
||||
ScoreStore(jxcontext.AdminCtx, []int{})
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user